针对 Node.js 中执行 import 语句出现 SyntaxError: Cannot use import statement outside a module 报错的排查指南,详细介绍配置 package.json 中 type: module 的具体步骤、原理、运行验证及注意事项。
Node.js 中使用 import 报错怎么办?配置 type:module 指南
时间:2026-10-30
浏览:318
文章目录
在 Node.js 环境中直接书写 ES Module 语法(如 import fs from 'fs')时,终端常常会抛出 SyntaxError: Cannot use import statement outside a module 的经典报错。出现这一错误的原因在于 Node.js 默认将 .js 文件视作 CommonJS 规范模块,必须通过在项目的 package.json 中声明 "type": "module",或者将文件后缀改为 .mjs,Node.js 才能正确启用 ES 模块解析器解析代码。本文将提供清晰的排查流程、具体配置步骤及后续开发中的常见细节。
一、为什么 Node.js 运行 import 会抛出错误?
Node.js 历史上一直采用 CommonJS(CJS)作为原生模块系统,使用 require() 加载依赖、通过 module.exports 导出功能。随着 ECMAScript 官方模块标准(ES Module,简称 ESM)的确立,现代前端生态普遍采用了 import 和 export 语法。为了维持向后兼容性,Node.js 默认将未明确标记的文件解析为 CommonJS,当解析器遇到 import 关键字时就会立即报错中止。
(node:12345) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.SyntaxError: Cannot use import statement outside a module
实际上,错误输出中已经给出了 Node.js 的官方解决建议:要么在 package.json 中配置 "type": "module",要么使用 .mjs 扩展名。下图直观展示了 Node.js 遇到 JavaScript 文件时的模块系统决策逻辑:
二、核心操作:配置 package.json 的 type: module 步骤
解决此问题最标准、最符合现代工程习惯的方法,是在项目根目录的 package.json 中显式声明 "type": "module"。配置后,该目录下及所有子目录下的所有 .js 文件都将被默认解析为 ES Module。
1. 初始化或打开 package.json
如果当前目录下还没有 package.json 文件,可以在命令行终端中切换到项目目录并执行初始化命令:
npm init -y
这会在当前目录下快速生成一份基础的 package.json 文件。
2. 在配置文件中添加 "type": "module"
使用任意文本编辑器打开 package.json,在根层级属性中添加 "type": "module" 字段。请注意检查 JSON 逗号语法是否完整正确:
{
"name": "my-node-project",
"version": "1.0.0",
"description": "Node.js ES Module project",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
3. 编写代码并进行验证
在同目录下新建 index.js,编写使用 import 语法的代码:
// index.js
import os from 'node:os';
console.log('系统平台:', os.platform());
console.log('CPU 架构:', os.arch());
console.log('Node.js 原生 ES Module 运行成功!');
在终端运行命令:
node index.js
运行结果(示例):
系统平台: darwin
CPU 架构: arm64
Node.js 原生 ES Module 运行成功!
控制台正常打印出系统信息且没有抛出语法错误,表明 type: module 配置已经生效。
完整操作流程总结如图 2 所示:
三、配置 type: module 后的重要差异与注意事项
一旦在项目中设置了 "type": "module",Node.js 对文件的处理规则将发生根本性转变。开发者如果不了解这些规则,很容易遇到新的二次报错:
1. 本地模块导入必须包含文件扩展名
在 CommonJS 中,我们可以写 const utils = require('./utils'),Node.js 会自动按顺序探测 .js、.json 或文件夹下的 index.js。但在原生 ES Module 规范中,为了与浏览器标准对齐,相对路径导入必须写出明确的文件扩展名:
// ❌ 错误做法:会抛出 ERR_MODULE_NOT_FOUND
import { calculateSum } from './utils';
// ✔ 正确做法:显式加上 .js 后缀
import { calculateSum } from './utils.js';
2. 不再提供 __dirname 与 __filename 全局变量
在 CommonJS 模块中,每个文件都有内置的 __dirname(当前文件所在目录绝对路径)和 __filename。在 ES Module 中,这两个变量已不存在。如果直接访问会提示 ReferenceError: __dirname is not defined in ES module scope。现代标准的替代方式是使用 import.meta.url 结合 url 模块进行转换:
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
// 获取当前模块的绝对文件路径与目录路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log('当前目录:', __dirname);
console.log('当前文件:', __filename);
3. 不允许直接使用 require()
在 type: module 模式下,直接调用 require('lodash') 会提示 ReferenceError: require is not defined in ES module scope。正确的做法是使用 import 语法:
import lodash from 'lodash';
如果确实需要引入某些古老的、仅支持 CommonJS 且无法通过默认 import 正常解构的第三方包,可以使用 Node.js 提供的 createRequire 工具创建专用的 require 函数:
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const legacyPkg = require('./legacy-commonjs-pkg.cjs');
4. 导入 JSON 文件需要导入断言(Import Attributes)
在 CommonJS 中可以直接 require('./data.json')。而在 ES Module 中,导入 JSON 必须显式注明类型属性(Node.js 18+ 推荐写法):
import configData from './config.json' with { type: 'json' };
console.log(configData.version);
四、替代方案:不改 package.json 时如何使用 import?
如果处于一个大型遗留项目中,或者临时只写一个简单的测试脚本,不希望因为改动 package.json 的 type 字段而影响已有的大量 CommonJS 代码,可以选用以下方案:
方案 A:直接使用 .mjs 扩展名
Node.js 规定:无论 package.json 如何配置,凡是以 .mjs 结尾的文件都会无条件强制使用 ES Module 解析。可以将文件命名为 demo.mjs,然后编写代码:
// demo.mjs
import path from 'node:path';
console.log('解析路径:', path.resolve('.'));
终端直接运行 node demo.mjs 即可,无需任何配置文件辅助。
方案 B:混合项目中使用 .cjs 保留旧模块
如果已经把 package.json 设为了 "type": "module",但项目中仍有少数脚本需要维持 CommonJS 规范(例如某些构建工具配置文件),可以将这些特定的文件后缀命名为 .cjs。在 ESM 项目中,.cjs 文件依然可以使用 require() 和 module.exports。
五、排查清单与综合选型总结
在处理 Node.js 模块语法错误时,可以参照以下排查与解决流程进行快速定位与处置:
在 Node.js 中使用
import 遇到报错,本质上是模块体系从 CommonJS 切换到 ES Module 时的解析器声明问题。通过在 package.json 中添加 "type": "module",即可直接解除 import 语法的限制。在后续开发过程中,牢记“相对路径带上 .js 后缀”以及“使用 import.meta.url 替代 __dirname”两条关键规则,就能平稳顺畅地享受现代 JavaScript 模块系统带来的开发体验。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。