pkgでNode.jsスクリプトを実行バイナリにする
Rubyスクリプトをcross-platformなstandaloneバイナリにしようとして諦めた - あーありがち(2019-10-03)
で Ruby を諦めたので、次は Node.js.
zeit/pkgですごく簡単にできる
zeit/pkg: Package your Node.js project into an executable
試したのは 4.4.0
基本的な使い方は
pkg [-t target] [-o output] <source>
で、必要な stub を自動でダウンロードして依存モジュールも含めて -o で指定した名前の実行バイナリを生成してくれる。
ネットワークが弱い場合はこのダウンロードでイライラするけど、そこが済めば1実にあっけなく終わる。本当にあっという間。
ただし、通常ではできあがったバイナリはすごくでかい。どれだけ簡単なコードでも 30MB 以上になってしまう。もしかしたら V8 の option でサイズの削減はできるかもしれないけど、そこはまだ試していない。
でもcross-compileはできない
README には cross-compile できると書かれているんだけど、これは間違いだった。macOS 上で Windows ターゲットのコンパイルを試してみて、確かにコンパイル自体は動作はするんだけど、実際にできあがったバイナリを実行することはできなかった。Windows 上で Windows ターゲットのバイナリを作ったら普通に実行できたので、CI のプラットフォームを Windows にして pkg を実行する形でないとダメっぽい。
続きは GitHub Actionsでpkgを使ったNode.js実行バイナリをWindowsを含めてmatrixビルドする - あーありがち(2019-10-05)
localのファイルのrequireはそのままでは相対パスを解決できない
バイナリはできるけど実行すると以下のように怒られる。
Error: Cannot find module 'xxx
Require stack:
- /snapshot/src/index.js
1) If you want to compile the package/file into executable, please pay attention to compilation warnings and specify a literal in 'require' call. 2) If you don't want to compile the package/file into executable and want to 'require' it from filesystem (likely plugin), specify an absolute path in 'require' call using process.cwd() or process.execPath.
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:608:15)
at Function.Module._resolveFilename (pkg/prelude/bootstrap.js:1287:46)
at Function.Module._load (internal/modules/cjs/loader.js:524:27)
at Module.require (internal/modules/cjs/loader.js:664:19)
at Module.require (pkg/prelude/bootstrap.js:1166:31)
at require (internal/modules/cjs/helpers.js:16:16)
at Object.<anonymous> (/snapshot/src/index.js:0:0)
at Module._compile (pkg/prelude/bootstrap.js:1261:22)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:768:10)
at Module.load (internal/modules/cjs/loader.js:626:32)
解決策としては process.cwd() とか process.execPath ではなく、
https://github.com/zeit/pkg#config
を参考に、package.json に
"pkg": {
"scripts": "src/**/*.js"
}
みたいなやつを足しておく必要あり。
環境変数を指定しておくとダウンロードした stub をキャッシュしてくれる ↩