@@ -10,15 +10,17 @@ This feature allows the distribution of a Node.js application conveniently to a
1010system that does not have Node.js installed.
1111
1212Node.js supports the creation of [single executable applications][] by allowing
13- the injection of a JavaScript file into the `node` binary. During start up, the
14- program checks if anything has been injected. If the script is found, it
15- executes its contents. Otherwise Node.js operates as it normally does.
13+ the injection of a blob prepared by Node.js, which can contain a bundled script,
14+ into the `node` binary. During start up, the program checks if anything has been
15+ injected. If the blob is found, it executes the script in the blob. Otherwise
16+ Node.js operates as it normally does.
1617
17- The single executable application feature only supports running a single
18- embedded [CommonJS][] file .
18+ The single executable application feature currently only supports running a
19+ single embedded script using the [CommonJS][] module system .
1920
20- A bundled JavaScript file can be turned into a single executable application
21- with any tool which can inject resources into the `node` binary.
21+ Users can create a single executable application from their bundled script
22+ with the `node` binary itself and any tool which can inject resources into the
23+ binary.
2224
2325Here are the steps for creating a single executable application using one such
2426tool, [postject][]:
@@ -28,12 +30,24 @@ tool, [postject][]:
2830 $ echo 'console.log(`Hello, ${process.argv[2]}!`);' > hello.js
2931 ```
3032
31- 2. Create a copy of the `node` executable and name it according to your needs:
33+ 2. Create a configuration file building a blob that can be injected into the
34+ single executable application (see
35+ [Generating single executable preparation blobs][] for details):
36+ ```console
37+ $ echo '{ "main": "hello.js", "output": "sea-prep.blob" }' > sea-config.json
38+ ```
39+
40+ 3. Generate the blob to be injected:
41+ ```console
42+ $ node --experimental-sea-config sea-config.json
43+ ```
44+
45+ 4. Create a copy of the `node` executable and name it according to your needs:
3246 ```console
3347 $ cp $(command -v node) hello
3448 ```
3549
36- 3 . Remove the signature of the binary:
50+ 5 . Remove the signature of the binary:
3751
3852 * On macOS:
3953
@@ -50,35 +64,35 @@ tool, [postject][]:
5064 $ signtool remove /s hello
5165 ```
5266
53- 4 . Inject the JavaScript file into the copied binary by running `postject` with
67+ 6 . Inject the blob into the copied binary by running `postject` with
5468 the following options:
5569
5670 * `hello` - The name of the copy of the `node` executable created in step 2.
57- * `NODE_JS_CODE ` - The name of the resource / note / section in the binary
58- where the contents of the JavaScript file will be stored.
59- * `hello.js ` - The name of the JavaScript file created in step 1.
60- * `--sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 ` - The
71+ * `NODE_SEA_BLOB ` - The name of the resource / note / section in the binary
72+ where the contents of the blob will be stored.
73+ * `sea-prep.blob ` - The name of the blob created in step 1.
74+ * `--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 ` - The
6175 [fuse][] used by the Node.js project to detect if a file has been injected.
62- * `--macho-segment-name NODE_JS ` (only needed on macOS) - The name of the
63- segment in the binary where the contents of the JavaScript file will be
76+ * `--macho-segment-name NODE_SEA ` (only needed on macOS) - The name of the
77+ segment in the binary where the contents of the blob will be
6478 stored.
6579
6680 To summarize, here is the required command for each platform:
6781
6882 * On systems other than macOS:
6983 ```console
70- $ npx postject hello NODE_JS_CODE hello.js \
71- --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2
84+ $ npx postject hello NODE_SEA_BLOB sea-prep.blob \
85+ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
7286 ```
7387
7488 * On macOS:
7589 ```console
76- $ npx postject hello NODE_JS_CODE hello.js \
77- --sentinel-fuse NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \
78- --macho-segment-name NODE_JS
90+ $ npx postject hello NODE_SEA_BLOB sea-prep.blob \
91+ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \
92+ --macho-segment-name NODE_SEA
7993 ```
8094
81- 5 . Sign the binary:
95+ 7 . Sign the binary:
8296
8397 * On macOS:
8498
@@ -95,12 +109,33 @@ tool, [postject][]:
95109 $ signtool sign /fd SHA256 hello
96110 ```
97111
98- 6 . Run the binary:
112+ 8 . Run the binary:
99113 ```console
100114 $ ./hello world
101115 Hello, world!
102116 ```
103117
118+ ## Generating single executable preparation blobs
119+
120+ Single executable preparation blobs that are injected into the application can
121+ be generated using the `--experimental-sea-config` flag of the Node.js binary
122+ that will be used to build the single executable. It takes a path to a
123+ configuration file in JSON format. If the path passed to it isn't absolute,
124+ Node.js will use the path relative to the current working directory.
125+
126+ The configuration currently reads the following top-level fields:
127+
128+ ```json
129+ {
130+ "main": "/path/to/bundled/script.js",
131+ "output": "/path/to/write/the/generated/blob.blob"
132+ }
133+ ```
134+
135+ If the paths are not absolute, Node.js will use the path relative to the
136+ current working directory. The version of the Node.js binary used to produce
137+ the blob must be the same as the one to which the blob will be injected.
138+
104139## Notes
105140
106141### `require(id)` in the injected module is not file based
@@ -135,15 +170,16 @@ of [`process.execPath`][].
135170### Single executable application creation process
136171
137172A tool aiming to create a single executable Node.js application must
138- inject the contents of a JavaScript file into:
173+ inject the contents of the blob prepared with `--experimental-sea-config"`
174+ into:
139175
140- * a resource named `NODE_JS_CODE ` if the `node` binary is a [PE][] file
141- * a section named `NODE_JS_CODE ` in the `NODE_JS ` segment if the `node` binary
176+ * a resource named `NODE_SEA_BLOB ` if the `node` binary is a [PE][] file
177+ * a section named `NODE_SEA_BLOB ` in the `NODE_SEA ` segment if the `node` binary
142178 is a [Mach-O][] file
143- * a note named `NODE_JS_CODE ` if the `node` binary is an [ELF][] file
179+ * a note named `NODE_SEA_BLOB ` if the `node` binary is an [ELF][] file
144180
145181Search the binary for the
146- `NODE_JS_FUSE_fce680ab2cc467b6e072b8b5df1996b2 :0` [fuse][] string and flip the
182+ `NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 :0` [fuse][] string and flip the
147183last character to `1` to indicate that a resource has been injected.
148184
149185### Platform support
@@ -165,6 +201,7 @@ to help us document them.
165201
166202[CommonJS]: modules.md#modules-commonjs-modules
167203[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
204+ [Generating single executable preparation blobs]: #generating-single-executable-preparation-blobs
168205[Mach-O]: https://en.wikipedia.org/wiki/Mach-O
169206[PE]: https://en.wikipedia.org/wiki/Portable_Executable
170207[Windows SDK]: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
0 commit comments