在Node.js的代码中,可以引用其它模块,用法如下:
const xxx = require('xxx');
Node.js的模块,可分为:
例如Node.js内置的 http 模块。
使用 require() 方法加载模块时,得到的是其 module.exports 所指向的对象。
创建文件 0727_5.js :
var f = function() {
console.log('hello')
}
// module.exports.username = 'Tom';
// module.exports.password = 'xyz';
// module.exports.f = f
module.exports = {
name: 'Jerry',
password: 'abc',
f
}
module.exports 指向一个JavaScript对象(如果换成被注释的代码,效果也一样)。
创建文件 0727_6.js :
const xxx = require('./0727_5.js');
console.log(xxx);
xxx.f();
运行程序:
➜ temp0727 node 0727_6.js
{ name: 'Jerry', password: 'abc', f: [Function: f] }
hello
注意:使用 require() 方法加载模块时,会执行被加载模块的代码。例如:如果在 0727_5.js 中添加一行代码:
console.log('good');
再次运行程序:
➜ temp0727 node 0727_6.js
good
{ name: 'Jerry', password: 'abc', f: [Function: f] }
hello
可见,在 require('./0727_5.js') 处,会执行 0727_5.js 的代码。
由于 module.exports 写起来比较复杂,Node提供了 exports 对象。默认情况下, exports 和 module.exports 指向同一个对象。但是要注意,这跟Java里面“ A 和 B 两个对象可以指向同一个实例,也可以指向不同实例”类似,最终 require() 方法获取的是 module.exports 指向的对象。
比如:
创建文件 0727_8.js :
const xxx = require('./0727_7.js');
console.log(xxx);
其中 0727_7.js 内容为:
exports.username = 'Tom';
module.exports.password = 'xyz';
则运行程序,结果为:
➜ temp0727 node 0727_8.js
{ username: 'Tom', password: 'xyz' }
若 0727_7.js 内容为:
module.exports = {
height: 180,
weight: 70
}
exports.age = 20;
则运行程序,结果为:
➜ temp0727 node 0727_8.js
{ height: 180, weight: 70 }
注意: exports.age = 20 并没有起作用,因为 module.exports 已经指向别处了。
Node.js 中的第三方模块又叫做包。
包是基于内置模块封装出来的,提供了更高级、更方便的 API,极大的提高了开发效率。包和内置模块之间的关系,类似于jQuery和浏览器内置 API之间的关系。
Node.js的包管理工具叫做 npm ( Node Package Manager ),npm会随着Node一起安装。
➜ ~ npm -v
8.11.0
安装包的命令如下:
npm i|install :项目包npm i|install -g :全局包例如,在 temp0727 目录下安装 express 包:
➜ temp0727 npm i express
added 57 packages, and audited 58 packages in 19s
7 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
安装完成之后,在当前目录下多了3个文件/文件夹:
node_modules :存放包的目录,在里面可以找到 express ;package-lock.json :记录 node_modules 目录里的包信息;package.json :包管理配置工具;我们来重点看一下 package.json ,它有点类似于Maven里的 pom.xml 配置文件。
在用git管理项目源码时,一般我们不会把三方包也放进去,所以只需在 package.json 中记录需要哪些包,而协作者获取源码之后,只需在项目根目录下运行 npm i ,就会一次性安装 package.json 里记录的所有包。
使用 npm list 命令可以看到当前项目安装了哪些包:
➜ temp0727 npm list
temp0727@ /home/ding/temp/temp0727
└── express@4.18.1
前面提到了全局包。事实上只有工具性质的包,才有全局安装的必要性。因为它们一般提供了终端命令。判断某个包是否需要全局安装,可以参考官方( https://www.npmjs.com/ )提供的使用说明。
例如,在该网站上搜索 express ,文档里提到的安装方法为:
npm install express
因为它不是工具性质的包,所以不应该使用全局安装。
搜索 i5ting_toc ,文档里提到的安装方法为:
npm install -g i5ting_toc
i5ting_toc 是一个工具,能把MarkDown文档转换为HTML文档,显然应该全局安装。
全局安装 i5ting_toc :
➜ temp0727 npm i -g i5ting_toc
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
added 17 packages, and audited 18 packages in 6s
5 vulnerabilities (2 high, 3 critical)
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
注意给出的提示信息, --global 已经过时,应该用 --location=global 。
安装之后就可以使用 i5ting_toc 工具了:
➜ temp0727 which i5ting_toc
/home/ding/Downloads/node-v16.15.1-linux-x64/bin/i5ting_toc
我们先来创建一个MarkDown文档 test.md:

用如下命令将其转换为HTML文档:
➜ temp0727 i5ting_toc -f test.md -o
pwd=/home/ding/temp/temp0727
source_file_name=/home/ding/temp/temp0727/test.md
dest_file_path=/home/ding/temp/temp0727/preview/test.html
转换后效果如下:

不论是内置模块、用户自定义模块、还是第三方模块,在第一次加载后都会被缓存,所以多次调用 require() 方法不会导致模块的代码被执行多次。
内置模块的加载优先级最高。
加载模块文件时,可以省略其扩展名,其加载顺序为:
.js 扩展名进行加载.json 扩展名进行加载.node 扩展名进行加载使用 require() 加载自定义模块时,必须指定以 ./ 或 ../ 开头的路径标识符。对于第三方模块的加载机制,Node.js会从当前目录开始,尝试从 /node_modules 文件夹中加载第三方模块。如果没有找到,则移动到上一层目录中加载,直到文件系统的根目录。
如果加载的是一个目录,则会在该目录下查找 package.json 文件,并寻找 main 属性,作为加载的入口。如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则Node.js会试图加载目录下的 index.js 文件。
https://www.npmjs.com/