Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Node .js module


May 10, 2021 Node.js


Table of contents


Module

稳定性: 5 - 锁定

This section describes the .js node system.

Node .js a simple module loading system. I n the Node .js system, each file can be treated as a separate module. I n the following example, foo.js the circle module in circle.js same folder. foo.js content:

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

This circle.js

var PI = Math.PI;

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};

circle.js outputs area() and circumference() To add functions and objects to the root module, you can add them to exports

The variables loaded into the module are private, as if the module were contained in a function. In this example, PI is circle.js the circle.

If you want the root in the module to output like a function (for example, a constructor), or if you want to output a module.exports exports

bar.js square module, which outputs the constructor:

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

square is square.js square file:

// assigning to exports will not modify module, must use module.exports
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

The module system require("module") module.

Cycles

The ring calls require() the module may not have finished executing when it returned.

Consider the following scenario:

a.js :

console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');

b.js :

console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

main.js :

console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);

When main.js a.js a.js b.js A t this b.js to a.js T o prevent looping calls, a.js incomplete copy of the output object is b.js b module. b.js the load, and its exports is provided a.js module.

main.js when both modules are loaded, they both end. The output of this program is as follows:

$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true

If your program has ring module dependencies, you need to make sure it is linear.

The core module

Node has many modules compiled into binary. These modules are described in more detail elsewhere in this document.

The core module is defined in Node's lib/

require() loads the core module first. For example, require('http') always returns a compiled HTTP module, regardless of the name of the file.

The file module

If the module is not found by file name, .js will try to load the file with the .js and .json added, and if it's not good enough, then try loading the file with .node added.

.js resolve to JavaScript's text file, .json will resolve to JSON's text file, .node a compiled plug-in dlopen

The prefix '/' represents the absolute path. For require('/home/marco/foo.js') load /home/marco/foo.js file.

The module's './' the require() That is, circle.js be .js directory with foo.js require('./circle') find.

There is no / ./ in front of the file, indicating that the module may be core module or node_modules node_modules from the folder.

If the specified path does require() throws an exception with the code 'MODULE_NOT_FOUND' thrown.

Load node_modules directory

If the module require() is not a local module and does not '/' '../' beginning './' Node starts at the parent directory of the current module and attempts to node_modules folder.

If not, it doesn't go to the parent directory until you look for it in the root of the file system.

For example, if a file loaded in '/home/ry/projects/foo.js' require('bar.js') Node will look in the following order:

  • /home/ry/projects/node_modules/bar.js
  • /home/ry/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

This allows the program to be independent and does not create conflicts.

You can request a specified file or distribution subdirecte of modules to add a path suffix after the module name. F or example, require('example-module/path/to/file') path/to/file example-module The path suffix uses the same syntax.

The folder serves as a module

You can put programs and libraries in separate folders and provide a single entry point to them. There are three ways to pass a folder as an argument require()

The first is to create a package.json file at the root of the folder, which specifies the main module. package.json is as follows:

{ "name" : "some-library",
  "main" : "./lib/some-library.js" }

If this is ./some-library require('./some-library') will try to load ./some-library/lib/some-library.js

If there is no package.json the folder, Node tries to index.js or index.node file. F or example, if there is no package.json file in the example above. Then require('./some-library') try to load:

  • ./some-library/index.js
  • ./some-library/index.node

Cache

The module is cached the first time it is loaded. This means that the require('foo') and of course you must resolve to the same file every time.

Multiple calls require('foo') cause the module code to execute more than once. This is an important feature so that the "partially done" object can be returned, allowing transitional dependencies to be loaded, even if ring calls may be caused.

If you want to call a module more than once, output a function and call it.

The module is replaced with an alert

The module's cache depends on the resolved file name. T herefore, depending on where the call is made, the module may resolve to a different file (for node_modules folder). I f resolved to a different file, require('foo') return a different object.

module object

  • {Object}

In each module, the variable module a reference to an object that represents the current module. F or convenience, module.exports exports global module. module is not a de facto global object, but is inside each module.

module.exports

  • {Object}

The module system module.exports object. M any people want their modules to be instances of a class. T herefore, assign the object to be exported to module.exports Note that assigning the desired object to exports binds it to the exports which may not be what you want.

For example, suppose we have a module a.js

var EventEmitter = require('events').EventEmitter;

module.exports = new EventEmitter();

// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(function() {
  module.exports.emit('ready');
}, 1000);

Another file can be written as follows:

var a = require('./a');
a.on('ready', function() {
  console.log('module a is ready');
});

Note: Assigned module.exports be executed immediately and cannot be performed in callbacks.

x.js:

setTimeout(function() {
  module.exports = { a: "hello" };
}, 0);

y.js:

var x = require('./x');
console.log(x.a);

