Skip to content

Commit c43ae7c

Browse files
committed
fixup! src: use JSON configuration and blob content for SEA
1 parent 63988d2 commit c43ae7c

File tree

3 files changed

+63
-17
lines changed

3 files changed

+63
-17
lines changed

doc/api/cli.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,16 @@ added: v16.6.0
588588

589589
Use this flag to disable top-level await in REPL.
590590

591+
### `--experimental-sea-config`
592+
593+
<!-- YAML
594+
added: REPLACEME
595+
-->
596+
597+
Use this flag to generate a blob that can be injected in to the Node.js
598+
binary to produce a [single executable application][]. See the documentation
599+
about [this configuration][`--experimental-sea-config`] for details.
600+
591601
### `--experimental-shadow-realm`
592602

593603
<!-- YAML
@@ -2546,6 +2556,7 @@ done
25462556
[`--cpu-prof-dir`]: #--cpu-prof-dir
25472557
[`--diagnostic-dir`]: #--diagnostic-dirdirectory
25482558
[`--experimental-wasm-modules`]: #--experimental-wasm-modules
2559+
[`--experimental-sea-config`]: single-executable-applications.md#experimental-sea-config`
25492560
[`--heap-prof-dir`]: #--heap-prof-dir
25502561
[`--import`]: #--importmodule
25512562
[`--openssl-config`]: #--openssl-configfile
@@ -2583,6 +2594,7 @@ done
25832594
[scavenge garbage collector]: https://v8.dev/blog/orinoco-parallel-scavenger
25842595
[security warning]: #warning-binding-inspector-to-a-public-ipport-combination-is-insecure
25852596
[semi-space]: https://www.memorymanagement.org/glossary/s.html#semi.space
2597+
[single executable applications]: single-executable-applications.md
25862598
[test reporters]: test.md#test-reporters
25872599
[timezone IDs]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
25882600
[tracking issue for user-land snapshots]: https://github.com/nodejs/node/issues/44014

doc/api/single-executable-applications.md

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ This feature allows the distribution of a Node.js application conveniently to a
1010
system that does not have Node.js installed.
1111

1212
Node.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

2325
Here are the steps for creating a single executable application using one such
2426
tool, [postject][]:
@@ -28,12 +30,23 @@ 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:
35+
```console
36+
$ echo '{ "main": "hello.js", "output": "sea-prep.blob" }' > sea-config.json
37+
```
38+
39+
3. Generate the blob to be injected:
40+
```console
41+
$ node --experimental-sea-config sea-config.json
42+
```
43+
44+
4. Create a copy of the `node` executable and name it according to your needs:
3245
```console
3346
$ cp $(command -v node) hello
3447
```
3548

36-
3. Remove the signature of the binary:
49+
5. Remove the signature of the binary:
3750

3851
* On macOS:
3952

@@ -50,17 +63,17 @@ tool, [postject][]:
5063
$ signtool remove /s hello
5164
```
5265

53-
4. Inject the JavaScript file into the copied binary by running `postject` with
66+
6. Inject the blob into the copied binary by running `postject` with
5467
the following options:
5568

5669
* `hello` - The name of the copy of the `node` executable created in step 2.
5770
* `NODE_SEA_BLOB` - 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.
71+
where the contents of the blob will be stored.
72+
* `hello.js` - The name of the blob created in step 1.
6073
* `--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2` - The
6174
[fuse][] used by the Node.js project to detect if a file has been injected.
6275
* `--macho-segment-name NODE_SEA` (only needed on macOS) - The name of the
63-
segment in the binary where the contents of the JavaScript file will be
76+
segment in the binary where the contents of the blob will be
6477
stored.
6578

6679
To summarize, here is the required command for each platform:
@@ -78,7 +91,7 @@ tool, [postject][]:
7891
--macho-segment-name NODE_SEA
7992
```
8093

81-
5. Sign the binary:
94+
7. Sign the binary:
8295

8396
* On macOS:
8497

@@ -95,12 +108,32 @@ tool, [postject][]:
95108
$ signtool sign /fd SHA256 hello
96109
```
97110

98-
6. Run the binary:
111+
8. Run the binary:
99112
```console
100113
$ ./hello world
101114
Hello, world!
102115
```
103116

117+
<a id="experimental-sea-config"></a>
118+
## Using `--experimental-sea-config` to generate a blob for single executables
119+
120+
`--experimental-sea-config` takes a path to a configuration file in JSON format.
121+
If the path passed to it isn't absolute, Node.js will use the path relative to the
122+
current working directory.
123+
124+
The configuration currently reads the following top-level fields:
125+
126+
```
127+
{
128+
"main": "/path/to/bundled/script.js",
129+
"output": "/path/to/write/the/generated/blob.blob"
130+
}
131+
```
132+
133+
If the paths are not absolute, Node.js will use the path relative to the
134+
current working directory. The version of the Node.js binary used to produce
135+
the blob must be the same as the one to which the blob will be injected.
136+
104137
## Notes
105138

106139
### `require(id)` in the injected module is not file based
@@ -135,7 +168,8 @@ of [`process.execPath`][].
135168
### Single executable application creation process
136169

137170
A tool aiming to create a single executable Node.js application must
138-
inject the contents of a JavaScript file into:
171+
inject the contents of the blob prepared with `--experimental-sea-config"`
172+
into:
139173

140174
* a resource named `NODE_SEA_BLOB` if the `node` binary is a [PE][] file
141175
* a section named `NODE_SEA_BLOB` in the `NODE_SEA` segment if the `node` binary

test/parallel/test-single-executable-application.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const common = require('../common');
66
const fixtures = require('../common/fixtures');
77
const tmpdir = require('../common/tmpdir');
88
const { copyFileSync, readFileSync, writeFileSync, existsSync } = require('fs');
9-
const { execFileSync, exec } = require('child_process');
9+
const { execFileSync } = require('child_process');
1010
const { join } = require('path');
1111
const { strictEqual } = require('assert');
1212
const assert = require('assert');

0 commit comments

Comments
 (0)