As of node.js 18.16.0 you can now generate single executable applications
Users can create a single executable application from their bundled script with the node binary itself and any tool which can inject resources into the binary.
Here are the steps for creating a single executable application using one such tool, postject:
- Create a JavaScript file:
echo 'console.log(`Hello, ${process.argv[2]}!`);' > hello.js
- Create a configuration file building a blob that can be injected into the single executable application (see Generating single executable preparation blobs for details):
echo '{ "main": "hello.js", "output": "sea-prep.blob" }' > sea-config.json
- Generate the blob to be injected:
node --experimental-sea-config sea-config.json
- Create a copy of the node executable and name it according to your needs:
On systems other than Windows:
cp $(command -v node) hello
On Windows:
Using PowerShell:
cp (Get-Command node).Source hello.exe
Using Command Prompt:
for /F "tokens=*" %n IN ('where.exe node') DO @(copy "%n" hello.exe)
The .exe extension is necessary.
- Remove the signature of the binary (macOS and Windows only):
codesign --remove-signature hello
signtool can be used from the installed Windows SDK. If this step is skipped, ignore any signature-related warning from postject.
signtool remove /s hello.exe
- Inject the blob into the copied binary by running postject with the following options:
hello
/ hello.exe
- The name of the copy of the node executable created in step 4.
NODE_SEA_BLOB
- The name of the resource / note / section in the binary where the contents of the blob will be stored.
sea-prep.blob
- The name of the blob created in step 1.
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
- The fuse used by the Node.js project to detect if a file has been injected.
--macho-segment-name NODE_SEA
(only needed on macOS) - The name of the segment in the binary where the contents of the blob will be stored.
To summarize, here is the required command for each platform:
npx postject hello NODE_SEA_BLOB sea-prep.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
npx postject hello.exe NODE_SEA_BLOB sea-prep.blob `
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
- On Windows - Command Prompt:
npx postject hello.exe NODE_SEA_BLOB sea-prep.blob ^
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
npx postject hello NODE_SEA_BLOB sea-prep.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \
--macho-segment-name NODE_SEA
- Sign the binary (macOS and Windows only):
codesign --sign - hello
A certificate needs to be present for this to work. However, the unsigned binary would still be runnable.
signtool sign /fd SHA256 hello.exe
- Run the binary:
- On systems other than Windows
$ ./hello world
Hello, world!
$ .\hello.exe world
Hello, world!