bigywater.tech
常见报错 · 31

Node.js ERR_REQUIRE_ESM、Cannot use import statement outside a module:Node 26 上默认已不再报,什么情况下还会报

“Error [ERR_REQUIRE_ESM]: require() of ES Module not supported” 和 “SyntaxError: Cannot use import statement outside a module” 曾经是 Node 最让人头疼的报错。新版本默认放开了很多限制,这篇在本机用 Node 26 逐个复现,看哪些已经不再报错、哪些还会、报什么,以及剩下的 ESM 报错怎么修。

不再报错
Node 26 默认 require(esm) 成功、无 package.json 时 import 直接运行;老报错要加 --no-experimental-* 才能复现
2 个
仍然会报错的主要情形:package.json 写了 type: commonjs 的 import 语法,以及含顶层 await 的 ESM 被 require
4 种
ESM 里仍然常见的报错:无扩展名、目录 import、__dirname 未定义、require 未定义

import 写在 .js 里

实测 · 本机执行输出
  没有 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 才报老错误。

require 一个 ESM

实测 · 本机执行输出
    $ 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。

ESM 里 import CJS

实测 · 本机执行输出
    $ 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

默认导出总可用,具名导入只有静态分析得出的才行。

ESM 里的其它报错

实测 · 本机执行输出
    $ 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 与扩展名决定文件是哪种模块。

分步演示

模块类型
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64;报错文本都是真实复现时原样捕获的(命令行工具统一用 LC_ALL=C 取英文原文,路径换成 );所有服务都是本机上自己起的、只监听 127.0.0.1,不访问外网;计时用 time.perf_counter,数字每次运行会有小幅抖动。本篇用 Node v26.12.0;每个例子是临时目录里的几个小文件,用子进程运行 node 并取真实输出(路径换成 ,进程号换成 );老报错用 --no-experimental-require-module 与 --no-experimental-detect-module 复现
    • 没有验证:Node 20、22 等老版本上默认值的具体版本分界(文中说的“老版本”只是这两个开关关闭后得到的报错,不是在老版本上实测);TypeScript、Babel、Jest、webpack 等工具链对模块类型的处理;package.json 的 exports / imports 字段与条件导出;动态 import() 的行为;Windows 路径下的报错文字;import attributes(with { type: "json" })
    京ICP备2026067502号-1京公网安备11010502063487号