在一个包内,可以通过包名来引用该包的 package.json
文件中 exports
字段所定义的值。例如,假设 package.json
文件内容如下:
// package.json
{
"name": "a-package",
"exports": {
".": "./index.mjs",
"./foo.js": "./foo.js"
}
}
然后,该 npm 包中的任何模块都可以通过该 npm 包的名字引用该 npm 包自身的导出内容:
// ./a-module.mjs
import { something } from 'a-package'; // Imports "something" from ./index.mjs.
再看看具体的案例可能会有更深刻的理解,此案例的目录结构为:
package.json
内容为:
{
"name": "common",
"type": "module",
"exports": {
".": "./index.mjs",
"./foo.js": "./foo.js"
}
}
index.mjs
内容为:
const a = 1
export {
a
}
foo.js
内容为:
const foo = 2
export {
foo
}
a-module.mjs
内容为:
import { a } from 'common'
import { foo } from 'common/foo.js'
console.log('a ', a)
console.log('foo ', foo)
然后在终端运行 a-module.mjs
,可以看到,在 a-module.mjs
中可以正常通过自身的包名引入其他模块:
自引用仅在 package.json
文件中包含 exports
字段时可用,并且只允许导入该 exports
字段(在 package.json 中)定义的内容,否则会产生运行时错误。
因此对于如下 package.json
文件内容,another-module.mjs
会报错:
// package.json
{
"name": "a-package",
"exports": {
".": "./index.mjs",
"./foo.js": "./foo.js"
}
}
// ./another-module.mjs
// 从./m.mjs 导入 another 会失败,因为
// package.json 的 exports 字段
// 没有提供名为 ./m.mjs 的导出
import { another } from 'a-package/m.mjs';
当使用 require
时,即在 CommonJS 模块中,自引用功能也是可用的,如下面具体的案例,此案例的目录结构为:
其中,package.json
文件内容如下:
{
"name": "common",
"type": "commonjs",
"exports": {
"./foo.js": "./foo.js"
}
}
foo.js
文件内容为:
const a = 1
const b = 2
module.exports = {
a,
b
}
a-module.js
文件内容如下,通过 npm 包名自引用自身包的模块:
const { a } = require('common/foo.js')
console.log('a ', a)
然后在命令行终端运行 a-module.js
文件:
最后,自引用对于有作用域的包同样适用。例如下面的案例,该案例的目录结构为:
package.json
文件内容如下:
{
"name": "@my/package",
"exports": "./index.js"
}
index.js
文件内容如下:
module.exports = 42
other.js
文件内容如下,通过包名引入 exports
字段导出的内容:
console.log(require('@my/package'))
然后在命令行终端使用 Node.js 运行 other.js
文件,正常输出 42
:
总结
在 npm 包内,可以通过包名引用该包的 package.json
文件中 exports
字段导出的 API ,这种特性称为包的自引用。
无论是 ES 模块格式,还是 CommonJS 模块格式的包都支持包的自引用,还有带有作用域的 npm 包同样支持包的自引用。