Module system of Node.js

Keywords: Javascript node.js Vue.js

First, the definition of modularity.

① With file scope
② With communication rules: Rules for loading and exporting

2, CommonJS module specification

1. The module system in nodejs has file scope and communication rules. It uses the require method to load the module, and uses the exports interface object to export the members of the module.
2. Load require

① Syntax:

var Custom variable = require("modular")

② Two functions: execute the code in the loaded module to obtain the exports export interface object in the loaded module.

3. Export

① In nodejs is the module scope. All members in the default file are valid only in the current file module
② Members that want to be accessed by other modules can be mounted in the objects of the exports interface
③ Export multiple members (must be in object)
example.js:

// example.js

// Export number
exports.num = 123;
// Export string
exports.str = 'nodejs'
// derived function
exports.fn1 = function() {
  console.log('This is fn1')
}
// Export object
exports.obj1 = {
  name: 'Jack',
  age: '18'
}

index.js:

var example = require('./example')

console.log(example.num)
console.log(example.str)
console.log(example.fn1)
console.log(example.obj)

Operation results:

> demo node index.js
123
nodejs
[Function (anonymous)]
{ name: 'Jack', age: '18' }

④ Export a single member (get a function, string, etc., instead of an object)

example.js:

module.exports = 'Export string'

index.js:

var example = require('./example')
console.log(example.str)

Operation results

> demo node index.js
nodejs

⑤ The following situations will be overwritten
example.js:

// example.js
module.exports='nodejs';
module.exports={
    num:123,
    str:'world'
}

index.js:

var example = require('./example')
console.log(example)

Operation results:

> demo node index.js
{ num: 123, str: 'world'}

⑥ You can also export multiple members in this way

example.js:

module.exports={
    num:123,
    str:'world',
    add:function(x,y){
        return x+y;
    }
}

index.js:

var example = require('./example')
console.log(example)

Operation results:

> demo node index.js
{ num: 123, str: 'world', add: [Function: add] }

⑦ Principle explanation: exports is a reference to module.exports.
Differences between exports and module.exports:
Each module has a module object and an exports object in the module object. You can mount the members to be exported to the module.exports interface object, that is, the method of "module.exports.xxx = xxx".
However, it is too cumbersome to write in this way every time, so nodejs provides a member called "exports" in each module for convenience, so that the result of "exports === module.exports" is "true". Therefore, for "module.exports", you can use "exports.xxx = xxx".
When a module needs to export a single member, it must use "module.exports". Using "exports = xxx" does not work.
Because "module.exports" is the final "return" of each module, and exports is only a reference to mulule. Exports, even if "exports = xxx" is re assigned, it will not affect "module.exports", and the reference relationship between exports and module.exports will be broken after re assignment. However, there is a special assignment method, "exports = mudule.exports" is used to re-establish the reference relationship.

a.js:

exports.foo = 'bar'
//  Return {foo: 'bar'}
module.exports.a = 123
// Return {foo: 'bar', a: 123}
exports = { a: 456 }
// Return {foo: 'bar', a: 123} no change
module.exports.foo = 'This is foo'
// Return {foo: 'this is foo', a: 123}
exports.c = 666
// Return {foo: 'this is foo', a: 123} no change
exports = module.exports; 
// Re established the reference relationship
exports.a = 789 
// Return {foo: 'this is foo', a: 789}

index.js:

var a = require('./a')
console.log(a)
4. require method

Loading rules for
① Load from cache first: it can avoid repeated loading and improve loading efficiency

Execution results:

Execution process:

② Determine module ID: require("module ID")

  • If it is a module in the form of path:
a. . / indicates the current directory

Neither '.' nor '/' can be omitted. You can omit the file suffix, such as require('. / b')

b. ... / indicates the upper level directory

Neither '...' nor '/' can be omitted. You can omit the file suffix, such as require('... / b')

c. /, indicating the root path of the disk to which the current file module belongs

Such as require('/ b')

  • If it is a core module:

It is also a file in essence. The core module file has been compiled into a binary file, so it only needs to be loaded according to the file name, such as require('fs') and require('http ')

  • In the case of third-party modules:
    ① All third-party modules must be downloaded through npm and can be loaded through require("package name") when used. It is impossible for any third-party package to have the same name as the core module
    ② When using npm to download a package, a node will be generated in the project directory_ Modules folder (one and only one for a project)
    ③ Explanation of loading rules for third-party modules (refer to article: https://www.infoq.cn/article/nodejs-module-mechanism/ )

3, Four types of modules in Node.js

Native module and 3 file modules
Native module - core module:

The core module is the module provided by nodejs itself, also known as the native module.
·fs for file operations
·http for http services
·url path operation module
·path operation module
·os operating system information

File module
  • .js
  • .json
  • .node
File search strategy in the require method of Node.js:

There are four types of modules (native module and three file modules) in Node.js. Although the require method is extremely simple, the internal loading is very complex, and their loading priorities are different

Load from file module cache

Although the priority of the native module is different from that of the file module, the existing modules will be preferentially loaded from the cache of the file module.

Load from native module

The priority of the native module is second only to that of the file module cache. After parsing the file name, the require method first checks whether the module is in the native module list. Take the HTTP module as an example. Although there is an http/http.js/http.node/http.json file in the directory, the require("HTTP") will not be loaded from these files, but from the native module.

The native module also has a cache, which is also loaded from the cache first. If the cache has not been loaded, call the loading method of the native module for loading and execution

Load from file

When the file module does not exist in the cache and is not a native module, Node.js will parse the parameters passed in by the require method and load the actual file from the file system. The packaging and compilation details in the loading process have been described in the previous section. Here we will describe in detail the process of finding the file module, and some details are worth knowing.

The require method accepts the following parameters:

  • http, fs, path, etc., native modules.
  • . / mod or... / mod, the file module of the relative path.
  • /pathtomodule/mod, file module of absolute path.
  • mod, file module of non-native module.
    Execute the require(X) statement under path Y in the following order:
1. If X It is a built-in module
   a. Return to built-in module
   b. Stop execution
2. If X with '/' start
   a. set up Y Is the root path of the file
3. If X with './' or '/' or '../' start
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. Throw exception "not found"

LOAD_AS_FILE(X)
1. If X It's a file, take X As JavaScript Text loads and stops execution.
2. If X.js It's a file, take X.js As JavaScript Text loads and stops execution.
3. If X.json It's a file, analysis X.json by JavaScript Object and stop execution.
4. If X.node It's a file, take X.node Load as a binary plug-in and stop execution.

LOAD_INDEX(X)
1. If X/index.js It's a file,  take X/index.js As JavaScript Text loads and stops execution.
2. If X/index.json It's a file, analysis X/index.json by JavaScript Object and stop execution.
3. If X/index.node It's a file,  take X/index.node Load as a binary plug-in and stop execution.

LOAD_AS_DIRECTORY(X)
1. If X/package.json It's a file,
   a. analysis X/package.json, And find "main" Field.
   b. let M = X + (json main field)
   c. LOAD_AS_FILE(M)
   d. LOAD_INDEX(M)
2. LOAD_INDEX(X)
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
   b. DIR = path join(PARTS[0 .. I] + "node_modules")
   c. DIRS = DIRS + DIR
   d. let I = I - 1
5. return DIRS

Posted by VenusJ on Sat, 20 Nov 2021 03:24:25 -0800