1. 项目场景:

在学习express框架时,使用 formidable 包进行解析表单数据(文件上传)的Node.js模块时,用 import 方式进行导入。

import formidable from "formidable";

随后,使用 npm start 进行执行。

注:是通过应用生成器工具 express-generator 快速创建应用骨架的,所以使用 npm start 来执行项目。


2. 项目问题:

bug1:【SyntaxError: Cannot use import statement outside a module】

执行上述命令后。出现如下报错。
报错1
报错原因是不能在模块外使用 import 语句。在 Node.js 环境中默认使用的是 CommonJS 规范。需要使用 require 语句进行导入。import 是 ES6 中的模块化写法,CommonJS 模块与 ES6 模块不兼容。


3. 解决方案:

对 bug1 的解决方案:

针对 bug1 的解决方案:
① 在 package.json 中设置字段 “type”:“module”

② 使用 .mjs 的扩展名。(从 Node.js v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。Node.js 要求 ES6 模块采用 .mjs
后缀文件名)

现使用方法①进行解决:

添加 type 字段
添加之后,再次运行。
运行后,出现新的错误:如下。


bug2:【‘ERR_UNKNOWN_FILE_EXTENSION’】

报错2

针对 bug2, 我查看此项目中的其他模块都是使用 CommonJS 规范的 require 方式进行导入的。然后在上面我修改了“type”:“module”。说明此项目需要遵循 ES6 的模块化规范。这样造成了两种规范的混用。通过查阅资料,知道 目前阶段,通过 Babel 转码,CommonJS 模块的 require 命令和 ES6 模块的 impor 命令,可以写在同一个模块里面,但是最好不要这样做。因为 import 在静态解析阶段执行,所以它是一个模块之中最早执行的。(出自 阮一峰的《ES6 标准入门》)
混用可能不会得到想要的结果

知识点:
(1).mjs文件总是以 ES6 模块加载,.cjs文件总是以 CommonJS 模块加载,.js文件的加载取决于package.json里面type字段的设置。
(2)ES6 模块与 CommonJS 模块尽量不要混用。require命令不能加载.mjs文件,会报错,只有import命令才可以加载.mjs文件。反过来,.mjs文件里面也不能使用require命令,必须使用import。

对 bug2 的新解决方案:

由于前面大量使用了 require 进行导入。所以
① 放弃 在 package.json 中设置字段 “type”:“module” 的解决方法,且
② 将 formidable 包 的导入方式改为 require 再次进行测试。

如下代码所示:

const formidable = require('formidable');

运行查看后,结果继续报错,如下:


bug3:【Error [ERR_REQUIRE_ESM]】

报错
报错不支持 require 语法,应使用 import 语法代替。但是之前以 import 方式导入时并未运行成功。所以我采用给 formidable 进行降级尝试。查看已安装的 formidable 的版本是3.4.0。

查看版本

对bug3 的解决方案:

针对 bug3,采用:
给 formidable 进行降级到 2.1.1(支持 require 的版本)

成功
降级后运行成功,问题解决。
但是总感觉这应该不是解决此问题的最优解,更好的方法由于学习深度的不够还不能找到。以此记录,在日后的学习中希望找到最优的方法。

4. 总结:

通过解决此问题,对以下知识有了更深的理解:

1. JavaScript 的两种模块:ES6 模块(ESM)和 CommonJS 模块(CJS)。
2. CommonJS 模块使用 require() 和 module.exports,ES6 模块使用 import 和 export 。
3. ES6 模块与 CommonJS 模块的差异。
4. Node.js 的模块加载方法:
CommonJS 模块是 Node.js 专用。从 Node.js v13.2 版本开始,Node.js 默认打开了 ES6 模块支持。


Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