详解开发 npm 库时,package.json 里的相关字段。

main & module

以前使用 main 和 module。main 指向主要入口, 一般是 cjs 格式的。module 指向 esm 入口。注意,仅 webpack 和 rollup 等打包工具支持 module,而 nodejs 仅支持 main. 如果你直接执行 node 命令如node your.js,你的 js 文件引入了库,node 将只会调用库的 main 字段对应的文件。

exports

exports 可以导出多个入口。

{
  "exports": {
    ".": {
      "import": "./src/main-esm.js",
      "require": "./src/main-cjs.js",
      "types": "./src/main.d.ts"
    },
    "./module-a": {
      "import": "./src/module-a-esm.js",
      "require": "./src/module-a-cjs.js",
      "types": "./src/module-a.d.ts"
    }
  }
}

"."代表主要入口,即上面的 main & module。子级的"import"是 esm 文件, "require"是 cjs 文件。"types"是类型定义文件。

遗憾的是,"exports"被 nodejs 和主要打包工具支持,却不被当前稳定版本的 typescript(4.5)支持。typescript4.7 已经支持了,但是 vscode 内置的是 4.5. 所以使用 vscode 时会找不到"exports"里的类型定义文件。

所以如果你的库有多个入口并且每个入口都有自己的类型定义文件,我建议你不要这样做,而是发布为不同的 npm 库。

package.json 例子

{
  "type": "module",
  "main": "./src/index.cjs",
  "module": "./src/index.js",
  "types": "./src/index.d.ts",
  "exports": {
    ".": {
      "require": "./src/index.cjs",
      "import": "./src/index.js",
      "types": "./src/index.d.ts"
    }
  }
}

因为使用了"type": "module", 所以导出的 cjs 文件用'cjs'扩展名。