Node.js v20がリリースを迎えました。2023年4月18日の公開です。このリリースにより、Node.jsはより安全になり、パフォーマンスもさらなる進化を遂げました。

今回は偶数番目のリリースとなります。2023年10月に長期サポート(LTS)バージョンになり、2026年4月までサポートが継続する予定です。Node.js運営チームは、LTSへの昇格前に問題を特定、修正できるように、コミュニティからのフィードバックを積極的に受け付けています。

この最新リリースには、実験的なPermission Model、同期的なimport.meta.resolve、安定版テストランナー、V8 JavaScriptエンジンのバージョン11.3へのバージョンアップ、パフォーマンスの改善とバグ修正など、開発者が喜ぶアップデートや機能がふんだんに盛り込まれています。

こちらの記事では、Node.js v20で導入された点を探り、その新機能と性能を詳しくご紹介したいと思います。

Node.js v20のインストール

Node.js v20のインストールは、他のバージョンのNode.jsとよく似ています。必要な操作は、以下の通りです。

  1. Node.jsの公式サイトからインストーラパッケージをダウンロードします。
  2. インストーラをダウンロードしたら、それを実行し、指示に従ってインストール作業を完了します。このプロセスは非常に簡単で、使用許諾契約に同意して「次へ」ボタンをクリックするだけでOKです。
  3. インストールが完了したら、システム/マシンを再起動して、すべての変更が反映されるようにします。
  4. 次のコマンドを実行して、Node.jsのインストールを確認します。
node -v
Node.js v20のインストール
Node.js v20のインストール

バージョン番号(v20.0.0)が表示されていれば、Node.jsが正しくインストールされ、Node.js v20で作業を開始する準備ができたことを意味します。

Node.js v20の新機能

このNode.jsのリリースで導入された5つの主要なアップデートを順に見てみましょう。その機能は以下の通りです。

実験的なPermission Model

Node.js v20での実験的なPermission Modelの導入は、開発者による実行中の特定のリソースへのアクセスを制限する術として注目に値します。

この新機能は、本番環境など、セキュリティとリソースの利用が重要な場合に有効です。

Permission Modelには、ファイルシステム、child_process、worker_threads、ネイティブアドオンへのアクセス制限など、ある程度の幅があります。

--allow-fs-read--allow-fs-write--allow-child-processなどを使用して、アクセス可能なリソースを指定することができます。これらのフラグを有効にするには、--experimental-permissionを必要な権限と組み合わせて使用します。

以下に、Permission Modelを使用して、ファイルシステム全体の読み取りと書き込みのアクセスを許可する例を紹介します。

$ node --experimental-permission --allow-fs-read=* --allow-fs-write=* index.js

特定のフォルダやファイルへのアクセス権を指定することもできます。例えば、次のコマンドは、/tmp/フォルダへの書き込みを許可します。

$ node --experimental-permission --allow-fs-write=/tmp/ --allow-fs-read=/home/index.js index.js

Permission Modelの大きな利点は、ファイルシステムのアクセスをより細かく制御できることです。例えば、パスやワイルドカードのパターンを指定して、特定のフォルダやファイルへのアクセスを許可することができます。

