The running mechanism of node modules is simple to understand. Cover general process, skip the underlying system distinction.
- CommonJS standard
- Node module loading process
- summary
1. com monJS specification
CommonJS specification, including module reference, module definition, module identification, three parts
Module references: Modules use the require method to synchronously load dependent modules
Module definition: A file is a module in Node and provides methods or variables that export the current module from exports objects
Module id: The module id is passed to the require() method as a string named camelCase or as a file path.
1.1. CommonJS application in node module
There are two ways to export module content:
The contents of A. js are as follows,
Method 1: You can mount exported variables or functions to the properties of exports objects
// Each node.js file is a separate module
// Node wraps the contents of the retrieved Javascript file, passing in the following variables
console.log(exports, require.module, __filename, __dirname);
// You can mount exported variables or functions to the properties of exports objects,
exports.name = 'luoxiaobu';
exports.age = '18'Copy the code
Exports a variable object or function as a whole using the module.exports object
// Each node.js file is a separate module
// Node wraps the contents of the retrieved Javascript file, passing in the following variables
console.log(exports, require.module, __filename, __dirname);
let name = 'luoxiaobu';
let age = '18'
// Exports an entire variable object or function using the module.exports object.
module.exports = {name,age};Copy the code
How modules are referenced: By the source from which they are referenced
// The core module is introduced into Node's own module
let crypto = require('crypto')
// User-written modules are introduced
let aModule = require('./a.js')
// third party, other people implement published module (actually also other users write)
let proxy = require('http-proxy');Copy the code
2. Node module loading process
/ / the node NativeModule
function Module(id = ' ', parent) {
this.id = id;
this.path = path.dirname(id);
this.exports = {};
this.parent = parent;
updateChildren(parent, this.false);
this.filename = null;
this.loaded = false;
this.children = [];
}Copy the code
// Set up NativeModule.
function NativeModule(id) {
this.filename = `${id}.js`;
this.id = id;
this.exports = {};
this.module = undefined;
this.exportKeys = undefined;
this.loaded = false;
this.loading = false;
this.canBeRequiredByUsers = ! id.startsWith('internal/');
}Copy the code
2.1 Description of Node Module Loading
// Check the cache for the requested file.
// 1. If a module already exists in the cache: return its exports object.
// 2. If the module is native: call
// `NativeModule.prototype.compileForPublicLoader()` and return the exports.
// 3. Otherwise, create a new module for the file and save it to the cache.
// Then have it load the file contents before returning its exports
// object.
Module._load = function(request, parent, isMain) {
let relResolveCacheIdentifier;
if (parent) {
debug('Module._load REQUEST %s parent: %s', request, parent.id); . }// Find the file location
const filename = Module._resolveFilename(request, parent, isMain);
// There is no need to perform the return cache again
const cachedModule = Module._cache[filename];
if(cachedModule ! = =undefined) {
updateChildren(parent, cachedModule, true);
if(! cachedModule.loaded)return getExportsForCircularRequire(cachedModule);
return cachedModule.exports;
}
// Load the node native module, loadNativeModule
// Mod.exports is returned if it exists and can be referenced by the user. (This includes compiling the Node module to create module objects and storing the module running results on module objects)
const mod = loadNativeModule(filename, request);
if (mod && mod.canBeRequiredByUsers) return mod.exports;
// Create a module
// Don't call updateChildren(), Module constructor already does.
const module = new Module(filename, parent);
if (isMain) {
process.mainModule = module;
module.id = '. ';
}
// Cache module
Module._cache[filename] = module;
if(parent ! = =undefined) {
relativeResolveCache[relResolveCacheIdentifier] = filename;
}
// Load and execute the new module
module.load(filename);
return module.exports;
};Copy the code
2.2 Node source Directory
General source code structure :(only annotated parts of interest)
Node Bindings: is a bridge between JS and C++, which translates the C++ interface exposed by V8 engine into JS API
V8: A JavaScript engine that provides a JavaScript runtime environment
C++ module reference process
2.3 Node Module Classification
// This file creates the internal module & binding loaders used by built-in// modules. In contrast, user land modules are loaded using// lib/internal/modules/cjs/loader.js (CommonJS Modules) or// lib/internal/modules/esm/* (ES Modules).//// This file is compiled and run by node.cc before bootstrap/node.js// was called, therefore the loaders are bootstraped before we start to// actually bootstrap Node.js. It creates the following objects:
- The core module of Node
- Node core module JS implementation
- Node core module c++ implementation, js package call c++ module
- Third-party modules, or user-written modules
-
JavaScript module, we developed to write JavaScript module
- JSON module, a JSON file
- C/C++ extension module, written in C/C++, compiled with the suffix.node (interested in the dynamic link library)
-
2.3.1 Core module of a node
(introduction of c++ core modules, exposed c++ interfaces)
Process.binding/InternalBinding is actually a C++ function that Bridges the C++ and Javascript sides of the Node library.
2.3.2 Non-core module of a node
- JavaScript modules, JavaScript modules that we develop and write (or third-party modules)
- JSON module, a JSON file
- C/C++ extension module, written in C/C++, compiled with the suffix.node (interested in the dynamic link library)
The general loading process of such modules is as follows:
Path analysis
const filename = Module._resolveFilename(request, parent, isMain);Copy the code
Is there a cache
const cachedModule = Module._cache[filename];
if(cachedModule ! = =undefined) {
updateChildren(parent, cachedModule, true);
return cachedModule.exports;
}Copy the code
Create a Module object
const module = new Module(filename, parent);
// Cache module objects
Module._cache[filename] = module;Copy the code
File location is executed according to the suffix
// Native extension for .js
Module._extensions['.js'] = function(module, filename) {
if (experimentalModules && filename.endsWith('.js')) {
const pkg = readPackageScope(filename);
if (pkg && pkg.type === 'module') {
throw newERR_REQUIRE_ESM(filename); }}const content = fs.readFileSync(filename, 'utf8');
module._compile(stripBOM(content), filename);
};
// Native extension for .json
Module._extensions['.json'] = function(module, filename) {
const content = fs.readFileSync(filename, 'utf8');
if (manifest) {
const moduleURL = pathToFileURL(filename);
manifest.assertIntegrity(moduleURL, content);
}
try {
module.exports = JSON.parse(stripBOM(content));
} catch (err) {
err.message = filename + ':' + err.message;
throwerr; }};// Native extension for .node
Module._extensions['.node'] = function(module, filename) {
if (manifest) {
const content = fs.readFileSync(filename);
const moduleURL = pathToFileURL(filename);
manifest.assertIntegrity(moduleURL, content);
}
// Be aware this doesn't use `content`
return process.dlopen(module, path.toNamespacedPath(filename));
};Copy the code
Returns the module.exports object.
3. Summary
The running mechanism of node modules is simple to understand. Involve the general process, skip the underlying system distinction.
The article sorted out the relevant materials, recorded part of the practice and their own understanding, understanding of the inaccurate, but also ask for correct. Welcome to discuss and study together.
References: