TechFeed Experts Night Pick up

Node.jsの2022年を振り返り、Node.jsの未来を見つめてみた ~TechFeed Experts Night#8講演より

本記事は、2022年11月に開催された「TechFeed Experts Night#8 ~ JavaScriptランタイム戦争最前線」のセッション書き起こし記事「Node.jsの2022年を振り返り、Node.jsの未来を見つめてみた by @shisama_」を転載したものです。オリジナルはTechFeedをご覧ください。

「Node.jsの2022年と未来」というタイトルで話します。よろしくお願いします。サイボウズでフロントエンドエンジニアをやっているshisamaです。

自己紹介

今日はNode.jsの18と19の主な変更点を紹介したいと思います。その後は、現在実装中の機能から、いくつかおもしろそうなものをピックアップし、最後に時間があれば(Node.jsの)今後の10年について紹介したいと思います。

Agenda

Node.js v18の主な変更点

今年は4月にNode.js v18がリリースされました。そして、11月にLTSとしてv18.12.0がリリースされました。また、このNode.js v18は3年後の2025年4月30日にメンテナンスが終了する予定です。

Node.js v18

Node.js v18で何が入ったかというと、まずはfetch()関数がフラグがなくても実行可能になりました。これはブラウザのfetch()関数とインタフェースが同じfetch()関数というものです。Node.js v15かv16くらいで実装されていたのですが、そのときはまだ--experimental-fetchというフラグが必要でした。しかし、v18からはフラグがなくても使えるようになっています。

fetch()関数自体は、フロントエンドのコードを書いたことがある人は一度は見たことがあると思いますが、HTTPのリクエストを送信する関数です。ただしNode.jsのfetch()はまだExperimentalな機能なので、使用には注意してください。また、ブラウザと同じようにグローバル関数として使用することができます。なのでrequireとかimportなどを使ってモジュールを読み込む必要はありません。

fetch()関数

次に、テストランナーの追加について話したいと思います。これはJestやVitestのようなテストランナーがNode.js本体にも追加されたという変更です。

ここに書かれているコードのように、node:testというところからテスト関数をimportし、そのテスト関数の第1引数にテストの説明(description)を書き、第2引数にコールバック関数を書き、そのコールバック関数の中にテストコードを書く、および何かを検証するコードを書くという使い方になります。このテストコードをどうやって実行するかというと、node –testという--testオプションを付けたコマンドで実行できます。また、このテスト関数にはオプションを付与することができ、skip などを指定することができます。

テストランナーの追加

次に、V8(JSエンジン)がバージョンアップしました。V8というのはNode.jsの中で使われているJavaScriptエンジンで、Google ChromeやMicrosoftEdgeなどでも使われています。Node.jsではメジャーバージョンが上がるタイミングでV8が更新されますが、Node.js v18ではV8が10.1にバージョンアップされました。これで何ができるようになったかというと、ArrayのfindLastIntl.supportedValuesOf()が使えるようになりました。

V8(JSエンジン)がバージョンアップ

次にHTTP requestTimeout()のデフォルト値が変更されました。server.requestTimeoutのタイムアウト時間のデフォルト値が0から300000ミリ秒(5分)になりました。もともと、サーバを起動するときにrequestTimeoutというものを指定できたのですが、たとえば600000ミリ秒とか300000ミリ秒とか指定することができます。

しかし、これはオプショナルな引数なので省略することもできます。この省略した場合の値が今までは0が指定されていたのですが、Node.js18からは300000ミリ秒になります。なぜ0がダメだったのかというと、0というのはタイムアウトなしという意味になるので、たとえば処理が長いリクエストがあるとその完了を待つことになるんですよね。なので、めちゃくちゃ長い処理がきたときにその待ち時間が発生してしまうので、いいタイミングでタイムアウトにして次のリクエストを捌けるようにすることが、多くのユーザに使ってもらうためには必要ということで「5分」がデフォルト値になりました。0を明示的に指定することも可能ですが、それは推奨されていません。

HTTP requestTimeout()のデフォルト値が変更

次に、Web Streams APIがフラグなしで使えるようになりました。これも、Node.js v17以前から実装されていたのですが、フラグが必要でした。それがv18からはフラグがなくても使えるようになります。

これは、ブラウザのStream APIと同じインターフェースや仕様に沿ったStreamのAPIです。Node.jsからは古くからStreamというAPIがありますが、これとは互換性がありません。また、このWeb Streams APIはまだExperimentalな機能です。

Web Streams API

次に、--watchフラグです。これはWebpackや、Jestでおなじみのwatchモードというものが、Node.js本体にも導入されました。これは何かというと、実行中のプログラムの依存関係にあるモジュールに変更があったら自動的にプロセスを再起動する機能になります。

たとえば、node index.js –watchのように--watchフラグを付けて、index.jsをエントリポイントとして、Nodeのプロセスを起動したとします。そのときに、ここに書かれているようなModule A/ Module B/Module Cという依存関係があった場合、この4つのファイルのどれかに変更があったときにそのNode.jsのプロセスが自動的に再起動されるという機能です。