$ node --experimental-permission --allow-fs-read=/home/user/* index.js

上記のコマンドは、/home/user/ディレクトリ内のすべてのフォルダへの読み取り権限を付与します。

プロセスオブジェクトのpermissionプロパティは、実行時に特定のパーミッションが付与されているかどうかをチェックするのに使用可能です。例えば、Node.jsのプロセスが特定のフォルダ、/home/user/documentsへの読み取りアクセス権を持っているかどうかをチェックするには、以下のコードを使用できます。

if (process.permission.has('fs.read', '/home/user/documents')) {
  console.log('Read access granted to /home/user/documents');
} else {
  console.log('Read access not granted to /home/user/documents');
}

Permission Modelを使用することで、Node.jsプロセスのファイルシステムへのアクセスをより細かく制御することができ、セキュリティの向上やリソース利用の効率化につながります。

この機能はまだ実験的であり、Node.jsの将来のリリースで変更される可能性がある点には、注意が必要です。Permission Modelのドキュメントを随時チェックし、この機能を使用する際には十分な注意を払うようにしましょう。

テストランナーがstableに

Node.js v20では、追加の依存関係をインストールせず、JavaScriptのテストを素早く容易に構築、実行できるtest_runnerモジュールが安定版として利用できます。

テストファイルのオーサリングや構造化のためのdescribeit/test、フックなどのビルディングブロック、モッキング、ウォッチモード、そしてnode --testコマンドを使った複数テストファイルの並列実行などが追加されました。

以下にテストランナーの使用例を示します。

import { test, mock } from 'node:test';
import assert from 'node:assert';
import fs from 'node:fs';

mock.method(fs, 'readFile', async () => "Hello World");
test('synchronous passing test', async (t) => {
  // This test passes because it does not throw an exception.
  assert.strictEqual(await fs.readFile('a.txt'), "Hello World");
});

テストランナーには、--test-reporterフラグによるカスタムテストレポート、--experimental-test-coverageフラグによる実験的テストカバレッジ、そしてモッキング機能があります。

JestMochaのような包括的な機能を搭載したテストフレームワークの代わりになるものではありませんが、テストスイートを作成するシンプルかつ便利な手段です。Node.js v19での導入以来、大幅に強化され、エンドユーザーのテストとフィードバックにより、Node.js v20では安定版に位置付けられています。

詳細は、マージされたプルリクエストに記載されています。

V8 JavaScriptエンジンが11.3にバージョンアップ

Node.jsを動かすV8 JavaScript エンジンが、Node.js v20でバージョン11.3に更新されました。これにより、パフォーマンスが向上し、新しい言語機能が導入されています。このアップデートによる新機能の一部をご紹介します。

  • String.prototype.isWellFormedtoWellFormed:これらメソッドは、適切な文字列フォーマットを確保するのに有用です。ユーザーによる文字列の入力が正しいUTF-16形式であることを確認し、絵文字に起因するエラーを減らすことができます。
  • ArrayとTypedArrayをコピーにて変更するメソッド:元のデータに影響を与えることなく配列に変更を加えてコピーすることができます。比較や他の目的のために元のデータを保持する必要がある場合に特に便利です。
  • サイズの変更が可能なArrayBufferSharedArrayBuffer:高い柔軟性が確保され、今まで以上に効率的なメモリ割り当てが可能になります。
  • RegExpのv─正規表現への集合操作と構文の付与:正規表現を支える各種機能を追加することができます。
  • WebAssembly末尾再帰:特定のタイプの関数呼び出しを最適化するものです。

これらのアップデートは、Node.jsの開発コミュニティがパフォーマンスと機能性の向上に継続的に取り組んでいる事実を如実に示しています。

同期的なimport.meta.resolve()

Node.js v20では、import.meta.resolve()が導入され、場所を選ばないスクリプトを簡単に書くことができるようになりました。この関数は、ブラウザの動作と同様に同期的に返すので、より効率的な実行が可能です。

ローダリゾルブフックは、非同期関数として定義することができますが、import.meta.resolve()は、非同期リゾルブフックが読み込まれた場合でも、アプリケーションコードに対して同期的に返されます。

import.meta.resolve()の同期動作は、特に大量のデータを扱う場合に、より効率的なコード実行を可能にします。好みに応じて、フックを非同期または同期関数として定義することができます。アプリケーションコードは、非同期のフックが読み込まれているかどうかにかかわらず、依然として同期的に実行されます。

実験的なSingle Executable Applications(SEA)

SEA(Single Executable Applications)は、Node.js v20で導入された新機能であり、アプリケーションをNode.jsバイナリにバンドルし、エンドユーザーが単一の実行ファイルとして配布・実行できるようにするものです。

これはコミュニティからの長年の要望であり、1年間、アプローチに改良が加えられてきました。

Node.js v20では、SEAを構築するには、生のJSファイルを利用するのではなく、JSON設定からNode.jsが準備したBlobを挿入します。

Blobとは、バイナリデータを含むファイルのことで、今回はNode.jsが用意し、バイナリに挿入しています。今回の変更は、共存する複数のリソースをSEAに埋め込むことを可能にしており、新たな用途が開拓されるはずです。

以下はsea-config.jsonファイルの例です。

{ 
      "main": "myscript.js", 
      "output": "sea-prep.blob" 
}

コマンドnode --experimental-sea-config sea-config.jsonで実行すると、Blobがsea-prep.blobファイルに書き込まれ、これをバイナリに挿入することができます。

SEAの機能により、Node.jsインストールの強制を伴わないNode.jsアプリケーションの配布が可能になります。この機能は、OpenJS WorldのJavaScriptLandia Awardsの一環として、Outstanding Contribution from a New Arrival賞を受賞したDarshan Sen氏によるものです。

OpenJS Foundationの一員であるMicrosoftは、ベクター攻撃を減らし、Node.jsのアーキテクチャを強化する方法として、この機能についての試行錯誤を進めています。SEA機能はまだ実験的なものですが、Node.jsコミュニティにおける新たな可能性を予感させるものでしょう。

パフォーマンス

Node.js v20 では、新たに結成されたNode.jsパフォーマンスチームによる注力により、ランタイムが大幅に改善されています。この改善には、URL、fetch()EventTargetなどのランタイムのコアにあたる部分の最適化が含まれています。

注目すべき改良点として、EventTargetの初期化コストが半減し、これを使用するすべてのサブシステムへのアクセスが高速化されたことが挙げられます。さらに、V8 Fast APIコールを利用し、URL.canParse()やタイマーなどのAPIの性能が向上しています。

また、C++で書かれた高速で仕様に準拠したURLパーサーであるAdaのアップデート(バージョン2.0)も、具体的な変更点として注目に値します。

まとめ

今回は、Node.js v20がもたらす主な機能(実験版と安定版)と改善点(V8 JavaScriptエンジン、パフォーマンス、テストランナー、実験的なPermission Model、SEAなど)をご紹介しました。

Node.js v14は2023年4月にEnd-of-Life(サポート終了)となるため、Node.js v18(LTS)またはvNode.js 20(まもなくLTSに)へのアップグレードを開始することが推奨されています。

Node.jsの最新バージョンを試すなら、Kinstaを使ってNode.jsアプリケーションをデプロイするのがおすすめです。初回20ドル分が無料になります。KinstaではすでにNode.js v20をサポートしています。

Node.js v20で最も興味深いと思う機能や改善点は何ですか?他に注目すべき点はございますか?コメント欄でお聞かせください。

Joel Olawanle Kinsta

Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 200 technical articles majorly around JavaScript and it's frameworks.