啊?npm 包可以自己引入自己?

161 阅读2分钟

在一个包内,可以通过包名来引用该包的 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.

再看看具体的案例可能会有更深刻的理解,此案例的目录结构为:

95.png

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 中可以正常通过自身的包名引入其他模块:

96.png

自引用仅在 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 模块中,自引用功能也是可用的,如下面具体的案例,此案例的目录结构为:

97.png

其中,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 文件:

98.png

最后,自引用对于有作用域的包同样适用。例如下面的案例,该案例的目录结构为:

99.png

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

100.png

总结

在 npm 包内,可以通过包名引用该包的 package.json 文件中 exports 字段导出的 API ,这种特性称为包的自引用

无论是 ES 模块格式,还是 CommonJS 模块格式的包都支持包的自引用,还有带有作用域的 npm 包同样支持包的自引用。