JavaScript is one of the most frequently used programming languages in the world. It is the common language in the web world and is used by all browsers. The birth of JavaScript goes back to the era of Netscape, and its core content was hastily developed to fight Microsoft and participate in the fierce browser war at that time. Due to the premature release, some of its poor features inevitably resulted in.
Although its development time is short, JavaScript still has many powerful features, except for the feature of sharing a global namespace for each script.
Once the web page is loaded with JavaScript code, it is injected into the global namespace and will share the same address space as all other loaded scripts, which will lead to many security issues, conflicts, and some common problems, making bugs difficult to track and difficult to resolve.
But thankfully, Node has set some specifications for server-side JavaScript and also implements 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 so-called global scope at all, and modules will not interfere with each other.
In this chapter, we will learn about several different modules and how to load them.
Splitting the code into a series of well-defined modules can help you control 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 allud the module name to the corresponding module file path. And those core modules containing 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 exposed APIs to the programmer. Before using the module, you need to use the require function to import it, like this:
var module = require(‘module_name')
The above code will import a module named module_name. It 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, it can be a function, or an object containing a series of attributes (functions, arrays, 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 reconstruct some classes, objects, or functions into a series of well-defined reusable modules. For module users, the module only exposes the code you specified to the outside world.
In the following example, you will understand that in Node, files and modules correspond one by one. We created a file called, which only exports the Circle constructor to the outside.
function Circle(x, y, r) {
function r_squared() {
return (r, 2);
}
function area() {
return * r_squared();
}
return {area: area};
}
= Circle;
The most important thing in the code is the last line, which defines what the module exports to the outside. module is a special variable. It represents the current module itself, but an object exported by the module to the outside. It can be any object. In this example, we export the constructor of the Circle so that the module users can use this module to create Circle instances.
You can also export some complex objects, initialized into an empty object, and you export any content you want to expose to the outside world as the object's properties. For example, you designed a module that exposes a set of functions to the outside:
function printA() {
('A');
}
function printB() {
('B');
}
function printC() {
('C');
}
= printA;
= printB;
= ;
This module exports two functions (printA and printB) and a number (pi), and the calling code looks like this:
var myModule2 = require('./myModule2');
(); // -> A
(); // -> B
(); // -> 3.141592653589793
Loading module
As mentioned earlier, you can use the require function to load modules, and don't worry that calling require in the code will affect the global namespace, because there is no concept of global namespace in Node. If the module exists without any syntax or initialization errors, the require function will return the module object, and you can also 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 refer to modules. Let’s learn about these knowledge below.
Loading the core module
Node has some modules compiled into binary files, called core modules. They cannot be referenced by paths, and can only be used with module names. The core module has the highest loading priority, and even if there is already a third-party module of 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:
var http = require('http');
This will return an object containing the http module, which contains the APIs of those http modules defined in the Node API documentation.
Loading the file module
You can also use absolute paths to load modules from the file system:
var myModule = require('/home/pedro/my_modules/my_module');
You can also use a relative path based on the current file:
var myModule = require('../my_modules/my_module');
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 this file, you will try to add a js suffix to search again after the file name (Translator's note: In fact, in addition to js, you will also look for json and node. For details, you can see the official website documentation). Therefore, if a file called my_module.js exists in the current directory, there will be two loading methods:
var myModule = require('./my_module');
var myModule = require('./my_module.js');
Loading the directory module
You can also use the directory path to load the module:
var myModule = require('./myModuleDir');
Node will assume that this directory is a module package and try to search for package definition files in this directory.
If not found, Node will assume that the entry point of the package is a file (Translator's note: In addition to searching, the .node file is a binary extension package of Node, see the official document for details). As an example, Node will try to find the ./myModuleDir/ file.
On the contrary, if the file is found, Node will try to parse it and 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 the definition is as follows:
{
"name" : "myModule",
"main" : "./lib/"
}
Node will try to load the ./myModuleDir/lib/ file
Load from node_modules directory
If the parameters of the require function are not relative paths or core module names, Node will be searched in the node_modules subdirectory of the current directory. For example, in the following code, Node will try to find the file./node_modules/:
var myModule = require('');
If not found, Node will continue to search in the node_modules folder of the upper directory. If not found, continue to search in the upper directory until the corresponding module is found or the root directory is reached.
You can use this feature to manage the content or modules of the node_modules directory, but it is best to hand over the module management tasks to the NPM (see Chapter 1). The local node_modules directory is the default location for the NPM installation module. This design associates Node and NPM together. Usually, as a developer, you don't have to care too much about this feature. You can simply install, update and delete packages using NPM, which will help you maintain the node_modules directory.
Cache module
The module 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 that contains the following content:
('module my_module initializing...');
= function() {
('Hi!');
};
('my_module initialized.');
Then use the following code to load the module:
var myModuleInstance1 = require('./my_module');
It produces the following output:
module my_module initializing...
my_module initialized
If we import it twice:
var myModuleInstance1 = require('./my_module');
var myModuleInstance2 = require('./my_module');
The output is still:
module my_module initializing...
my_module initialized
That is to say, the initialization code of the module is executed only once. When you build your own module, if the initialization code of the module contains code that may have side effects, you must pay special attention to this feature.
summary
Node canceled the default global scope of JavaScript and instead adopted the CommonJS module system, so that you can better organize your code, thus avoiding 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 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 chapters of the official document. I personally feel that it is clearer than the author. A very representative example has been attached, which will be of great help to understand Node module loading. The following is also quoted:
Use require(X) to load modules under path Y
1. If X is the 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 an 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 it is a file, load it as a JavaScript script and end after loading.
3. If it is a file, load it as a Node binary plug-in and end after loading.
LOAD_AS_DIRECTORY(X)
1. If X/file exists,
a. Parses X/ and finds the "main" field.
b. Also M = X + (value of main field)
c. LOAD_AS_FILE(M)
2. If the X/ file exists, load X/ as a JavaScript script and end after loading.
3. If the X/ file exists, load X/ as the Node binary plug-in and end after loading.
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. Also PARTS = path split(START)
2. Also ROOT = index of first instance of "node_modules" in PARTS, or 0
3. Also I = count of PARTS - 1
4. Also DIRS = []
5. while I > ROOT,
a. If PARTS[I] = "node_modules" then continue the subsequent operation, otherwise the next loop
c. DIR = path join(PARTS[0 .. I] + "node_modules")
b. DIRS = DIRS + DIR
c. Also I = I - 1
6. Return to DIRS