May 10, 2021 Node.js
5. Load node_modules directory
6. The folder serves as a module
10.. Loaded from a global folder
稳定性: 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.
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.
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.
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.
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.
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
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'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
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.
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
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
id
{String}
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.
The identifier of the module. This is usually a fully resolved file name.
The file name that the module fully parses.
Whether the module has been loaded or is it loading.
The module that introduces this module.
The module introduced by this module.
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
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.
$HOME/.node_modules
$HOME/.node_libraries
$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.
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
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.