当前位置: 首页 > 知识库问答 >
问题:

前端 - Node项目中 CommonJs语法 和ES6 Module的语法 ,两个不同语法的文件可以互相导入吗?

傅新
2023-09-10

现象

  1. 项目A:ESM 模块文件中导入 CommonJS 模块文件。运行项目没报错

    https://stackblitz.com/edit/stackblitz-starters-pescaa?file=p...
  2. 项目B:CommonJS 模块文件中导入 ESM 模块文件,运行项目报错

    https://stackblitz.com/edit/stackblitz-starters-hujdvx?file=p...

关于

在 https://nodejs.org/api/packages.html 中有这样一段内容:

image.png

如果以模块的形式导入会使用模块自己的 package.json.
如果以路径的形式化导入会使用被导入文件就近的 package.json.
我的这个理解对不对?


问题

我一时也不知道该怎么表述这个问题了。大概就是 ESM 和 CommonJS 互相导入的问题吧。

  1. 项目是 ESM,那么项目的某些文件中能不能用 CommonJS、然后在 ESM 中导入 CommonJS?或者项目是 CommonJS,项目的某些文件是 ESM,CommonJS 中能不能导入 ESM?
  2. import 本地项目的某一个文件,为什么会使用导入文件附近的 package.json?被导入文件附近的 pacakge.josn 有什么影响?
    image.png
  3. 如果是导入模块,是不是一般模块的 package.json 中都会指明使用 CommonJS 语法会导入哪个文件、使用 ESM 语法会导入哪个文件?

===============================================

对于以上的问题 @然后去远足 已经给出了准确的回答。

补充两个问题

另外就是 在 https://nodejs.org/api/packages.html 的开头部分 ES 模块和CommonJS模块的对比中提到了, ES可以 loader commonjs, commonjs不能loader es

image.png
image.png

补充问题:

1.至于为什么 commonjs 不能loader es,我不确定,chatgpt的回复

image.png
@然后去远足 求大佬再帮忙解释一下。

2.让chatgpt给个示例, 他给出的示例中 提到的输出顺序 也搞不懂为什么 顺序不确定。

image.png
image.png

按照我的理解: commonjs的require是同步的,es的import也是同步的。
所以main.js 中 require('./commonjsModule.js');
commonjsModule.js中 require('./es6Module.mjs');

所以 es6Module.mjs 不是应该先被加载并执行内部的代码吗?

共有1个答案

姬奇思
2023-09-10

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 两种模块的指向。新一点的库一般都是这种方式了,你会发现它的项目结构里同时有 eslib 两个子目录,其实就分别代表 ESM 和 CommonJS,然后 exports 里会分别指向这两个目录。

当然了,开发的时候都是按一种方式去开发,最后通过 Webpack、Rollup 之类的构建工具转译成两种模块方案;而不是写两遍代码。

 类似资料:
  • 在C和C中都有效但具有不同语义学的语法示例是什么?换句话说,使用C和C编译器编译时产生不同输出的程序示例是什么?

  • 我试图将一个lexer语法导入到另一个lexer语法中。导入的语法使用不同的模式(在XMLLexer示例中,mode INSIDE和PROC_INSTR)。 如果我将导入的部分内联到主lexer定义中,解析器就可以工作,但我希望使用导入功能来进行干净的分离。(不是针对XML/HTML示例,而是在另一种情况下。) 是否有可能让它工作使用进口或这是一个ANTLR4的限制?

  • 问题内容: 说,我们在ES6中使用React。我们将React和Component导入为 为什么语法不同?我们不能按以下规定使用吗? 问题答案: 下面是文档的。 以上是默认导入。默认导入使用导出。只能有一个默认导出。 但这是成员导入(称为导入)。成员进口与出口。可以有很多成员出口。 您可以使用以下语法导入两者: 在JavaScript中,默认导入和命名导入被拆分,因此您不能像默认导入那样导入命名导

  • 我有一个带有rollup bundler的nodeJS/express应用程序。我使用rollup配置文件,命令在包中定义。json,比如:“build”:“env ROLLUP_OPTIONS='prod'ROLLUP--config configs/ROLLUP.config.js”。当我尝试“npm运行构建”时,我遇到了错误: 在汇总源代码中,这是导致错误的函数: 此函数(见上图)位于nod

  • 我正在使用antlr4 maven插件构建使用antlr4的maven项目: 我从一个语法文件开始,得到了我的pom。xml设置,一切都很好。 然后,我决定将语法拆分为逻辑部分,因此使用了几个语法文件,但它们位于不同的目录中(因此生成的代码将放在单独的包中),但仍然位于同一根src/main/antlr4目录下。 我在“顶层”语法文件中使用import语句来导入其他必需的文件。 但是现在maven

  • 问题内容: 你可以添加新的语句(例如)Python的语法? 说,允许 要么, 如果你应该的话,并没有那么多,但是,如果可能的话,就不那么多了(只需修改python解释器代码) 问题答案: 本文旨在更好地了解Python前端的工作方式。仅阅读文档和源代码可能会有点无聊,因此我在这里采用动手方法:我将向untilPython 添加一条语句。 本文的所有编码都是针对Python Mercurial存储库