有很多关于这方面的资源,但很容易令人困惑,我找不到任何关于这方面的最新资源:
2024 年的今天,我想创建一个用 tyescript 编写的库。 它将用于使用 webpack 捆绑器的 React 项目。该应用程序将在服务器(node.js)和浏览器中呈现。
如何配置 tsconfig.json?我该选择哪个设置
module
?
背景:
该库已经存在于 CJS 中,但在当前的大重写中,我正在考虑升级到 ESM,因为我们使用该库(目前也是 CJS)的应用程序在导入仅 ESM 模块时存在问题。而且,使用 CJS,在 webpack 中使用动态导入时,我们无法使用自动分割包。
文档
的打字稿参考指出es2015
、es2020
、es2022
、esnext
不应用于node.js
它指出
node16 和 nodenext 是所有打算在 Node.js v12 或更高版本中运行的应用程序和库的唯一正确的模块选项
但没有提及
nodenext
或 node16
是否也可以用于像 webpack 这样的浏览器/捆绑器。
这是什么?我应该选择哪个?
我想知道是否应该分开发布
/lib/cjs
和 /lib/esm
版本,并在 require
的 module
设置中包含 export
和 package.json
字段?
这仍然给我留下了一个问题:在 tsconfig 中使用哪个
module
输出设置,以便浏览器(通过 webpack)和 node.js 都可以使用 ESM。或者我应该选择其中一种环境来继续使用 CJS?
由于历史原因,组合太多,但大部分已经不需要了。总而言之,如果您想发布 Node.js 和浏览器都可以使用的仅 ESM 包,以下三个规则就足够了:
"type": "module'
。"module": "NodeNext"
"moduleResolution": "NodeNext"
"module": "ESNext"
"moduleResolution": "Bundler"
最后,还有一个公理 -
NodeNext + NodeNext
的组合是 ESNext + Bundler
的子集。另一种说法是,NodeNext + NodeNext
是具有由 Node.js 模块解析算法设置的约束的 ESM。最常见的例子是在导入语句中强制要求具有文件扩展名,例如import {} from 'other.js'
中NodeNext + NodeNext
。此限制不适用于 ESNext + Bundler
模式。
因此,如果您同时发布 Node.js(希望在不捆绑的情况下使用)和前端(希望使用
import-maps
或捆绑器),那么您应该使用 module: NodeNext + moduleResolution: NodeNext
。
这确保了 TypeScript(和其他现代捆绑器)遵循
main
规范指定的
exports
、package.json
声明。
此外,请记住
"type": "module"
很重要。如果没有,即使有 module: NodeNext
,打字稿编译器也会使用 CJS *.ts
语句将 *.js
文件编译为 require
,并使用 ESM import 语句将 *.mts
文件编译为 *.mjs
。
最后,还有另一种思考方式!如果您使用 TypeScript 作为编译器来编译您的库,那么您应该使用
NodeNext + NodeNext
。而且,如果您使用的是捆绑器,那么您可以选择任一组合(尽管我仍然建议使用 NodeNext + NodeNext
,因为它引入了严格的语义)。