2024年10月17日(日本時間)にリリースされたNode.js v23の主な変更点を紹介します。
- require()でESMを読み込む機能が安定版に
- "module-sync"をexports conditionに追加
- node --run が安定版へ
- Node.jsのテストランナー(node:test)のカバレッジ対象をglobで指定できるフラグの追加
- Windows 32-bitはサポート対象外へ
- v23のEOL予定について
- まとめ
- 参考記事
記事内のサンプルコードはすべて以下のリポジトリにあります。
require()でESMを読み込む機能が安定版に
v22から追加されたrequire()
でESMなファイルを読み込む機能ですが、以下のように--experimental-require-module
フラグを付けて実行する必要がありました。しかし、v23からはフラグなしでも実行可能になりました。
// Node.js v22以前はフラグが必要 node --experimental-require-module index.cjs // Node.js v23以降はフラグが不要 node index.cjs
以下のようにESMをCJSのファイルでrequire()
を使って読み込むことができます。
// index.cjs const { module } = require('./module.mjs`);
ただし、top-level awaitを使っているESMファイルを読み込むとエラーが発生します。これはrequire()
はあくまで同期的なモジュールの読み込みしかできないのに対して、Top-level Aawaitは非同期でなければいけないためです。
// ESMファイル // top-level awaitを使っている const response = await fetch("https://api.example/xxx'); export const text = await response.text();
// CJSファイル const { text } = require('./module.mjs'); // => top-level awaitを用いるファイルを読み込もうとしたのでERR_REQUIRE_ASYNC_MODULEエラーが発生する
また、require(esm)
が利用可能かどうかの判定をするためにはprocess.features.require_module
が有効です。
if (process.features.require_module) { const foo = require("package-a").foo; console.log(foo()); // module-sync }
top-level awaitを使うファイルにさえ気をつければCJSな環境でもESMのファイルを読み込むことができてとても便利です。
Node.js v22の記事でも説明しているので、そちらも興味があればお読みください。
"module-sync"をexports conditionに追加
前述したrequire(esm)
に関連するのですが、package.jsonのexports
フィールドに新しく"module-sync"
を設定できるようになりました。
これはrequire()
で読み込まれるモジュールを指定することができます。
package.jsonのexports
フィールドは条件に応じて読み込ませるモジュールを変更することができる機能です。
{ "type": "module", "main": "./index.js", "exports": { ".": { "require": "./index.cjs", "default": "./index.js" } } }
package.jsonに上記のような設定がされているnpmパッケージをESMから読み込もうとしたときは./index.js
が読み込まれ、CJSから読み込もうとしたときは./index.cjs
が読み込まれます。
v23ではこのexports
に"module-sync"
を指定することができます。
{ "type": "module", "main": "./index.js", "exports": { ".": { "module-sync": "./module.js", "default": "./index.js" } } }
たとえば、以下のようなファイルがあったとします。
// index.js await Promise.resolve(); export const foo = () => { return 'default'; };
こちらはtop-level awaitを使っているのでrequire()
で読み込むとエラーになります。なので、package.jsonのexports
では"default"
や"import"
に指定します。
{ "type": "module", "main": "./index.js", "exports": { ".": { "default": "./index.js" } } }
次にrequire()
で読み込めるような以下のファイルがあったとします。
// module.js export const foo = () => { return 'module-sync'; };
こちらはtop-level awaitを利用していないので、require()
で読み込んでもエラーになりません。ですから"module-sync"
に設定します。
{ "name": "package-a", "type": "module", "main": "./index.js", "exports": { ".": { "module-sync": "./module.js", "default": "./index.js" } } }
上記のような"module-sync"
が設定されたパッケージをrequire()
で読み込むコードをNode.js v23で実行するとmodule.js
が実行されます。
const { foo } = require("package-a"); console.log(foo()); // => bar
こちらの"module-sync"
はまだ実験的な機能ですので、実行時に以下の警告が表示されます。
(node:73758) ExperimentalWarning: Support for loading ES Module in require() is an experimental feature and might change at any time
Node.js v22以前の"module-sync"
に対応していないバージョンでrequire()
を使って読み込むと、./index.js
を読み込んでしまい、ERR_REQUIRE_ASYNC_MODULEエラーが発生します。
require(esm)
と"module-sync"
によりESM/CJSの互換性は向上するので、npm packageの作成者は利用をおすすめします。
node --run が安定版へ
Node.jsの実行オプションである--run
オプションはnpm run
と同じようにpackage.jsonの"scripts"
に記載したコマンドを実行することができます。
Node.js v22.0.0で実験的な機能として追加された機能ですが、v23からは安定版として利用可能です。
たとえば、以下のように"test"
コマンドが定義されていたとします。
"scripts": { "test": "node --test" },
以下のようにNode.jsを実行すると"test"
を実行することができます。
node --run test
Node.jsのテストランナー(node:test)のカバレッジ対象をglobで指定できるフラグの追加
Node.js v18でNode.js本体にもテストランナーが追加され、v20で安定版となりました。 カバレッジ取得についてはまだ実験的な機能ですが可能です。以下のようにフラグを付けて実行します。
node --test --experimental-test-coverage
v23からカバレッジを取る対象または対象外のファイルをglobパターンで指定できるようになりました。
カバレッジ対象を指定するには--test-coverage-include
を使います。たとえば、src
フォルダの中のファイルだけカバレッジを取りたい場合は以下のように指定します。
node --test --experimental-test-coverage --test-coverage-include=src/**/*.js
カバレッジ対象外を指定するには--test-coverage-exclude
を使います。たとえば、.test.js
の拡張子が付くファイルを対象外にしたい場合は以下のように指定します。
node --test --experimental-test-coverage --test-coverage-exclude=**/*.test.js
Windows 32-bitはサポート対象外へ
Node.js v23から32bit版のWindowsはサポート対象外となりました。Node.jsのビルド対象からも削除されたので、Node.jsのバイナリが提供されることはありません。
もしWindowsの32bit版をお使いの方は環境を移行するかNode.jsのソースコードを修正して自分でビルドするしかありません。
v23のEOL予定について
今回紹介したNode.js v23は2025年6月でメンテナンスが終了する予定です。
今回紹介した機能は次のv24(2025年4月リリース予定)でも利用可能なので、そちらへ移行するようにしてください。
日程についての最新の情報は以下のリポジトリをご確認ください。
まとめ
今回はrequire(esm)
がフラグなしで利用可能になったことや"module-sync"
を使ってCJS向けに安全にパッケージを提供できる仕組みが追加されたことが大きいと思います。これによりより一層ESMを利用する流れになっていくと良いと思います。
長くなってしまいましたが、最後までお読みいただきありがとうございました。不備や質問がございましたら、@shisama_までメンションするかブコメなどでコメントください。