Node项目中 CommonJs语法 和ES6 Module的语法 ,两个不同语法的文件可以互相导入吗?
现象
项目A:ESM 模块文件中导入 CommonJS 模块文件。运行项目没报错
https://stackblitz.com/edit/stackblitz-starters-pescaa?file=p...
项目B:CommonJS 模块文件中导入 ESM 模块文件,运行项目报错
https://stackblitz.com/edit/stackblitz-starters-hujdvx?file=p...
关于
在 https://nodejs.org/api/packages.html 中有这样一段内容:
如果以模块的形式导入会使用模块自己的 package.json. 如果以路径的形式化导入会使用被导入文件就近的 package.json.我的这个理解对不对?
问题
我一时也不知道该怎么表述这个问题了。大概就是 ESM 和 CommonJS 互相导入的问题吧。
- 项目是 ESM,那么项目的某些文件中能不能用 CommonJS、然后在 ESM 中导入 CommonJS?或者项目是 CommonJS,项目的某些文件是 ESM,CommonJS 中能不能导入 ESM?
- import 本地项目的某一个文件,为什么会使用导入文件附近的 package.json?被导入文件附近的 pacakge.josn 有什么影响?
- 如果是导入模块,是不是一般模块的 package.json 中都会指明使用 CommonJS 语法会导入哪个文件、使用 ESM 语法会导入哪个文件?
===============================================
对于以上的问题 @然后去远足 已经给出了准确的回答。
补充两个问题
另外就是 在 https://nodejs.org/api/packages.html 的开头部分 ES 模块和CommonJS模块的对比中提到了, ES可以 loader commonjs, commonjs不能loader es
补充问题:
1.至于为什么 commonjs 不能loader es,我不确定,chatgpt的回复
@然后去远足 求大佬再帮忙解释一下。
2.让chatgpt给个示例, 他给出的示例中 提到的输出顺序 也搞不懂为什么 顺序不确定。
按照我的理解: commonjs的require是同步的,es的import也是同步的。所以main.js 中 require('./commonjsModule.js');commonjsModule.js中 require('./es6Module.mjs');
所以 es6Module.mjs 不是应该先被加载并执行内部的代码吗?

A1:
可以混用,但最好不要这么做。
ESM 里引入 CommonJS 的话就正常 import
就好了,没什么特殊的。
CommonJS 里引入 ESM 稍微有点儿特殊,需要用 dynamic import
而不是 require()
:
- let bModule = require('./pathA/pathB/b.js');
- console.log('bModule', bModule);
+ import('./pathA/pathB/b.js').then((bModule) => {
+ console.log('bModule', bModule);
+ });
A2:
.mjs
、.cjs
文件分别以何种方式加载这没什么争议,有问题的是 .js
这种文件。
因为模块加载器需要提前知道一个 .js
到底是 CommonJS 还是 ESM 的、好来决定用哪种方式去加载,但显然通过文件名本身是没办法知道的,所以变成了通过 package.json 来区分。优先会找你导入的那个模块同级目录下的 package.json、如果没有那就向上一级目录找、还没有就再向上 …… 直到项目根目录为止,此时也就是跟你项目本身的设置保持一致了。
A3:
如果是只支持一种模块方案的,那就在 package.json
里配置 type
这个字段来标明。不标明默认就是 CommonJS,毕竟要跟以前的 Node 项目兼容 —— 老项目肯定都是只支持 CommonJS 的。
如果两种都支持,Node v14 之后 package.json
有了 exports
这个新的配置,你可以通知配置 CommonJS 和 ESM 两种模块的指向。新一点的库一般都是这种方式了,你会发现它的项目结构里同时有 es
和 lib
两个子目录,其实就分别代表 ESM 和 CommonJS,然后 exports
里会分别指向这两个目录。
当然了,开发的时候都是按一种方式去开发,最后通过 Webpack、Rollup 之类的构建工具转译成两种模块方案;而不是写两遍代码。

- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容