Home>Article>Web Front-end> Understanding the module system in Node.js
Related recommendations: "node js tutorial"
JavaScript as a A simple scripting language to add interactive functions to web pages came out. It did not include a module system at the beginning. As JavaScript solved more and more complex problems, writing all codes in one file and using function to distinguish functional units can no longer support the development of complex applications. Yes, ES6 brings classes and modules that are common in most high-level languages, making it easier for developers to organize code
import _ from 'lodash'; class Fun {} export default Fun;
The above three lines of code show the two most important elements of a module system, import and export
export
is used to specify the external interface of the module
import
is used to import the functions provided by other modules
Before ES6, many module loading solutions appeared in the community, the most important ones were CommonJS and AMD. Node.js was born earlier than ES6, and the module system used something similar to CommonJS The implementation follows several principles
A file is a module, and the scope of variables in the file is within the module
Usemodule.exports
Object export module external interface
Userequire
to introduce other modules
circle.js
const { PI } = Math; module.exports = function area(r) { PI * r ** 2; };
The above code implements a module of Node.js. The module does not depend on other modules and exports the methodarea
to calculate the area of a circle
test.js
const area = require('./circle.js'); console.log(`半径为 4 的圆的面积是 ${area(4)}`);
The module relies on circle.js and uses its exposed area method to calculate the area of the circle
The external exposed interface of the module uses module.exports. There are two common usages: adding attributes to it or assigning values to new objects.test.js
// 添加属性 module.exports.prop1 = xxx; module.exports.funA = xxx; module.exports.funB = xxx; // 赋值到全新对象 module.exports = { prop1, funA, funB, };
The two writing methods are equal to Price, there is no difference when using
const mod = require('./test.js'); console.log(mod.prop1); console.log(mod.funA());
There is another way to directly use theexports
object, but you can only add attributes to it and cannot assign it to a new object. The reason will be introduced later.
// 正确的写法:添加属性 exports.prop1 = xxx; exports.funA = xxx; exports.funB = xxx; // 赋值到全新对象 module.exports = { prop1, funA, funB, };
require usage is relatively simple, id supports two types: module name and file path
const fs = require('fs'); const _ = require('lodash');
The fs and lodash in the example are both module names. fs is the built-in core module of Node.js, and lodash is a third-party module installed through npm undernode_modules
. If there are duplicate names , give priority to using the system’s built-in modules
Because a project may contain multiple node_modules folders (Node.js’ relatively failed design), the third-party module search process will follow the principle of proximity and go up layer by layer (you can find it in the program Printmodule.paths
to view the specific search path) until the file system root directory is found according to theNODE_PATH
environment variable. For the specific process, please refer to the official documentation
In addition, Node .js also searches the following global directory listing:
$HOME
is the user's home directory,$PREFIX
is thenode_prefix
configured in Node.js. It is strongly recommended to place all dependencies in the local node_modules directory, which will load faster and be more reliable
Modules can also be loaded using file paths. This is the project A common loading method for custom modules within the directory. The path extension can be omitted. Modules prefixed with
'/'
Is the absolute path of the file. Find the module according to the system path.'./'
are relative to the file currently calling the require method, and are not affected by where subsequent modules are used. To affectThe module will be cached toModule._cache
after the first load, if it is called every time ## If #require('foo')is parsed to the same file, the same object will be returned. Calling
require(foo)multiple times at the same time will not cause the module's code to be executed multiple times. Node.js caches modules based on their actual file names, so the same module is not loaded twice when referenced from different levels of directories.
a.js
console.log('a 开始'); exports.done = false; const b = require('./b.js'); console.log('在 a 中,b.done = %j', b.done); exports.done = true; console.log('a 结束');
b.js
console.log('b 开始'); exports.done = false; const a = require('./a.js'); console.log('在 b 中,a.done = %j', a.done); exports.done = true; console.log('b 结束');
main.js:
console.log('main 开始'); const a = require('./a.js'); const b = require('./b.js'); console.log('在 main 中,a.done=%j,b.done=%j', a.done, b.done);When main.js loads a.js, a.js loads b.js. At this time, b.js will Try to load a.js In order to prevent an infinite loop, an
unfinished copy of the exports object of a.jswill be returned to the b.js module, and then b.js will complete the loading. And provide the exports object to the a.js module
so the output of the example ismain 开始 a 开始 b 开始 在 b 中,a.done = false b 结束 在 a 中,b.done = true a 结束 在 main 中,a.done=true,b.done=true
看不懂上面的过程也没关系,日常工作根本用不到,即使看懂了也不要在项目中使用循环依赖!
Node.js 每个文件都是一个模块,模块内的变量都是局部变量,不会污染全局变量,在执行模块代码之前,Node.js 会使用一个如下的函数封装器将模块封装
(function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
回头看看最开始的问题,为什么 exports 对象不支持赋值为其它对象?把上面函数添加一句 exports 对象来源就很简单了
const exports = module.exports; (function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
其它模块 require 到的肯定是模块的 module.exports 对象,如果吧 exports 对象赋值给其它对象,就和 module.exports 对象断开了连接,自然就没用了
随着 ES6 使用越来越广泛,Node.js 也支持了 ES6 Module,有几种方法
使用 babel 构建是在 v12 之前版本最简单、通用的方式,具体配置参考 @babel/preset-env(https://babeljs.io/docs/en/babel-preset-env)
.babelrc
{ "presets": [ ["@babel/preset-env", { "targets": { "node": "8.9.0", "esmodules": true } }] ] }
在 v12 后可以使用原生方式支持 ES Module
开启--experimental-modules
模块名修改为.mjs
(强烈不推荐使用)或者 package.json 中设置"type": module
这样 Node.js 会把 js 文件都当做 ES Module 来处理,更多详情参考官方文档(https://nodejs.org/dist/latest-v13.x/docs/api/esm.html)
更多编程相关知识,请访问:编程视频!!
The above is the detailed content of Understanding the module system in Node.js. For more information, please follow other related articles on the PHP Chinese website!