🎶

NodeなしでNodeを実行してみた

2023/04/28に公開

TL;DR

Nodeの実行環境を含めたバイナリファイルを出力できる新機能が追加された。
これを使うとNodeなしにNodeのプログラムが実行できるようになる。

新機能「Single executable applications」

NodeJSのv20.0.0から新機能「Single executable applications」が追加されました。

https://nodejs.org/api/single-executable-applications.html#single-executable-applications

CommonJSのコードをバイナリとして出力し、NodeJSが存在しない環境でも実行できるようにしてくれます。この機能は「experimental」で本実装されているわけではないのですが、面白そうなので遊んでみました。

コンパイル

実行はdocker上で行います。imageはbullseye(debian11)を使用しました。

$docker run -it node:20-bullseye-slim bash

公式のドキュメントに従い、以下を実行していきます。
hello.jsを作成

$ echo 'console.log(`Hello, ${process.argv[2]}!`);' > hello.js

コンパイルの設定ファイルを作成

$ echo '{ "main": "hello.js", "output": "sea-prep.blob" }' > sea-config.json

中間ファイルを作成

$ node --experimental-sea-config sea-config.json

nodeをコピー

$ cp $(command -v node) hello

バイナリファイルの結合

$ npx postject hello NODE_SEA_BLOB sea-prep.blob \
    --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2

これで、「hello」ファイルが作成されました。

実行

$ ./hello world
hello world

バイナリを実行できた!!!!

感想

本質的には、Node.jsの実行スクリプトと作成したファイルを一緒にして、単一のバイナリファイルを作成しているような内容になっています。このため、出力されたバイナリファイルをそのまま本番環境に簡単にデプロイできるのが利点です。
例えば、あるバージョンのNode.jsが稼働しているサーバーに、別バージョンのNode.jsのアプリケーションをデプロイする際に利用できます。実行環境に触れずにアプリケーションを実行できるのは大きな利点になることがあると思われます。オンプレミス環境では、このようなケースがまだ存在する可能性があると考えられます。

注意点

自分のローカル環境ではこのコマンドは正常に動作せず、dockerでの動作を確認しています。nodenvでnodeをインストールしている影響かと思われます。
以下のコード実行時に吐かれるhelloファイルがnodeのバイナリファイルではなく、nodenvのシェルスクリプトになっていたのが直接の原因に思われます。

$ cp $(command -v node) hello

Dockerであれば生のNode.jsを利用できるため、本記事ではDockerの上でコマンドを実行しています。

Discussion