A global variable is a variable that is declared in the global scope, in other words, a variable that is visible from all other scopes.
In NodeJS we have multiple variables and global objects, some of them are only specific to Node (Buffer, Event, process) while others are part of the Javascript language (JSON, Proxy, console)
__dirname
is a variable that tells you the path of the folder where the current javascript file lives. So __dirname
has a different value depending on the file path where this variable it's used.
__filename
is a variable that holds the filename of the code that it's running.
You can use both of them anywhere in your code, so they must be globals. Right?
Right?
It turns out that __dirname
, __filename
, exports
, module
and even require()
are not globals. You can use all these objects anywhere in your code, but they only exist in the module scope. Node does not execute our module code directly. Instead of that, code lives within a closed scope, and this scope is inside the module wrapper.
Inside the module wrapper
Every module is wrapped in a function that looks like this:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives here
});
You can take a look at the module wrapper in the Node source code But you can also check it in your terminal by running the following code:
const Module = require('module');
console.log(Module.wrap());
The output should be something like this:
> node main.js
(function(exports, require, module, __filename, __dirname) { undefined
});
But what is that undefined
after the curly brackets? Well, that is where your actual code lives. The wrapper function takes one argument, and it's the module code.
In Node source code, wrap
function looks like this:
Module.wrapper = [
'(function (exports, require, module, __filename, __dirname) { ',
'\n});',
];
let wrap = function(script) {
return Module.wrapper[0] + script + Module.wrapper[1];
};
So that means that if you call wrap
and pass some code as argument:
const Module = require("module");
console.log(Module.wrap('console.log("hello from the module wrapper")'));
You will get:
> node main.js
(function (exports, require, module, __filename, __dirname) {
console.log("hello from the module wrapper")
});
Now that we know this, we can modify the module wrapper (just for fun, of course)
We're going to need two files. The first one will be module.js
function sum(a, b) {
return a + b;
}
console.log(sum(1, 2));
It'll be just a simple two-sum.
The second file we'll need, it's the one where we'll modify the module wrapper. This file will be calledmain.js
const Module = require("module");
Module.wrap = function(script) {
console.log('hello from the module wrapper, today we will be executing the following code:');
console.log(script);
return Module.wrapper[0] + script + Module.wrapper[1];
}
require('./module');
Here we're replacing wrap()
function with our own. We know that this function takes the module code as argument, and should return the code wrapped.
Finally, we call require('./module')
to import our previously created file.
Now we just need to run node main.js
and the output should be:
> node main.js
hello from the module wrapper, today we will be executing the following code:
function sum(a, b) {
return a + b;
}
console.log(sum(1,2));
3
Very cool, very cool.
Why do we need a wrapper?
Node docs says it is used to keep top-level variables scoped to the current module, in that way those variables are not propagating to the global object. It is also used to provide global-looking variables like __filename
and __dirname
, if you think about it, those variables are related to each module, so it makes sense they not being truly globals.
That's it for today! I just wanted to share something interesting I discovered in the last few days. I'm starting to dig more and more into NodeJS source code, so probably I'll be sharing more stuff here or on Twitter.
Please, share the post with your friends and let me know in the comments if you know about another interesting piece of code from NodeJS source.
Top comments (0)