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】
执行上述命令后。出现如下报错。
报错原因是不能在模块外使用 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
后缀文件名)
现使用方法①进行解决:
添加之后,再次运行。
运行后,出现新的错误:如下。
bug2:【‘ERR_UNKNOWN_FILE_EXTENSION’】
针对 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 模块支持。