Node.js SEAで単一実行可能.exeファイルを生成する
Node.jsのプログラムをWindows上で実行できるように.exeファイルに変換する方法は色々ありますが、開発終了しているものが多いです。Node.jsには、SEA(Single Executable Applictions)という機能があり、Node.jsがインストールされていない環境でもNode.js上で動くアプリケーションを簡単に配布できるようになります。
ただし、macOS上で.exeファイルを生成するには仮想環境のWindows上で実行する必要があります。
ビルドの手順
npm i -D esbuild postject
まずは、必要なnpmモジュールをインストールしましょう。esbuild
はES modulesをCommonJS形式に変換するバンドラーで、postject
は.exeにBlobを注入するために使われます。
import process from 'node:process'
import {setTimeout} from 'node:timers/promises'
// .exeファイル実行時に自動で閉じてしまうのを防ぐ
process.stdin.resume()
!(async() => {
await setTimeout(1000)
console.log(process.version)
})()
簡単にNode.jsのバージョンを出力するJavaScriptファイルを作成してみます。Node.js v24時点でCommonJS形式のみの対応なので、esbuildで変換する際、Top Level Awaitでエラーが起きないようにasync IIFE(asyncの即時関数)で囲んでおきます。
npx esbuild src/index.js --outfile=dist/index.cjs --bundle --platform=node --format=cjs --minify
esbuild
コマンドでES modulesからCommonJS形式に変換します。
{
"main": "dist/index.cjs",
"output": "dist/index.blob",
"disableExperimentalSEAWarning": true
}
Node.jsプログラムからBlobを生成するための設定ファイルを作成します。main
フィールドにはCommonJS形式に変換されたファイルのパス、output
フィールドには生成先のファイルパスを書いておきます。disableExperimentalSEAWarning
は.exeファイル実行の際の警告を非表示にしてくれます。
node --experimental-sea-config sea-config.json
コマンドを実行して、注入するBlobを生成します。
node -e "fs.copyFileSync(process.execPath, 'dist/index.exe')"
Node.jsが含まれた.exeファイルを生成します。この.exeファイルを実行しても、Node.jsがバンドルされているだけなのでまだ何も実行されません。
npx postject dist/index.exe NODE_SEA_BLOB dist/index.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
.exeファイルにBlobを注入します。これで.exeファイル起動時にNode.jsプログラムが実行されるようになります。
npm-scriptsで一元化
npm-scriptsを使って1つのコマンドで生成できるようにしていきます。
npm i -D npm-run-all2
npm-run-all2
をインストールして、コマンドを直列や並列で実行できるようにします。
{
...
+ "scripts": {
+ "build": "npm-run-all build:*",
+ "build:bundle": "esbuild src/index.js --outfile=dist/index.cjs --bundle --platform=node --format=cjs --minify",
+ "build:blob": "node --experimental-sea-config sea-config.json",
+ "build:exe": "node -e \"fs.copyFileSync(process.execPath, 'dist/index.exe')\"",
+ "build:inject": "postject dist/index.exe NODE_SEA_BLOB dist/index.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2",
+ "build:clean": "run-p build:clean:*",
+ "build:clean:blob": "node -e \"fs.rmSync('dist/index.blob', {recursive: true})\"",
+ "build:clean:cjs": "node -e \"fs.rmSync('dist/index.cjs', {recursive: true})\""
+ }
}
package.json
にnpm-scriptsを追加します。これで、npm run build
とコマンドを打つだけで.exeファイルが生成されるようになります。
GitHubに今回の最小構成のプロジェクトを公開しているので参考にしてみてください。
Discussion