exports alias

exports variable is available in module.exports Like other variables, if you give him a new value, it no longer points to the old value.

To demonstrate this feature, assume that the implementation: require() :

function require(...) {
  // ...
  function (module, exports) {
    // Your module code here
    exports = some_func;        // re-assigns exports, exports is no longer
                                // a shortcut, and nothing is exported.
    module.exports = some_func; // makes your module export 0
  } (module, module.exports);
  return module;
}

If exports confused module.exports just use module.exports

module.require(id)

  • id {String}
  • Back: the module.exports of the module have been resolved by the . . . Object .

module.require method provides a way to load a module from the original module like a require()

In order to do this, you must obtain a module the module object. require() module.exports module is a module variable that can only be valid within a specific module scope, and if you want to use it, you must export it explicitly.

module.id

  • {String}

The identifier of the module. This is usually a fully resolved file name.

module.filename

  • {String}

The file name that the module fully parses.

module.loaded

  • {Boolean}

Whether the module has been loaded or is it loading.

module.parent

  • {Module Object}

The module that introduces this module.

module.children

  • {Array}

The module introduced by this module.

Other...

To get the exact file name to be loaded with require() you can require.resolve() function.

In summary, the following demonstrates the workflow of require.resolve in the form of advanced algorithms of pseudo-code:

require(X) from module at path Y
1. If X is a core module,
   a. return the core module
   b. STOP
2. If X begins with './' or '/' or '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW "not found"

LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text.  STOP
2. If X.js is a file, load X.js as JavaScript text.  STOP
3. If X.json is a file, parse X.json to a JavaScript Object.  STOP
4. If X.node is a file, load X.node as binary addon.  STOP

LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
   a. Parse X/package.json, and look for "main" field.
   b. let M = X + (json main field)
   c. LOAD_AS_FILE(M)
2. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
4. If X/index.node is a file, load X/index.node as binary addon.  STOP

LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   c. DIR = path join(PARTS[0 .. I] + "node_modules")
   b. DIRS = DIRS + DIR
   c. let I = I - 1
5. return DIRS

Loaded from a global folder

If the environment variable NODE_PATH set to a list of absolute paths split by a colon and the module is not found elsewhere, Node will search for those paths. (Note that in Windows systems, NODE_PATH with a sign.)

In addition, Node will search for these paths.

  • 1: $HOME/.node_modules
  • 2: $HOME/.node_libraries
  • 3: $PREFIX/lib/node

$HOME the user's home $PREFIX is the most configured folder node_prefix

Most of this is due to historical reasons. I t is highly recommended that you put the node_modules the folder. This will load faster.

Access to the main module

When Node runs a file, require.main set to its module This means that you can test to determine if the file is running directly.

require.main === module

For foo.js file. If you run node foo.js true if it runs indirectly through require('./foo')

Because module filename property __filename the entry point of the program can require.main.filename

Appendix: Package management tips

Node's require() semantic definition is general enough to support a variety of general directory structures. Package dpkg rpm and npm can build local packages from the Node module without modification.

Here's a possible directory structure:

Let's say /usr/lib/node/<some-package>/<some-version> folder that contains the specified version of the package content.

One package can depend on the other. I n order to install the package foo, you may need to install a specific version bar package. bar may have their own package dependencies, and under certain conditions, dependencies may conflict or form loops.

Because Node looks for the realpath of the module he loads (that is, resolves the symbolic link) and then looks for dependencies in the node_modules directory as described above, this situation is very similar to the following architecture:

  • /usr/lib/node/foo/1.2.3/ - foo Package, Version 1.2.3.
  • /usr/lib/node/bar/4.3.2/ foo bar package content.
  • /usr/lib/node/foo/1.2.3/node_modules/bar - symbolic /usr/lib/node/bar/4.3.2/ .
  • /usr/lib/node/bar/4.3.2/node_modules/* - Symbolic bar which the bar package depends.

Therefore, even if there is a circular dependency or dependency conflict, each module can get the available version of the package on which it depends.

When the code in the foo package foo you get the version that the symbolic link /usr/lib/node/foo/1.2.3/node_modules/bar points to. Then, when the code in the require('queue') you get the version that the symbolic link /usr/lib/node/bar/4.3.2/node_modules/quux points to.

Also, to make module search faster, don't put packages directly in /usr/lib/node directory, but in /usr/lib/node_modules/<name>/<version> T his way, if the dependent package cannot be found, you won't be looking for usr/node_modules /node_modules all the time. The real path is based on the file calling require(), so the package itself can be placed anywhere.

In order for the Node module to be available to Node REPL, you may need /usr/lib/node_modules folder path to the $NODE_PATH The package can $NODE_PATH that the folder is relative to the path.