4

I have a general and high-level understanding of the functionality and nature of Node.js' require() function and module.exports. However there are some behaviors that do not make sense to me.

Let's say I have two very simple one-line files a.js and b.js.

In a.js:

require('./b.js');

and in b.js:

console.log("testing");

and if I run node a.js in the terminal, here's what's logged:

$ node a.js
testing.

which means that just by requiring a file/module, the requested file's content is exposed to the file that issues the request (, right?)


Now I modify a.js to this:

require('./b.js');
testFunc(1, 2);

and b.js to this:

var testFunc = function(a, b) {
    var result = a + b;
    return result;
}

and run, again, node a.js in the terminal:

$ node a.js
/demo/a.js:3
testFunc(1, 2);
^

ReferenceError: testFunc is not defined
......

So what is going on here? Apparently, in the first example, by requiring b.js, a.js can access content inside b.js. However, in the second example, the function defined in b.js is not accessible at all as evident in ReferenceError: testFunc is not defined. What's the trick here?

Is it because require() only runs the required script without actually exposing the its content to the requesting file? Therefore in order to use other module's content, that module has to be exposed by using module.exports?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Aren Li
  • 1,852
  • 1
  • 15
  • 14

3 Answers3

2

Your understanding is flawed.

"file's content is exposed to the file that issues the request " in general no, only module.exports is exposed.

Node modules run inside their own scope so that any code in your module is not accessible outside it.

module wrapper documentation

(function (exports, require, module, __filename, __dirname) {
// Your module code actually lives in here
});

You see the console log because all console messages are directed to the same output, in this case the terminal.

It's similar to how console.log() messages work in browsers. Even though the below code is run in an iframe and is separate to the main page the console messages from the iframe and from the main window both are directed to the dev tools console.

console.log("whoa");
Patrick Evans
  • 41,991
  • 6
  • 74
  • 87
1

In your first case, nothing is exposed to the a.js. In nodejs, you have to explicitely store the exported values to a variable.

That said, when you require a module, the highest scope is being executed in order to create what will get exported. That's why you see that console.log is being executed.

If you wanted to export something from b.js, you'd have to do something like this:

module.exports = {
  testFunc: testFunc
}

And in a.js

var b = require('./b.js')
b.testFunc(1, 2)

In other words, unlike many languages, when requiring a module. No symbol gets attached to the global scope so without explicitely defining testFunc to the module b testFunc, nodejs will never know what testFunc is.

Loïc Faure-Lacroix
  • 13,220
  • 6
  • 67
  • 99
1

A good answer for this can be found in this post.

When you require a script in Node JS (b.js in this example), it can't physically do anything with the code unless it's exported -- unless of course you ask the script you're requiring to perform an action.

For example:

a.js

'use strict';

    let b = require('./b.js');

    let result = b.testFunc(1, 4);
    console.log(result);

b.js

'use strict';

    module.exports.testFunc = function(a, b) {
        let result = a + b;
        return result;
    }

    console.log(this.testFunc(5,5));
Community
  • 1
  • 1
ash
  • 1,224
  • 3
  • 26
  • 46