これまではNode.jsを起動して、開発者が何かコードを修正したら、Node.jsのプロセスを止めて再起動するという作業を手動で行わなければならなかったのですが、watchモードがあることによって、再起動する手間が省けて開発効率が上がることになります。これはv18.11.0から使えます。

--watchフラグ

Node.js v19の変更点

次に、Node.js v19について話をしていきたいと思います。

HTTP(S) Keep Aliveがデフォルトで有効になりました。Keep Aliveというのは、一定時間HTTPの接続を維持するもので、それによってハンドシェイクの回数を減らしてパフォーマンスを良くできるメリットがあります。

このKeep Aliveはこれまでも明示的に指定することが可能でした。このコードのように、{keepAlive: true} と指定してHTTPリクエストを投げることができますが、省略することも可能です。今までは省略するとKeepAliveが有効にならなかったのですが、今回からはデフォルトで有効になるようになっています。

HTTP(S) Keep Aliveがデフォルトで有効に

次に、V8のバージョンアップです。Node.js v19でもV8が10.7にアップデートされました。これによってIntl.Numberformat v3が使えるようになります。どういったものがあるかというと、範囲をフォーマットするformatRange()という関数などが使えるようになっています。

V8(JSエンジン)のバージョンアップ

次に--experimental-specifier-resolution フラグが削除されました。ECMAScript Module(ESM)のコードを書くときに、importのパスは拡張子を書かなくてはいけないのですが、そのパスの中の.jsとかを省略したいとき、これまでは--experimental-specifier-resolution=nodeというフラグを付けて実行することでNode.jsが自動的に拡張子を補完してくれていました。しかし、ESMは仕様上、拡張子の省略が許されてないので、この仕様に沿う形でこのフラグが削除されました。

代替手段としては、Custom Loaderというものが用意されています。拡張子を補完するスクリプトを書いて、Node.jsを実行するときに指定することで、拡張子を補完することができるというものです。

--experimental-specifier-resolutionフラグ削除

Custom Loaderについては、node.js/loaders-testというリポジトリにテストコードがあり、そこにTypeScriptのLoaderや、CoffeeScriptのLoader、拡張子を補完するLoaderなどのテストコードがあるので、そちらをサンプルとして参考にして実装するといいと思います。

node.js/loaders-testにCustom Loaderのサンプル

次に、Web Crypto APIがstableになりました。これはブラウザ(Web)のCrypto APIとインターフェースの互換性があるもので、Node.jsの古いCrypto APIとは互換性はありません。何ができるかというと、暗号化や復号ができるAPIになっています。

Web Crypto APIがstableに

次に、ShadowRealmです。ShadowRealmとはJavaScriptを実行するためのグローバル環境(Realm)を新しく生成するためのAPIです。ここに掲載されているコードを見ていただくと使い方はなんとなくわかるかと思いますが、ShadowRealmのインスタンスを生成してこのrealm.evaluate()という関数を呼び出してその関数の引数に書いた文字列のJavaScriptをRealmの環境内で実行できるというものになります。

これのメリットとして、トップレベルのJavaScriptのコンテキストとは別の実行環境を作ることができるので、お互いのグローバル環境を汚染しあわないという点があります。このコードでいうと、トップレベルのglobalThis.foofooという文字列を入れて、Realmの中ではbarという文字列を入れてても、トップレベルのfooは文字列fooが入ったまま、Realmの中のグローバル変数fooは文字列barが入っているというように、お互い干渉しあわないというメリットがあります。このおかげで、サンドボックス環境を作ることができるようになります。

ShadowRealm自体は現在ECMAScriptの仕様のproposalのstage3という扱いになっています。Node.jsには古くからvm APIというものがあって同じようなことができますが、このShadowRealmを使うことでブラウザと互換性をもてることがポイントになります。しかし、まだExperimentalな機能です。

ShadowRealm

ShadowRealmについては、petamorikenさんのzennの記事が詳しいのでそちらを読んでいただけるといいかなと思います。

ここまで話したNode.js v18とv19の変更点以外にも紹介できなかったものがあるので、興味があればブログも読んでみてください。

Node.js in the Future

ここからは、Node.jsの未来について紹介していきます。まずは現在実装中の機能からおもしろそうなものをピックアップして紹介したいと思います。

ひとつめですが、Node.js v18で追加されたテストランナーにモックの機能が追加されるというもので、プルリクエストはすでにマージされています。なので、近い将来使えるようになるかと思います。

使い方としては、このコードの通りで、node/testからimportし、そこからモック関数を作り、そのモック関数が呼ばれた回数を検証するといったことができます。

ほかにも、検証している関数の中で使っているモジュールなどをモック化したり、そのモックしたものを元に戻すといったAPIもあります。

node:test モックの機能

次に、node:http/staticです。これは静的ファイル用のHTTPサーバを簡単に起動することができるという機能です。このプルリクエストはまだマージされていません。

