假设我们要在Node环境中,使用esm包,我们先简单模拟下
// in cjs
// index.js,chalk 只有esm的包
const chalk = require('chalk');
console.log(chalk.blue('Hello World'));
那么就会报这个错误
Error [ERR_REQUIRE_ESM]: require() of ES Module not supported.
如果是在esm中(模拟esm的环境,node可以直接运行.mjs的后缀名,或者在package.json改type:"module")
// in esm
// index.js,chalk 只有esm的包
import chalk from 'chalk
console.log(chalk.blue('Hello World'));
// package.json
{
type: "module"
}
结果能够正常输出, 因为在esm 中 , import esm和cjs的包都是支持的
import module from 'esm-module'
import module from 'cjs-module'
回到问题, 如果在cjs中使用esm的包? 有几种解决办法
1、动态导入
// index.js, in cjs
(async () => {
const module = await import('chalk');
console.log(module.default.blue('Hello World'));
})();
这里不得不提一句top await, 从Node.js 14开始,支持top await,但是只能在esm 中
// in esm, index.mjs
const module = await import('chalk');
console.log(module.default.blue('Hello World'));
2、 转化esm为cjs
这个有点复杂, 这是我在umi中看到的,比如在create-umi中, 发现这些包都是从本地引入中
于是顺势点击看了下compiled/chalk, 发现像是转译过
于是问题就来了, 怎么转译的,难道直接把源码扒下来,后面在package.json看到这样一句命令
"scripts": {
"build:deps": "umi-scripts bundleDeps",
},
你可能会好奇,umi-scripts 在做一件什么事情,暂时先不论,之前有聊过,后面再详细聊下,现在只关注bundleDeps这个文件, 执行了下,看上去是把文件转化为cjs
至于转化哪些文件是根据package.json下面的配置
"compiledConfig": {
"deps": [
"address",
...
]
}
核心代码是这段, 比我想象中复杂多了,看得我有些吃力
其实这里我保持疑问,因为compiled是umi做的依赖预编译。这里刚好凑巧,引入了compiled后的代码。
3、 用tsx
根据tsx所讲,可以在node 下执行ts或esm的文件,
如果在项目中写一些简单的脚本,是很方便,结合强大的zx, 写起来就很舒适
虽然我还没明白umi中为啥要经过compiled, 如果写一个cli都要这么转换的,那复杂度岂不是很高,那不还不如用cjs的方式写
如果笔记有哪里不对的地方,可以指出来