できない.dev

Node.js で「Error [ERR_REQUIRE_ESM]」が解消できない

ESM 専用パッケージを CommonJS の require() で読み込もうとすると ERR_REQUIRE_ESM になる。
動的 import() を await する、package.json を type:module に切り替える、または ESM 化前のバージョンに固定する。

#node#esm#commonjs#require#import

要約

Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported. は、require()ESM 専用 パッケージを読もうとして拒否された状態。
メジャー更新で ESM only に切り替わるライブラリが増えているため頻発する。
動的 import()type:module 化、バージョン pin、Node 22 LTS の require(esm) の 4 択で対処する。

よくある原因

  1. ESM only への更新: chalk@5 / node-fetch@3 / nanoid@4 のように、メジャー更新で ESM only に切り替えたパッケージを CJS から require している。
  2. モジュール構文の混在: CJS 前提のプロジェクトで import 構文を混ぜているが、tsc / Babel の出力が require のまま。
  3. type 未指定: package.json"type":"module" が無いと Node は .js を CJS として扱う。
  4. Node が古い: 20 以前は ESM 連携が部分的で、トップレベル await や条件付き export の動きが新しい LTS と違う。

解決策

1. 動的 import を await する

// CJS プロジェクトのまま、関数内で取り込む
async function main() {
  const { default: chalk } = await import("chalk");
  console.log(chalk.green("ok"));
}
main();

CJS のトップレベルでは await が使えないため関数で囲む。公式 ESM ドキュメント のとおり、動的 import() は ESM / CJS どちらからも呼べる唯一の橋渡し。

2. プロジェクトを ESM 化

package.json に追記する。

{
  "type": "module"
}

これで .js が ESM 扱いになり、import { x } from "pkg" がそのまま使える。require を残したいファイルだけ拡張子を .cjs に変える。

3. CJS 対応の最終版に pin

npm install chalk@^4

移行が間に合わない既存コードに対しては、ESM 化前の最終メジャーに固定する暫定策。^5 などに上げ直す前に、テストが通る状態を作る。

4. Node 22 LTS の require(esm) を試す

Node.js Modules ドキュメント によれば、22 LTS 以降は実験的に CJS から ESM の require がサポートされている(一部制約あり)。--experimental-require-module フラグの要否はマイナーバージョンで変化するため、リリースノートで現状を確認する。

この記事は役立ちましたか?