Home > Article > Web Front-end > Detailed explanation of Node.js module loading_node.js
JavaScript is one of the most frequently used programming languages in the world. It is the universal language of the Web world and is used by all browsers. The birth of JavaScript can be traced back to the Netscape era. Its core content was hastily developed to compete with Microsoft and participate in the fierce browser war at that time. Due to its premature release, it inevitably resulted in some not-so-good features.
Despite its short development time, JavaScript still has many powerful features, except that each script shares a global namespace.
Once a web page loads JavaScript code, it will be injected into the global namespace and will share the same address space with all other loaded scripts. This will lead to many security issues, conflicts, and some common problems. Bugs are both difficult to track and difficult to resolve.
But thankfully, Node has set some specifications for server-side JavaScript and also implemented the CommonJS module standard. In this standard, each module has its own context and is distinguished from other modules. This means that modules will not pollute the global scope, because there is no such thing as a global scope, and modules will not interfere with each other.
In this chapter, we will learn about several different modules and how to load them.
Splitting your code into a series of well-defined modules can help you take control of your application. Below we will learn how to create and use your own modules.
Learn how Node loads modules
In Node, modules can be referenced through file paths or module names. If a non-core module is referenced by name, Node will eventually map the module name to the corresponding module file path. Those core modules that contain core functions will be preloaded when Node starts.
Non-core modules include third-party modules installed using NPM (Node Package Manager), as well as local modules created by you or your colleagues.
Each module imported by the current script will expose a set of public APIs to programmers. Before using the module, you need to use the require function to import it, like this:
The above code will import a module named module_name, which may be a core module or a module installed with NPM. The require function returns an object containing all the public APIs of the module. Depending on the module, the returned object may be any JavaScript value, a function, or an object containing a series of properties (a function, an array, or any JavaScript object).
Export module
The CommonJS module system is the only way to share objects and functions between files under Node. For a very complex program, you should restructure some classes, objects, or functions into a series of well-defined reusable modules. To the user of the module, the module exposes only the code you specify.
In the following example, you will learn that there is a one-to-one correspondence between files and modules in Node. We created a file called circle.js, which only exports the Circle constructor.
function r_squared() {
return Math.pow(r, 2);
}
function area() {
return Math.PI * r_squared();
}
return {area: area};
}
module.exports = Circle;
The most important line in the code is the last line, which defines what the module exports. module is a special variable, which represents the current module itself, and module.exports is the object exported by the module. It can be any object. In this example, we exported the constructor of Circle so that module users can use This module creates Circle instances.
You can also export some complex objects. module.exports is initialized as an empty object. You can export any content you want to expose to the outside world as attributes of the module.exports object. For example, you design a module that exposes a set of functions:
console.log('A');
}
function printB() {
console.log('B');
}
function printC() {
console.log('C');
}
module.exports.printA = printA;
module.exports.printB = printB;
module.exports.pi = Math.PI;
This module exports two functions (printA and printB) and a number (pi). The calling code looks like this:
myModule2.printA(); // -> A
myModule2.printB(); // -> B
console.log(myModule2.pi); // -> 3.141592653589793
Load module
As mentioned before, you can use the require function to load modules. You don't have to worry about calling require in the code will affect the global namespace, because there is no concept of global namespace in Node. If the module exists and there are no syntax or initialization errors, the require function will return the module object, and you can assign this object to any local variable.
There are several different types of modules, which can be roughly divided into core modules, local modules and third-party modules installed through NPM. According to the type of module, there are several ways to reference the module. Let’s learn about these knowledge. .
Load core module
Node has some modules that are compiled into binary files, called core modules. They cannot be referenced through paths, only module names. The core module has the highest loading priority. Even if there is a third-party module with the same name, the core module will be loaded first.
For example, if you want to load and use the http core module, you can do this:
This will return an http module object, which contains the htpp module API defined in the Node API documentation.
Load file module
You can also load modules from the file system using absolute paths:
var myModule2 = require('./lib/my_module_2');
Pay attention to the above code. You can omit the extension of the file name. If Node cannot find the file, it will try to search again by adding the js suffix after the file name (Translator's Note: In fact, in addition to js, it will also search for json and node, please refer to the official website documentation for details), therefore, if there is a file called my_module.js in the current directory, there will be the following two loading methods:
var myModule = require('./my_module.js');
Load directory module
You can also use the path to a directory to load modules:
Node will assume that this directory is a module package and try to search for the package definition file package.json in this directory.
If not found, Node will assume that the entry point of the package is the index.js file (Translator's Note: In addition to index.js, it will also search for index.node. The .node file is the binary expansion package of Node. See the official documentation for details) , taking the above code as an example, Node will try to find the ./myModuleDir/index.js file.
On the contrary, if the package.json file is found, Node will try to parse it, look for the main attribute in the package definition, and then use the value of the main attribute as the relative path of the entry point. In this example, if package.json is defined as follows:
"name" : "myModule",
"main" : "./lib/myModule.js"
}
Node will try to load the ./myModuleDir/lib/myModule.js file
Load from node_modules directory
If the parameter of the require function is not a relative path or a core module name, Node will search in the node_modules subdirectory of the current directory. For example, in the following code, Node will try to find the file./node_modules/myModule.js:
You can use this feature to manage the contents or modules of the node_modules directory, but it is best to leave the module management tasks to NPM (see Chapter 1). The local node_modules directory is the default location for NPM to install modules. This design Node and NPM are linked together. Usually, as a developer you don’t need to care too much about this feature, you can simply use NPM to install, update and delete packages, and it will maintain the node_modules directory for you
Cache module
Modules will be cached after the first successful loading, that is, if the module name is resolved to the same file path, then each call to require('myModule') will return exactly the same module.
For example, there is a module called my_module.js, which contains the following content:
module.exports = function() {
console.log('Hi!');
};
console.log('my_module initialized.');
Then load this module with the following code:
It produces the following output:
my_module initialized
If we import it twice:
var myModuleInstance2 = require('./my_module');
The output is still:
my_module initialized
In other words, the module's initialization code is only executed once. When you build your own modules, be sure to pay special attention to this feature if the module's initialization code contains code that may produce side effects.
Summary
Node cancels the default global scope of JavaScript and adopts the CommonJS module system so that you can better organize your code and avoid many security issues and bugs. You can use the require function to load core modules, third-party modules, or load your own modules from files and directories
You can also use relative paths or absolute paths to load non-core modules. If you put the module in the node_modules directory or for modules installed with NPM, you can also directly use the module name to load.
Translator’s Note:
It is recommended that readers read the module chapter of the official document. I personally feel that it is more clear and clear than the author. It also attaches a very representative example, which will be very helpful in understanding Node module loading. Let’s quote that example:
1. If X is a core module,
a. Load and return the core module
b. End
2. If X starts with './' or '/' or '../'
a. LOAD_AS_FILE(Y X)
b. LOAD_AS_DIRECTORY(Y X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. Throw exception: "not found"
LOAD_AS_FILE(X)
1. If X is a file, load X as a JavaScript script and end after loading
2. If X.js is a file, load X.js as a JavaScript script and end after loading
3. If X.node is a file, load X.node as a Node binary plug-in, and end after loading is completed
LOAD_AS_DIRECTORY(X)
1. If the X/package.json file exists,
a. Parse X/package.json, and find the "main" field.
b. Another M = X (the value of the main field)
c. LOAD_AS_FILE(M)
2. If the X/index.js file exists, load X/index.js as a JavaScript script and end after loading
3. If the X/index.node file exists, load X/index.node as a Node binary plug-in, and end after the loading is completed
LOAD_NODE_MODULES(X, START)
1. Also DIRS=NODE_MODULES_PATHS(START)
2. Do the following operations for each directory DIR under DIRS:
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. Another PARTS = path split(START)
2. Another ROOT = index of first instance of "node_modules" in PARTS, or 0
3. I = count of PARTS - 1
4. Another DIRS = []
5. while I > ROOT,
a. If PARTS[I] = "node_modules", continue the subsequent operation, otherwise it will loop next time
c. DIR = path join(PARTS[0 .. I] "node_modules")
b. DIRS = DIRS DIR
c. Another I = I - 1
6. Return to DIRS