Skip to content

Node CJS 和ESM 混合开发

禁止 module.exports 和 exports.fn 混用

解决filename,dirname无法直接使用

导入pkg的方法

或者放入到立即执行函数中 async await可以使用

不建议混用,建议使用esModule,因为ESM兼容commonjs

常见错误

引入纯 ESM 模块化的第三方包

https://blog.csdn.net/xs20691718/article/details/122727795?spm=1001.2014.3001.5502

引入一个概念 Pure ESM package,也就是纯 ESM 模块化的包, 如果要使用这种第三方库,可以阅读文档:https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

如果一个库是 Pure ESM package 的话,它就没办法再被 commonjs 标准的代码使用 require 引用了,如果要解决这个问题,文档中提出了三种方案:

  • Use ESM yourself. **(preferred)**Use import foo from 'foo' instead of const foo = require('foo') to import the package. You also need to put "type": "module" in your package.json and more. Follow the below guide.
  • If the package is used in an async context, you could use await import(…) from CommonJS instead of require(…).
  • Stay on the existing version of the package until you can move to ESM.

关于 nodejs 中如何处理 ES6 模块的,可以参考:https://www.ruanyifeng.com/blog/2020/08/how-nodejs-use-es6-module.html

  1. Use ESM yourself 第一种方式比较扯,就是把你自己的库也改成 ESM 标准,这就很坑了,这不是扩大了兼容性的问题了嘛。

  2. use await import(…) 第二种方式,就是将静态的 import 语句,改为动态的 import() 方法,例如:

text
// before
import { xxx } from 'globby';

// after
const { xxx } = await import('globby');

理论上讲好像可以,但是我实际尝试的时候,发现如果 tsc 编译后为 commonjs 标准的话, import() 方法会被转化为一个__importStar(require('globby'))方法,本质上还是 require() ?所以还是会报错。

需要进一步调研看看。

  1. Stay on the existing version of the package until you can move to ESM 这个方法也很扯淡,就是在你可以将你的项目改为 ESM 标准之前,使用旧版本的 commonjs 标准的第三方库。

解决方法 上面的三种方式,都没有解决问题,只能采取一种治标不治本的方式了。

既然第三方库是 ESM 标准,那么我们在 tsc 编译时,把它也编译一下好了。

以 globby 为例,在 tsconfig 文件中加入以下代码:

text
{
	"compilerOptions": {
		...
		// 因为 globby 是用 js 写的,所以在 tsconfig 中要将 allowJs 设置为 true
		"allowJs": true
	},
	"include": [
		"node_modules/globby/**/*"
	]
}

此时再运行 tsc 编译,会发现在输出的 dist 目录中,新增了一个 node_modules 目录,其中包含了编译后的 globby 包代码。

但是这里需要注意下,再次运行项目,发现还是报同样的错,只是报错的库由 globby 变成了 array-union,这 是因为 globby 是 pure ESM package,经过 tsc 编译后变成了 commonjs 标准,但是 globby 引用了 array-union,而 array-union 也是 pure ESM package。

以此类推,需要把所有的 pure ESM package 都编译一下:

json
{
  "include": [
    "node_modules/globby/**/*",
    "node_modules/array-union/**/*",
    "node_modules/slash/**/*"
  ]
}

完美,问题解决。

这里要吐槽一下,array-union 这个库,其实就一行代码: constarrayUnion = (...arguments_) => [...newSet(arguments_.flat())]; 就这还引入一个额外的库,坑!

Contributors

作者:Long Mo
字数统计:903 字
阅读时长:3 分钟
Long Mo
文章作者:Long Mo
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Longmo Docs