“Error [ERR_REQUIRE_ESM]: require() of ES Module not supported” 和 “SyntaxError: Cannot use import statement outside a module” 曾经是 Node 最让人头疼的报错。新版本默认放开了很多限制,这篇在本机用 Node 26 逐个复现,看哪些已经不再报错、哪些还会、报什么,以及剩下的 ESM 报错怎么修。
没有 package.json:
$ node a.js
ESM 语法能跑,type = function
package.json 没写 type:
$ node a.js
ESM 语法能跑,type = function
(node:<pid>) [MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type of file://<tmp>/s1/a.js is not specified and it doesn't parse as CommonJS.
Reparsing as ES module because module syntax was detected. This incurs a performance overhead.
To eliminate this warning, add "type": "module" to <tmp>/s1/package.json.
package.json 写了 "type": "commonjs":
$ node a.js (退出码 1)
(node:<pid>) Warning: Failed to load the ES module: <tmp>/s1/a.js. Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension.
<tmp>/s1/a.js:1
import { readFileSync } from 'node:fs';
SyntaxError: Cannot use import statement outside a module
同样的文件,关掉模块语法自动检测(--no-experimental-detect-module):
$ node --no-experimental-detect-module a.js (退出码 1)
(node:<pid>) Warning: Failed to load the ES module: <tmp>/s1b/a.js. Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension.
<tmp>/s1b/a.js:1
import { readFileSync } from 'node:fs';
SyntaxError: Cannot use import statement outside a module没有 package.json 或 type 没写时 Node 26 会自动识别并运行(后者有性能警告);type: commonjs 才报老错误。
$ node main.cjs
require(esm) 得到: [ '__esModule', 'default', 'hi' ] hello from esm
关掉 require(esm):
$ node --no-experimental-require-module main.cjs (退出码 1)
<tmp>/s2/main.cjs:1
const m = require('./esm.mjs');
Error [ERR_REQUIRE_ESM]: require() of ES Module <tmp>/s2/esm.mjs from <tmp>/s2/main.cjs not supported.
Instead change the require of <tmp>/s2/esm.mjs to a dynamic import() which is available in all CommonJS modules.
code: 'ERR_REQUIRE_ESM'
}
ESM 里有顶层 await:
$ node main.cjs
ERR_REQUIRE_ASYNC_MODULE | require() cannot be used on an ESM graph with top-level await. Use import() instead. To see where the top-level await comes from, use --experim默认可用;关闭选项后回到 ERR_REQUIRE_ESM;含顶层 await 的才报 ERR_REQUIRE_ASYNC_MODULE。
$ node ok.mjs
静态导出: 1 { a: 1, b: 2 }
$ node bad.mjs (退出码 1)
file://<tmp>/s3/bad.mjs:1
import { a } from './dynamic.cjs';
SyntaxError: Named export 'a' not found. The requested module './dynamic.cjs' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from './dynamic.cjs';
$ node good.mjs
用默认导出: 1默认导出总可用,具名导入只有静态分析得出的才行。
$ node no_ext.js (退出码 1)
node:internal/modules/esm/resolve:989
throw error;
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '<tmp>/s4/util' imported from <tmp>/s4/no_ext.js
Did you mean to import "./util.js"?
$ node dir.js (退出码 1)
node:internal/modules/esm/resolve:989
throw error;
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '<tmp>/s4/lib' is not supported resolving ES modules imported from <tmp>/s4/dir.js
Did you mean to import "./lib/index.js"?
$ node dirname.js (退出码 1)
file://<tmp>/s4/dirname.js:1
console.log(__dirname);
ReferenceError: __dirname is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '<tmp>/s4/package.json' contains "type": "module". To treat it as a CommonJS script,
$ node req.js (退出码 1)
file://<tmp>/s4/req.js:1
const fs = require('fs');
ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '<tmp>/s4/package.json' contains "type": "module". To treat it as a CommonJS script,
修法:import.meta.dirname(新)/ fileURLToPath;createRequire:
$ node fixed.js
import.meta.dirname = true | require 可用 = function省略扩展名、目录 import、__dirname 与 require 未定义,各有明确文字与修法。
a.js(type=module 的包里):
$ node a.js
undefined object
b.cjs(type=module 的包里):
$ node b.cjs
function object
c.mjs(type=module 的包里):
$ node c.mjs
undefined object看最近 package.json 的 type 与扩展名决定文件是哪种模块。