【umi】02 如何在cjs 环境用esm包

428 阅读2分钟

假设我们要在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中, 发现这些包都是从本地引入中

image.png

于是顺势点击看了下compiled/chalk, 发现像是转译过

image.png

于是问题就来了, 怎么转译的,难道直接把源码扒下来,后面在package.json看到这样一句命令

 "scripts": {
    "build:deps": "umi-scripts bundleDeps",
  },

你可能会好奇,umi-scripts 在做一件什么事情,暂时先不论,之前有聊过,后面再详细聊下,现在只关注bundleDeps这个文件, 执行了下,看上去是把文件转化为cjs

image.png

至于转化哪些文件是根据package.json下面的配置

  "compiledConfig": {
    "deps": [
      "address",
      ...
     ]
   }

image.png

核心代码是这段, 比我想象中复杂多了,看得我有些吃力

image.png

其实这里我保持疑问,因为compiled是umi做的依赖预编译。这里刚好凑巧,引入了compiled后的代码。

3、 用tsx

根据tsx所讲,可以在node 下执行ts或esm的文件,

image.png

如果在项目中写一些简单的脚本,是很方便,结合强大的zx, 写起来就很舒适

虽然我还没明白umi中为啥要经过compiled, 如果写一个cli都要这么转换的,那复杂度岂不是很高,那不还不如用cjs的方式写

如果笔记有哪里不对的地方,可以指出来

4、 参考