在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/