提供满足 esm、commonjs 和 bundlers 的 module、main 和 browser 字段

provide module, main and browser fields that satisfy esm, commonjs and bundlers

我有许多已发布的 npm 包,我已经升级它们以提供 commonjs 和 esm 构建。一些包可能同时适用于节点和浏览器。所有使用 webpack 或 rollup 编译的包。所有都是用打字稿写的,并转译到 dist 目录中。

我创建了一个如下所示的 commonjs index.js 文件:

 'use strict'
  
  if (process.env.NODE_ENV === 'production') {
    module.exports = require('./react-abortable-fetch.cjs.production.min.js')
  } else {
    module.exports = require('./react-abortable-fetch.cjs.development.js')
  }

我将 package.json main 字段设置为上面的 index.js 文件。

我还为每个包生成一个 .esm.js 文件,我将 browsermodule 字段都设置为 esm.js 文件并设置 type文件为 module.

最终结果是这样的:

  "type": "module",
  "main": "dist/index.js",
  "browser": "dist/react-abortable-fetch.esm.js",
  "module": "dist/react-abortable-fetch.esm.js",
  "types": "dist/index.d.ts",

这种方法的问题是只有 esm 包可以使用它(除非我错了)。

配置 package.json 文件的最佳方法是什么,以便尚未实现飞跃的包(而且相当多)仍然可以使用该包?

想法是利用 Node.js conditional exports 根据导入模块的方式自定义导入行为(requireimport)。

为了让 CommonJS 和 ESM 有两个不同的接口,您可以:

  • 转译为 CommonJS 和 ESM(允许在同一个应用程序中为您的库意外使用 importrequire,这可能会导致不需要的和不可预测的行为)
  • 将实现作为 ESM 和 CommonJS 包装器(不可能,因为当它具有顶级 await 时你不能 require ECMAScript 模块)
  • 将实现作为 CommonJS 和 ESM 包装器(最佳实际解决方案)

因此您必须将 CommonJS 设置为 TypeScript 转译目标,然后创建一个 ESM 包装器(最好在专用文件夹中)。最后将CommonJS和ESM入口点映射到package.json:

中对应的文件
"exports": {
  "require": "./index.js",
  "import": "./esm/index.js"
}

我在这里发布了一个最小的工作项目:https://github.com/Guerric-P/demo-commonjs-esm

为了使用 TypeScript 中的库,每个 JavaScript 个文件还需要一个 .d.ts 文件。