提供满足 esm、commonjs 和 bundler 的 module、main 和 browser 字段 [英] provide module, main and browser fields that satisfy esm, commonjs and bundlers

查看:21
本文介绍了提供满足 esm、commonjs 和 bundler 的 module、main 和 browser 字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a number of published npm packages that I have upgraded to provide both commonjs and esm builds. Some of the packages might be for both node and the browser. All packages compiled with webpack or rollup. All are written in typescript and transpiled into a dist directory.

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

I create a commonjs index.js file that looks like this:

 '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 文件.

I set the package.json main field to the above index.js file.

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

I also generate a .esm.js file for each package and I set both browser and module fields to the esm.js file and set the type file to be 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 包可以使用它(除非我错了).

The problem with this approach is that only esm packages can consume it (unless I am wrong).

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

What is the best way to configure the package.json file so that packages that have not made the leap yet (and that is quite a few) can still consume the package?

推荐答案

这个想法是利用 Node.js 条件导出 以根据您导入模块的方式(requireimport)自定义导入行为.

The idea is to leverage Node.js conditional exports to customize the import behavior depending on how you import the module (require or import).

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

In order to have two different interfaces for CommonJS and ESM, you could either:

  • 转换为 CommonJS 和 ESM(允许在同一应用程序中意外将 importrequire 用于您的库,这可能会导致不需要和不可预测的行为)
  • 将实现作为 ESM 和 CommonJS 包装器(不可能,因为当 ECMAScript 模块具有顶级 await 时,您不能require)
  • 将实现作为 CommonJS 和 ESM 包装器(最佳实际解决方案)
  • Transpile to both CommonJS and ESM (allows to accidentally use both import and require for your library in the same application which could cause unwanted and unpredictable behaviors)
  • Have the implementation as ESM and a CommonJS wrapper (not possible because you can't require an ECMAScript module when it has top-level await)
  • Have the implementation as CommonJS and an ESM wrapper (best actual solution)

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

So you have to set CommonJS as a TypeScript transpilation target, then create an ESM wrapper (preferably in a dedicated folder). Finally, map the CommonJS and the ESM entry points to the corresponding files in the package.json:

"exports": {
  "require": "./index.js",
  "import": "./esm/index.js"
}

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

I have published a minimal working project here: https://github.com/Guerric-P/demo-commonjs-esm

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

In order to use the libraries in TypeScript, you also need one .d.ts file aside every JavaScript file.

这篇关于提供满足 esm、commonjs 和 bundler 的 module、main 和 browser 字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