Talking about the Module System in node. js
- 2021-08-09 06:59:40
- OfStack
Modules for Node. js
JavaScript comes out as a simple script language for adding interactive functions to web pages, but it does not contain module system when it was born. With JavaScript solving problems becoming more and more complex, all codes are written in one file, and function distinguishing functional units can no longer support complex application development. ES6 brings class and module, which are available in most high-level languages, which is convenient for developers to organize codes
import _ from 'lodash';
class Fun {}
export default Fun;
The above three lines of code show the two most important elements of a modular system, import and export
1.
export
Used to specify the external interface of the module
2.
import
Used to enter functions provided by other modules
Before ES6, there were many module loading schemes in the community, the most important of which were CommonJS and AMD. Node. js was born earlier than ES6, and the module system used an implementation similar to CommonJS and followed several principles
1. A file is a module, and the scope of variables in the file is within the module
STEP 2 Use
module.exports
External interface of object export module
STEP 3 Use
require
Introduce other modules
circle.js
const { PI } = Math;
module.exports = function area(r) {
PI * r ** 2;
};
The above code realizes one module of Node. js, and the module does not depend on other modules. The method area is derived to calculate the area of a circle
test.js
const area = require('./circle.js');
console.log(` The radius is 4 The area of the circle is ${area(4)}`);
The module relies on circle. js to calculate the area of the circle using its externally exposed area method
module.exports
The module exposes the interface to the outside using module. exports, which is commonly used in two ways: adding attributes to it or assigning values to new objects
test.js
// Add Attributes
module.exports.prop1 = xxx;
module.exports.funA = xxx;
module.exports.funB = xxx;
// Assign a value to a brand new object
module.exports = {
prop1,
funA,
funB,
};
The two writing methods are equivalent, and there is no difference when using them
const mod = require('./test.js');
console.log(mod.prop1);
console.log(mod.funA());
There is another direct use
exports
Object, but you can only add properties to it, and you can't assign values to new objects, which will be explained later
// Correct writing: Add attributes
exports.prop1 = xxx;
exports.funA = xxx;
exports.funB = xxx;
// Assign a value to a brand new object
module.exports = {
prop1,
funA,
funB,
};
require('id')
Module type
require is simple to use, and id supports two types: module name and file path
Module name
const fs = require('fs');
const _ = require('lodash');
In the example, fs and lodash are all module names, fs is the core module built in Node. js, and lodash is the third module installed under node_modules through npm. In case of duplicate names, the system built-in module is preferred
Because one project may contain multiple node_modules folders (Node. js comparison failed design), the third-party module search process will follow the proximity principle layer by layer (module. paths can be printed in the program to see the specific search path) until the file system root directory is found according to the NODE_PATH environment variable. For the specific process, please refer to the official document
In addition, Node. js searches the following list of global directories:
$HOME/.node_modules $HOME/.node_libraries $PREFIX/lib/nodeWhere $HOME is the user's home directory and $PREFIX is node_prefix configured in Node. js. It is strongly recommended that all dependencies be placed in the local node_modules directory, which will load faster and more reliably
File path
Modules can also be loaded using file path, which is a general loading method for custom modules in the project. The extension name can be omitted from the path, and will be tried in the order of. js,. json and. node
The module prefixed with '/' is the absolute path of the file. Find the module according to the system path Modules prefixed with './' are relative to the file that is currently calling the require method and are not affected by where subsequent modules are usedSingle load & Cyclic dependency
The module is cached after the first load to the
Module._cache
If every time you call
require('foo')
Are resolved to the same 1 file, the same object is returned, and multiple calls are made at the same time
require(foo)
Does not cause the code of the module to be executed multiple times. Node. js caches modules based on the actual filename, so referencing the same module from different hierarchical directories does not repeat the load.
Understanding the module single load mechanism is convenient for us to understand the phenomenon after module cyclic dependence
a.js
console.log('a Begin ');
exports.done = false;
const b = require('./b.js');
console.log(' In a In, b.done = %j', b.done);
exports.done = true;
console.log('a End ');
b.js
console.log('b Begin ');
exports.done = false;
const a = require('./a.js');
console.log(' In b In, a.done = %j', a.done);
exports.done = true;
console.log('b End ');
main.js
console.log('main Begin ');
const a = require('./a.js');
const b = require('./b.js');
console.log(' In main In, a.done=%j , b.done=%j', a.done, b.done);
When main. js loads a. js and a. js loads b. js, b. js attempts to load a. js
To prevent an infinite loop from returning an unfinished copy of the exports object of a. js to the b. js module, then b. js completes loading and supplies the exports object to the a. js module
So the output of the example is
main begins
a Start
b begins
In b, a. done = false
End of b
In a, b. done = true
End of a
In main, a. done = true, b. done = true
It doesn't matter if you don't understand the above process. You don't need it at all in your daily work. Even if you understand it, don't use circular dependency in your project!
Working principle
Node. js Each file is a module, and the variables in the module are local variables, which will not pollute the global variables. Before executing the module code, Node. js will use the following function wrapper to encapsulate the module
const { PI } = Math;
module.exports = function area(r) {
PI * r ** 2;
};
0
__filename: Absolute path to the current module file
__dirname: Absolute path to the directory where the current module file is located
module: Current module instance
require: Method for loading other modules, shortcut to module. require
exports: Object to export module interface, shortcut to module. exports
Looking back at the initial question, why doesn't exports object support assigning values to other objects? It is very simple to add a sentence exports object source to the above function
const { PI } = Math;
module.exports = function area(r) {
PI * r ** 2;
};
1
Other modules require to the module module. exports object, if the exports object assigned to other objects, and module. exports object disconnected, naturally useless
Using ES Module in Node. js
As ES6 becomes more widely used, Node. js also supports ES6 Module in several ways
babel Construction
Building with babel is the simplest and most common way before v12. For specific configuration, refer to @ babel/preset-env
.babelrc
const { PI } = Math;
module.exports = function area(r) {
PI * r ** 2;
};
2
Native support
ES Module can be supported in native mode after v12
Open--experimental-modules
The module name is changed to
.mjs
(Strongly not recommended) or package. json
import
0
In this way, Node. js will treat js files as ES Module. Please refer to the official documents for more details
The above is to talk about node. js module system details, more information about node. js module please pay attention to other related articles on this site!