如何将ESM模块的import转译为CommonJS?Babel转译失败求助
我正在开发一个必须为CommonJS格式的包,因为使用它的项目暂不支持import/export语法。我的包依赖仅支持ESM的模块globby。
原本打算用Babel转译所有代码,期望Babel能将import转换为可正常运行的动态import()形式,但方案无效。项目调用我的包时抛出错误:
Error [ERR_REQUIRE_ESM]: require() of ES Module /mydir/project/node_modules/globby/index.js
from /mydir/project/node_modules/mypackage/index.js not supported.
Instead change the require of index.js in
/mydir/project/node_modules/mypackage
to a dynamic import() which is available in all CommonJS modules.
我原本期望Babel能将
import {globby} from 'globby'
转换为CommonJS可使用的形式,但并未实现。使用的Babel版本为7.19,babel.config.js配置如下:
module.exports = api => { api.cache(true) const presets = [['@babel/preset-env', { "loose": true, "targets": { "node": 16 }, "modules": 'commonjs' } ]] const ignore = ['./src/tooltip.js'] const plugins = ["@babel/plugin-syntax-dynamic-import", ["@babel/plugin-transform-modules-commonjs", { "allowTopLevelThis": true }]] return { presets, ignore, plugins } }
1. 明确Babel的转换边界
Babel只会转换你的业务代码中的模块语法,不会修改第三方依赖的代码结构。globby本身是ESM模块,转译后你的代码仍会尝试用require()加载它,这就是报错的核心原因。
2. 手动改用动态import()加载globby
CommonJS模块原生支持动态import()(返回Promise),直接在代码里替换静态import:
// 异步函数内使用 async function scanFiles() { const { globby } = await import('globby'); const result = await globby(['src/**/*.js']); return result; }
如果需要在模块顶层初始化,可以用立即执行异步函数:
let globbyInstance; (async () => { const module = await import('globby'); globbyInstance = module.globby; })(); // 后续使用时确保实例已初始化 async function useGlobby() { if (!globbyInstance) throw new Error('globby未完成初始化'); return await globbyInstance(['*.json']); }
3. 简化Babel配置避免冲突
@babel/preset-env已经内置了@babel/plugin-transform-modules-commonjs的功能,无需单独在plugins中重复配置,否则可能导致转换逻辑冲突。调整后的配置如下:
module.exports = api => { api.cache(true) const presets = [['@babel/preset-env', { "loose": true, "targets": { "node": 16 }, "modules": 'commonjs' } ]] const ignore = ['./src/tooltip.js'] const plugins = ["@babel/plugin-syntax-dynamic-import"]; return { presets, ignore, plugins } }
4. 备选方案:寻找globby的CJS兼容版本
部分ESM包会同时提供CommonJS格式的入口,可检查globby的文档或package.json确认是否有对应版本。如果没有,不推荐额外引入esm加载器,这会增加使用方的配置成本。
内容的提问来源于stack exchange,提问作者Ste

