社内で NestJS を利用したアプリケーションを構築した後
exe ファイルへの変換と Windows サービスへの登録が必要になりました。
あまり情報がなかったので備忘録的に書き残します。
NestJS だけでなく Node.js を利用したアプリケーション全般に適用できる内容かと思います。
環境
- Windows10 64bit
- Node.js 14.18.1
NestJS とは(一応)
- Node.js Web フレームワーク
- TypeScript の完全なサポート
- ORM(TypeORM, Sequelize)のサポート
- GraphQL のサポート
- Express を超える抽象化
- Angular のアーキテクチャから影響を受けている
- Guards を利用した認証
- WebSockets のサポート
など…Express で後々必要になる機能が最初から用意されており、ドキュメントも充実しています。
なにより初学者は TypeScript の環境作成だけで苦労するので、最初から ts-node を利用した環境が用意されるのはありがたいです。
Module, Controller, Provider(Service)の概念を理解するのに少し苦労しますが Angular を使用したことがある方なら特に問題はないでしょう。
また、とっつきにくかった GraphQL をコードファーストで定義することができ、理解するのにとても役立ちました。
実装とスキーマ定義を同期させながら開発ができることも魅力でした。(一般的にはスキーマファーストで開発するのが主だとは思いますが)
例えば lerna + yarn workspaces + NestJS + NextJS の構成にしてフロント、バックエンドで同じスキーマ定義ファイルを参照し開発を進められます。
概要
簡単な NestJS プロジェクトの作成と exe ファイルへの変換の手順を示します。
プロジェクトの作成
Nest CLI をインストール
npm i -g @nestjs/cli
プロジェクトの作成
nest new <project-name>
パッケージマネージャの指定はお好みで。この時点でサーバーを立てられる状態になっています。
cd <project-name>
npm run start
http://localhost:3000/ に GET リクエストを投げれば Hello World!
が返ってきます。
ビルド
npm run build
dist
フォルダに js ファイルが作成され、以下コマンドで起動できます。
node dist/main
# or "npm run start:prod"
この dist/main.js
をエントリポイントとする exe ファイルの作成を行います。
nexe のインストール
nexe は Node.js アプリケーションを単一 exe ファイルにコンパイルしてくれるツールです。
同様なツールに pkg がありこちらの方が手軽だったのですがアイコンの変更やバージョン情報の書き換えを行うと起動できなくなったのでやめました。
NestJS プロジェクトの devDependencies に追加します。
npm i nexe --save-dev
exe ファイルの作成
以下コマンドを実行します。
./node_modules/.bin/nexe dist/main.js --target windows-x64-14.15.3 --output NestJS.exe
--target
を省略すると Windows にインストールされている Node.js 環境のダウンロードを試みるのですが、https://github.com/nexe/nexe/releases にないバージョンだと
Error: https://github.com/nexe/nexe/releases/download/v3.3.3/windows-x64-14.18.1 is not available, create it using the --build flag
と表示されるので windows-x64-14.15.3
を直接指定しています。
アイコンの作成・変更
アイコンの作成
ImageMagickを使用してsvg
ファイルからico
ファイルを作成します。
とりあえず NestJS アイコンの svg
ファイル を使用して ico
ファイルを作成することにします。
./magick.exe convert icon.svg -transparent white -define icon:auto-resize icon.ico
アイコンの削除
Resource Hacker を使用して初期アイコンを削除します。
./ResourceHacker.exe -open NestJS.exe -save NestJS.exe -action delete -mask ICONGROUP,1,1033
Current Directory:
D:\Node.js\Nest\executable
Commandline:
"D:\Node.js\Nest\executable\ResourceHacker.exe" -open NestJS.exe -save NestJS.exe -action delete -mask ICONGROUP,1,1033
Open : D:\Node.js\Nest\executable\NestJS.exe
Save : D:\Node.js\Nest\executable\NestJS.exe
Deleted: ICONGROUP,1,1033
Success!
アイコンの追加
./ResourceHacker.exe -open NestJS.exe -save NestJS.exe -action addoverwrite -resource <ico FilePath> -mask ICONGROUP,MAINICON,0
Current Directory:
D:\Node.js\Nest\executable
Commandline:
"D:\Node.js\Nest\executable\ResourceHacker.exe" -open NestJS.exe -save NestJS.exe -action addoverwrite -resource icon.ico -mask ICONGROUP,MAINICON,0
Open : D:\Node.js\Nest\executable\NestJS.exe
Save : D:\Node.js\Nest\executable\NestJS.exe
Resource: D:\Node.js\Nest\executable\icon.ico
Added: ICONGROUP,MAINICON,0
Success!
バージョン情報の編集
Rc ファイル作成
以下の内容のファイルを utf-16
で VersionInfo.rc
として保存します。
1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEOS 0x4
FILETYPE 0x1
{
BLOCK "StringFileInfo"
{
BLOCK "041103a4"
{
VALUE "CompanyName", "(C) xxx CORPORATION"
VALUE "FileDescription", "NestJS"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "NestJS.exe"
VALUE "LegalCopyright", "(C) xxx CORPORATION"
VALUE "OriginalFilename", "NestJS.exe"
VALUE "PrivateBuild", "0000"
VALUE "ProductName", "NestJS"
VALUE "ProductVersion", "1.0.0.0"
VALUE "SpecialBuild", "0000"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0411 0x03A4
}
}
Res ファイル作成
./ResourceHacker.exe -open VersionInfo.rc -save VersionInfo.res -action compile
Current Directory:
D:\Node.js\Nest\executable
Commandline:
"D:\Node.js\Nest\executable\ResourceHacker.exe" -open VersionInfo.rc -save VersionInfo.res -action compile
Open : D:\Node.js\Nest\executable\VersionInfo.rc
Save : D:\Node.js\Nest\executable\VersionInfo.res
Compiling: D:\Node.js\Nest\executable\VersionInfo.rc
Success!
初期バージョン情報の削除
./ResourceHacker.exe -open NestJS.exe -save NestJS.exe -action delete -mask VERSIONINFO,1,1033
Current Directory:
D:\Node.js\Nest\executable
Commandline:
"D:\Node.js\Nest\executable\ResourceHacker.exe" -open NestJS.exe -save NestJS.exe -action delete -mask VERSIONINFO,1,1033
Open : D:\Node.js\Nest\executable\NestJS.exe
Save : D:\Node.js\Nest\executable\NestJS.exe
Deleted: VERSIONINFO,1,1033
Success!
バージョン情報の追加
./ResourceHacker.exe -open NestJS.exe -save NestJS.exe -action addoverwrite -resource VersionInfo.res
Current Directory:
D:\Node.js\Nest\executable
Commandline:
"D:\Node.js\Nest\executable\ResourceHacker.exe" -open NestJS.exe -save NestJS.exe -action addoverwrite -resource VersionInfo.res
Open : D:\Node.js\Nest\executable\NestJS.exe
Save : D:\Node.js\Nest\executable\NestJS.exe
Resource: D:\Node.js\Nest\executable\VersionInfo.res
Added: VERSIONINFO,1,1041
これでアイコンとバージョン情報を設定した exe ファイルが作成できました。
もし.env など参照ファイルがあれば exe ファイルと同じ場所に配置してください。
モジュールが見つからないとエラーが表示された場合は、該当のモジュールのみ含む node_module フォルダを作成して exe ファイルと同じ場所に配置してください。
Cannot find module 'xxx' or its corresponding type declarations.
Windows サービスへの登録
NSSM を使用し、作成した exe ファイルを Windows サービスとして登録します。
使い方は公式を参照すれば問題ないと思いますが、管理者権限が必要なことに注意してください。
サービスへの登録はこんな感じ。
./nssm.exe install NestJSService NestJS.exe
./nssm.exe set NestJSService Description "NestJSアプリケーション"
./nssm.exe set NestJSService AppNoConsole 1
./nssm.exe set NestJSService AppRestartDelay 1000
./nssm.exe start NestJSService
Service "NestJSService" installed successfully!
Set parameter "Description" for service "NestJSService".
Set parameter "AppNoConsole" for service "NestJSService".
Set parameter "AppRestartDelay" for service "NestJSService".
NestJSService: START: この操作を正しく終了しました。
サービスから削除する場合はこう。
./nssm.exe stop NestJSService
./nssm.exe remove NestJSService confirm
NestJSService: STOP: この操作を正しく終了しました。
Service "NestJSService" removed successfully!
終わりに
「製品の NestJS のコードを見られないように隠蔽したい」という要望から調査を始めましたが、
かなり特殊な手順になってしましました。nexe のメンテナンスも現在は停滞しているようで、いつまでこの手順が使えるのかは分かりません。(Electronはどうやってるんだろう)
素直にexeファイルへのコンパイルがサポートされている言語で開発した方がよかったと思います。
追記 (2024/01/05)
公式でexe化がサポートされました。まだ実験段階っぽいですが、可能ならこちらを利用した方が良いと思います。
Single executable applications