现象
项目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()
: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 之类的构建工具转译成两种模块方案;而不是写两遍代码。