How does require() in node.js work?

I tried this:

// mod.js
var a = 1;
this.b = 2;
exports.c = 3;


// test.js
var mod = require('./mod.js');
console.log(mod.a);    // undefined
console.log(mod.b);    // 2
console.log(mod.c);    // 3, so this === exports?

So I image that require() may be implement like this:

var require = function (file) {
var exports = {};
var run = function (file) {
// include "file" here and run
};
run.apply(exports, [file]);
return exports;
}

Is that right? Please help me to understand require(), or where can I find the source code. Thanks!

49447 次浏览

The source is available here next to the downloads : http://nodejs.org/ exports/require are keywords, I don't think they are coded in javascript directly. Node is coded in C++ , javascript is just a scripting shell around the C++ core.

Source code is here. exports/require are not keywords, but global variables. Your main script is wrapped before start in a function which has all the globals like require, process etc in its context.

Note that while module.js itself is using require(), that's a different require function, and it is defined in the file called "node.js"

Side effect of above: it's perfectly fine to have "return" statement in the middle of your module (not belonging to any function), effectively "commenting out" rest of the code

Andrey showed the source code, but if you also wonder how to use it, the easy and simple explanation is here (http://nodejs.org/api/modules.html).

These were two good examples for me.

//foo.js, multiple methods
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is ' + circle.area(4));


//circle.js
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};


//bar.js
var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());


//square.js, single method
module.exports = function(width) {
return {
area: function() {
return width * width;
}
};
}

My favourite pattern is

(function (controller) {


controller.init = function (app) {


app.get("/", function (req, res) {
res.render("index", {});
});


};
})(module.exports);
var mod = require('./mod.js');

The require is a function that takes one argument called path, in this case the path is ./mod.js

when the require is invoked, a sequences of tasks are happened:

  1. call Module.prototype.require function declared in lib/module.js which assert that the path exists and was a string

  2. call Module._load which is a function in lib/module.js that resolve the file through Module._resolveFilename(request, parent, isMain),

  3. the Module._resolveFilename function is called and checks if the module is native (The native modules are returned by NativeModule function defined in lib/internal/bootstrap_node.js), if yes it will return the module else it checks the number of characters of the parh (Must 2 character at least) and some characters (the path must started by ./) via Module._resolveLookupPaths function defined in defined in lib/internal/bootstrap_node.js
  4. check the directory that contains the file
  5. If the path contains an extension (in our example yes: mod.js), the basename function defined in lib/path.js checks that the extension is "js"
  6. then it will create a new module for the file given in argument var module = new Module(filename, parent);
  7. the content will be compiled via v8 through the function NativeModule.prototype.compile defined in lib/internal/bootstrap_node.js
  8. the NativeModule.wrap defined in lib/internal/bootstrap_node.js takes the javascript content compiled of mod.js and wraps it : It wraps it in some other code that makes all this work. So the code you've written in mod.js is wrapped in a function expression. that means everything you write in node is run in V8
  9. a module.exports is what's returned

I dig a little more of nodejs source code/2/ and make a sequence diagram/1/, hope this could give you a intuitive overview. There is another article http://fredkschott.com/post/2014/06/require-and-the-module-system/ which also explain the require() mechanism in a easy way, go through this article first could help you to understand the diagram quickly. enter image description here

Ref:

/1/ diagram source repo: https://github.com/z1yuan/nodejs.git

/2/ https://github.com/nodejs/node-v0.x-archive.git

Try This.
This is a snippet of what I used to create the same functionality as Node.js

/*
FILE: require.js
*/
/*
This is the file used
*/
window.require = function(src, ret) {
if (src === 'jsmediatags') {
src = 'https://cdnjs.cloudflare.com/ajax/libs/jsmediatags/3.9.5/jsmediatags.js';
};
var d = document.createElement('script');
d.src = src;
document.head.appendChild(d);
var fullURL = src.split('://');
var neededURL = fullURL[1];
var nameParts = neededURL.split('/');
var nameNUM = nameParts.length - 1;
var fileName = nameParts[nameNUM];
var g = fileName.split('.');
var global = g[0];
if (ret === true) {
return window[global]
};
};
See if this works, and to add more files to its library, just type more in. (if (src===yourfilenamehere) { src = "path/to/your/file" }

The module loading mechanism in Node.js is caching the modules on the first require call. It means that every time you use require('xyz-module') you will get the same instance of xyz-module, which ensures that the modules are singleton-like and have the same state across your application.

You can load native modules and path references from your file system or installed modules. If the identifier passed to the require function is not a native module or a file reference (beginning with /, ../, ./ or similar), then Node.js will look for installed modules. It will walk your file system looking for the referenced module in the node_modules folder. It starts from the parent directory of your current module and then moves to the parent directory until it finds the right module or until the root of the file system is reached.