何ができるかというと、node -r node:http/static /path/to/static –port 8080といったコマンドを実行すると、この/path/to/staticディレクトリの中に入っているHTMLやCSS、JS、画像といった静的なファイルを配信するサーバを起動することができます。なので、サーバのコードを自分で書かなくてもよくなります。すでにnpm packageとしてhttp-serverがあったり、Pythonにもhttp.serverというものがあったりしますが、その代替として使えるかと思います。

node:http/static 静的ファイル用のHTTPサーバ

次にQUICです。QUICのプルリクエストもまだマージされていません。これはどういうものかというと、トランスポートプロトコル、つまり通信プロトコルのひとつです。特徴としては、データ再送の効率化や通信の継続性、内部的にTLSを使用しているので暗号化前提という特徴があります。

HTTP/3と呼ばれるプロトコルは、このQUICを土台に動きます。なので次の図の通り、HTTP/2はTLS、TCPがありますが、HTTP/3は、UDPの上にQUICがあり、そのQUICがTLSを内包していて、その上にHTTPがあるという形になります。

QUIC

QUICやHTTP/3に関しては後藤ゆきさんが書かれたgihyo.jpの記事がすごくわかりやすくて詳しいので、そちらを読んでみてください。

次に、Single Executable Applicationです。これもまだプルリクエストがマージされていません。これは何かというと、複数のJSファイルをひとつにまとめて、さらにWIndowsなどで実行できる実行ファイルに変換するというものです。

Webpackなどで複数のファイルをひとつにまとめるということはできますが、まとめたファイルを実行するにはNode.jsが必要だったり、ほかにもブラウザ上で動かさなければならないという制約があるので、JavaScriptのランタイムが必要です。Node.jsやJavaScriptのランタイムがインストールされていないユーザー向けにアプリケーションを配布したいときに、Node.jsでWindowsやMac向けに実行ファイルを作り、その実行ファイルを配布することで、ユーザーはNode.jsをインストールしなくてもそのアプリケーションを使うことができるという機能です。代替手段としては、vercelがpkgというパッケージを出していて、それを使うと同じようなことができます。

Single Executable Application

次にパーミッションモデルです。これもまだプルリクエストが出ていますが、マージされていないどころかまだドラフトです。

これは何かというと、あとのセッションの日野澤さんがお話しされるDenoのように、実行時にパーミッションを付与することで、ファイルアクセスやプロセスの軌道などを制御し、セキュアな実行を可能にするというものです。どういうことかというと、悪意のあるコードをNode.jsを使って実行してしまったときに、その悪意のあるコードがそのマシンの中のファイルにアクセスして秘密情報を抜き取ってサーバに送るという攻撃ができてしまう可能性があります。しかし、実行するスクリプトはそもそもファイルアクセスが必要ないと思って実行している場合、そのファイルアクセスを禁止して実行することで悪意あるスクリプトが混在していたとしてもファイルにはアクセスできないようにNode.jsが制御することで防ぐ機能です。

パーミッションを付与する方法については、Denoのようにそもそもファイルアクセスを禁止しておいて、許可制のフラグにするのか、禁止形式にするのかどうかも決まっていません。

パーミッションモデル

Node.jsの次の10年に向けて

今後10年についても簡単に紹介したいと思います。

Node.jsの今後10年どうするかという議論が始まっていて、リポジトリがnodejs/next-10というところにあります。その中に優先度の高い機能の一覧と関連リンクが掲載されている文章や、Node.jsのリポジトリ内に優先度の高い機能の概要が掲載されていたりします。

次の10年

これが、nodejs/nodeにあるTecnical Prioritiesという文章です。いくつか項目があり、それぞれ簡単な説明があるので興味があれば読んでみてください。

next-10で優先度の高い機能の概要が掲載

その中に書いてあるものとしてはこのようなものがあります。今回紹介したQUICやパーミッションモデル、Single Executable Applicationsなどもこの中に含まれています。

Tecnical Priorities

その中でもおもしろそうなものをピックアップして紹介します。

まずはSuitable types for end-usersです。これは、メンテナブルで信頼度の高い方をユーザーに提供したいというもので、どうやってやるのかを現在議論中です。

Suitable types for end-users

ほかにも、ECMAScriptの最新の機能をサポートしたいということも議論されています。

Support for features from the latest ECMAScript spec

まとめ

駆け足になってしまいましたが、最後にまとめです。

  • Node.js v18とv19にはWeb互換な機能がいくつかフラグなしで使えるようになったり、stableになったりと、Web互換が強くなりました。
  • テストランナーや--watchモードなど、開発体験を向上させるための機能も追加されました。
  • また、Node.jsの次の10年に向けて議論が開始されています。
  • そして、優先度が高い機能から実装や議論が始まっています。

それから、今月26日にJSConf JPがあるのですが、その中でもNode.jsについてのトークがあるので、興味があったら参加してみてください(注: こちらのイベントは終了しました⁠⁠。

ご清聴、ありがとうございました。

おすすめ記事

記事・ニュース一覧