- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- env 环境变量
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议 2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS 模块
- module/esm ECMAScript 模块
- module/package 包模块
- module/typescript TS 模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
- sqlite 轻型数据库
- stream 流
- stream/iter 可迭代流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
- zlib/iter 可迭代压缩
Node.js v26.0.0 文档
- Node.js v26.0.0
- 目录
-
导航
- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- env 环境变量
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议 2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS 模块
- module/esm ECMAScript 模块
- module/package 包模块
- module/typescript TS 模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- sea 单个可执行应用程序
- sqlite 轻型数据库
- stream 流
- stream/iter 可迭代流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
- zlib/iter 可迭代压缩
- 其他版本
单个可执行应用#>
🌐 Single executable applications
源代码: src/node_sea.cc
此功能允许方便地将 Node.js 应用分发到未安装 Node.js 的系统上。
🌐 This feature allows the distribution of a Node.js application conveniently to a system that does not have Node.js installed.
Node.js 支持通过允许注入由 Node.js 准备的 blob 来创建 单个可执行应用,该 blob 可以包含打包的脚本,注入到 node 二进制文件中。在启动期间,程序会检查是否有任何内容被注入。如果找到了 blob,它会执行 blob 中的脚本。否则,Node.js 会像平常一样运行。
🌐 Node.js supports the creation of single executable applications by allowing
the injection of a blob prepared by Node.js, which can contain a bundled script,
into the node binary. During start up, the program checks if anything has been
injected. If the blob is found, it executes the script in the blob. Otherwise
Node.js operates as it normally does.
单个可执行应用功能支持使用 CommonJS 或 ECMAScript 模块 模块系统运行单个嵌入脚本。
🌐 The single executable application feature supports running a single embedded script using the CommonJS or the ECMAScript Modules module system.
用户可以使用 node 可执行文件本身以及任何可以将资源注入二进制文件的工具,从他们打包的脚本创建单个可执行应用。
🌐 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.
-
创建一个 JavaScript 文件:
echo 'console.log(`Hello, ${process.argv[2]}!`);' > hello.js -
创建一个配置文件,用于构建可以注入到单个可执行应用中的 blob(详情见 生成单个可执行准备 blob):
- 在非 Windows 系统上:
echo '{ "main": "hello.js", "output": "sea" }' > sea-config.json- 在 Windows 上:
echo '{ "main": "hello.js", "output": "sea.exe" }' > sea-config.json.exe扩展名是必要的。 -
生成目标可执行文件:
node --build-sea sea-config.json -
签署二进制文件(仅限 macOS 和 Windows):
- 在 macOS 上:
codesign --sign - hello- 在 Windows 上(可选):
要使其工作,需要提供证书。然而,未签名的二进制文件仍然可以运行。
signtool sign /fd SHA256 hello.exe -
运行二进制文件:
- 在非 Windows 系统上
$ ./hello world Hello, world!- 在 Windows 上
$ .\hello.exe world Hello, world!
使用 --build-sea 生成单个可执行应用#>
🌐 Generating single executable applications with --build-sea
要直接生成单个可执行应用,可以使用 --build-sea 标志。它使用 JSON 格式的配置文件路径。如果传递给它的路径不是绝对路径,Node.js 将使用相对于当前工作目录的路径。
🌐 To generate a single executable application directly, the --build-sea flag can be
used. It takes a path to a configuration file in JSON format. If the path passed to it
isn't absolute, Node.js will use the path relative to the current working directory.
该配置当前读取以下顶层字段:
🌐 The configuration currently reads the following top-level fields:
{
"main": "/path/to/bundled/script.js",
"mainFormat": "commonjs", // Default: "commonjs", options: "commonjs", "module"
"executable": "/path/to/node/binary", // Optional, if not specified, uses the current Node.js binary
"output": "/path/to/write/the/generated/executable",
"disableExperimentalSEAWarning": true, // Default: false
"useSnapshot": false, // Default: false
"useCodeCache": true, // Default: false
"execArgv": ["--no-warnings", "--max-old-space-size=4096"], // Optional
"execArgvExtension": "env", // Default: "env", options: "none", "env", "cli"
"assets": { // Optional
"a.dat": "/path/to/a.dat",
"b.txt": "/path/to/b.txt"
}
}
如果路径不是绝对路径,Node.js 将使用相对于当前工作目录的路径。用于生成二进制数据的 Node.js 二进制版本必须与将注入二进制数据的版本相同。
🌐 If the paths are not absolute, Node.js will use the path relative to the current working directory. The version of the Node.js binary used to produce the blob must be the same as the one to which the blob will be injected.
注意:在生成跨平台 SEA(例如,在 darwin-arm64 上为 linux-x64 生成 SEA)时,必须将 useCodeCache 和 useSnapshot 设置为 false,以避免生成不兼容的可执行文件。由于代码缓存和快照只能在编译它们的平台上加载,当尝试加载在不同平台上构建的代码缓存或快照时,生成的可执行文件可能会在启动时崩溃。
🌐 Note: When generating cross-platform SEAs (e.g., generating a SEA
for linux-x64 on darwin-arm64), useCodeCache and useSnapshot
must be set to false to avoid generating incompatible executables.
Since code cache and snapshots can only be loaded on the same platform
where they are compiled, the generated executable might crash on startup when
trying to load code cache or snapshots built on a different platform.
资源#>
🌐 Assets
用户可以通过在配置中添加键-路径字典作为 assets 字段来包含资源。在构建时,Node.js 会从指定路径读取资源并将它们打包到准备好的 blob 中。在生成的可执行文件中,用户可以使用 sea.getAsset() 和 sea.getAssetAsBlob() API 检索这些资源。
🌐 Users can include assets by adding a key-path dictionary to the configuration
as the assets field. At build time, Node.js would read the assets from the
specified paths and bundle them into the preparation blob. In the generated
executable, users can retrieve the assets using the sea.getAsset() and
sea.getAssetAsBlob() APIs.
{
"main": "/path/to/bundled/script.js",
"output": "/path/to/write/the/generated/executable",
"assets": {
"a.jpg": "/path/to/a.jpg",
"b.txt": "/path/to/b.txt"
}
}
单一可执行应用可以按如下方式访问资源:
🌐 The single-executable application can access the assets as follows:
const { getAsset, getAssetAsBlob, getRawAsset, getAssetKeys } = require('node:sea');
// Get all asset keys.
const keys = getAssetKeys();
console.log(keys); // ['a.jpg', 'b.txt']
// Returns a copy of the data in an ArrayBuffer.
const image = getAsset('a.jpg');
// Returns a string decoded from the asset as UTF8.
const text = getAsset('b.txt', 'utf8');
// Returns a Blob containing the asset.
const blob = getAssetAsBlob('a.jpg');
// Returns an ArrayBuffer containing the raw asset without copying.
const raw = getRawAsset('a.jpg');
有关更多信息,请参阅 sea.getAsset()、sea.getAssetAsBlob()、sea.getRawAsset() 和 sea.getAssetKeys() API 的文档。
🌐 See documentation of the sea.getAsset(), sea.getAssetAsBlob(),
sea.getRawAsset() and sea.getAssetKeys() APIs for more information.
启动快照支持#>
🌐 Startup snapshot support
useSnapshot 字段可用于启用启动快照支持。在这种情况下,当最终可执行文件启动时,main 脚本将不会被执行。相反,它会在构建机器上生成单一可执行应用准备 blob 时运行。生成的准备 blob 将包含一个快照,该快照捕获 main 脚本初始化的状态。最终的可执行文件在注入准备 blob 后,会在运行时反序列化该快照。
🌐 The useSnapshot field can be used to enable startup snapshot support. In this
case, the main script would not be executed when the final executable is launched.
Instead, it would be run when the single executable application preparation
blob is generated on the building machine. The generated preparation blob would
then include a snapshot capturing the states initialized by the main script.
The final executable, with the preparation blob injected, would deserialize
the snapshot at run time.
当 useSnapshot 为 true 时,主脚本必须调用 v8.startupSnapshot.setDeserializeMainFunction() API 来配置在最终可执行文件被用户启动时需要运行的代码。
🌐 When useSnapshot is true, the main script must invoke the
v8.startupSnapshot.setDeserializeMainFunction() API to configure code
that needs to be run when the final executable is launched by the users.
单个可执行应用使用快照的典型模式是:
🌐 The typical pattern for an application to use snapshot in a single executable application is:
- 在构建时,在构建机器上,会运行主脚本以将堆初始化到准备好接收用户输入的状态。该脚本还应使用
v8.startupSnapshot.setDeserializeMainFunction()配置一个主函数。该函数将被编译并序列化到快照中,但在构建时不会被调用。 - 在运行时,主函数将在用户计算机上的反序列化堆之上运行,以处理用户输入并生成输出。
启动快照脚本的一般约束也适用于用于为单一可执行应用构建快照的主脚本,主脚本可以使用 v8.startupSnapshot API 来适应这些约束。详见 关于 Node.js 启动快照支持的文档。
🌐 The general constraints of the startup snapshot scripts also apply to the main
script when it's used to build snapshot for the single executable application,
and the main script can use the v8.startupSnapshot API to adapt to
these constraints. See
documentation about startup snapshot support in Node.js.
V8 代码缓存支持#>
🌐 V8 code cache support
当在配置中将 useCodeCache 设置为 true 时,在生成单个可执行文件准备 Blob 的过程中,Node.js 会编译 main 脚本以生成 V8 代码缓存。生成的代码缓存将成为准备 Blob 的一部分,并注入到最终的可执行文件中。当启动单个可执行应用时,Node.js 不会从头编译 main 脚本,而是使用代码缓存来加快编译速度,然后执行脚本,从而提高启动性能。
🌐 When useCodeCache is set to true in the configuration, during the generation
of the single executable preparation blob, Node.js will compile the main
script to generate the V8 code cache. The generated code cache would be part of
the preparation blob and get injected into the final executable. When the single
executable application is launched, instead of compiling the main script from
scratch, Node.js would use the code cache to speed up the compilation, then
execute the script, which would improve the startup performance.
注意: 当 useCodeCache 为 true 时,import() 不起作用。
执行参数#>
🌐 Execution arguments
execArgv 字段可用于指定 Node.js 特定的参数,这些参数将在单个可执行应用启动时自动应用。这使得应用开发者能够配置 Node.js 运行时选项,而无需终端用户了解这些标志。
🌐 The execArgv field can be used to specify Node.js-specific
arguments that will be automatically applied when the single
executable application starts. This allows application developers
to configure Node.js runtime options without requiring end users
to be aware of these flags.
例如,以下配置:
🌐 For example, the following configuration:
{
"main": "/path/to/bundled/script.js",
"output": "/path/to/write/the/generated/executable",
"execArgv": ["--no-warnings", "--max-old-space-size=2048"]
}
将指示 SEA 使用 --no-warnings 和 --max-old-space-size=2048 标志启动。在可执行文件中嵌入的脚本中,可以使用 process.execArgv 属性访问这些标志:
🌐 will instruct the SEA to be launched with the --no-warnings and
--max-old-space-size=2048 flags. In the scripts embedded in the executable, these flags
can be accessed using the process.execArgv property:
// If the executable is launched with `sea user-arg1 user-arg2`
console.log(process.execArgv);
// Prints: ['--no-warnings', '--max-old-space-size=2048']
console.log(process.argv);
// Prints ['/path/to/sea', 'path/to/sea', 'user-arg1', 'user-arg2']
用户提供的参数位于 process.argv 数组中,从索引 2 开始,就像应用启动时会发生的情况一样:
🌐 The user-provided arguments are in the process.argv array starting from index 2,
similar to what would happen if the application is started with:
node --no-warnings --max-old-space-size=2048 /path/to/bundled/script.js user-arg1 user-arg2
执行参数扩展#>
🌐 Execution argument extension
execArgvExtension 字段控制如何提供除 execArgv 字段中指定的之外的额外执行参数。它接受以下三个字符串值之一:
🌐 The execArgvExtension field controls how additional execution arguments can be
provided beyond those specified in the execArgv field. It accepts one of three string values:
"none":不允许扩展。只会使用execArgv中指定的参数,NODE_OPTIONS环境变量将被忽略。"env":(默认)NODE_OPTIONS环境变量可以扩展执行参数。这是默认行为,以保持向后兼容性。"cli":可执行文件可以使用--node-options="--flag1 --flag2"启动,这些标志将作为 Node.js 的执行参数解析,而不会传递给用户脚本。这允许使用NODE_OPTIONS环境变量不支持的参数。
例如,使用 "execArgvExtension": "cli" 时:
🌐 For example, with "execArgvExtension": "cli":
{
"main": "/path/to/bundled/script.js",
"output": "/path/to/write/the/generated/executable",
"execArgv": ["--no-warnings"],
"execArgvExtension": "cli"
}
可执行文件可以这样启动:
🌐 The executable can be launched as:
./my-sea --node-options="--trace-exit" user-arg1 user-arg2
这相当于运行:
🌐 This would be equivalent to running:
node --no-warnings --trace-exit /path/to/bundled/script.js user-arg1 user-arg2
单个可执行应用 API#>
🌐 Single-executable application API
node:sea 内置模块允许从嵌入在可执行文件中的 JavaScript 主脚本与单一可执行应用进行交互。
🌐 The node:sea builtin allows interaction with the single-executable application
from the JavaScript main script embedded into the executable.
sea.isSea()#>
- 返回:<boolean> 该脚本是否在单个可执行应用内运行。
sea.getAsset(key[, encoding])#>
此方法可用于检索在构建时配置为打包到单一可执行应用中的资源。找不到匹配的资源时会抛出错误。
🌐 This method can be used to retrieve the assets configured to be bundled into the single-executable application at build time. An error is thrown when no matching asset can be found.
key<string> 在单个可执行应用配置中,由assets字段指定的字典中该资源的键。encoding<string> 如果指定,该资源将被解码为字符串。TextDecoder支持的任何编码都可接受。如果未指定,则会返回一个包含资源副本的ArrayBuffer。- 返回:<string> | <ArrayBuffer>
sea.getAssetAsBlob(key[, options])#>
类似于 sea.getAsset(),但返回结果为 <Blob>。当找不到匹配的资源时会抛出错误。
🌐 Similar to sea.getAsset(), but returns the result in a <Blob>.
An error is thrown when no matching asset can be found.
key<string> 在单个可执行应用配置中,由assets字段指定的字典中该资源的键。options<Object>type<string> Blob 的可选 MIME 类型。
- 返回:<Blob>
sea.getRawAsset(key)#>
此方法可用于检索在构建时配置为打包到单一可执行应用中的资源。找不到匹配的资源时会抛出错误。
🌐 This method can be used to retrieve the assets configured to be bundled into the single-executable application at build time. An error is thrown when no matching asset can be found.
与 sea.getAsset() 或 sea.getAssetAsBlob() 不同,这个方法不会返回副本。相反,它返回打包在可执行文件中的原始资源。
🌐 Unlike sea.getAsset() or sea.getAssetAsBlob(), this method does not
return a copy. Instead, it returns the raw asset bundled inside the executable.
目前,用户应避免写入返回的数组缓冲区。如果注入的部分未标记为可写或未正确对齐,写入返回的数组缓冲区很可能会导致崩溃。
🌐 For now, users should avoid writing to the returned array buffer. If the injected section is not marked as writable or not aligned properly, writes to the returned array buffer is likely to result in a crash.
key<string> 在单个可执行应用配置中,由assets字段指定的字典中该资源的键。- 返回:<ArrayBuffer>
sea.getAssetKeys()#>
- 返回 <string[]> 一个包含嵌入在可执行文件中的所有资源键的数组。如果没有嵌入资源,则返回一个空数组。
此方法可用于获取嵌入到单个可执行应用中的所有资源键的数组。当不在单个可执行应用中运行时,会抛出错误。
🌐 This method can be used to retrieve an array of all the keys of assets embedded into the single-executable application. An error is thrown when not running inside a single-executable application.
在注入的主脚本中#>
🌐 In the injected main script
注入的主脚本的模块格式#>
🌐 Module format of the injected main script
要指定 Node.js 应该如何解释注入的主脚本,请在单一可执行应用配置中使用 mainFormat 字段。接受的值有:
🌐 To specify how Node.js should interpret the injected main script, use the
mainFormat field in the single-executable application configuration.
The accepted values are:
"commonjs":注入的主脚本被视为一个 CommonJS 模块。"module":注入的主脚本被视为 ECMAScript 模块。
如果未指定 mainFormat 字段,则默认为 "commonjs"。
🌐 If the mainFormat field is not specified, it defaults to "commonjs".
目前,"mainFormat": "module" 不能与 "useSnapshot" 一起使用。
🌐 Currently, "mainFormat": "module" cannot be used together with "useSnapshot".
在注入的主脚本中加载模块#>
🌐 Module loading in the injected main script
在注入的主脚本中,模块加载不会从文件系统读取。默认情况下,require() 和 import 语句只能加载内置模块。尝试加载只能在文件系统中找到的模块会抛出错误。
🌐 In the injected main script, module loading does not read from the file system.
By default, both require() and import statements would only be able to load
the built-in modules. Attempting to load a module that can only be found in the
file system will throw an error.
用户可以将他们的应用打包成一个独立的 JavaScript 文件,以注入到可执行文件中。这也确保了更确定的依赖图。
🌐 Users can bundle their application into a standalone JavaScript file to inject into the executable. This also ensures a more deterministic dependency graph.
为了在注入的主脚本中从文件系统加载模块,用户可以创建一个 require 函数,该函数可以使用 module.createRequire() 从文件系统加载模块。例如,在 CommonJS 入口点中:
🌐 To load modules from the file system in the injected main script, users can
create a require function that can load from the file system using
module.createRequire(). For example, in a CommonJS entry point:
const { createRequire } = require('node:module');
require = createRequire(__filename);
require() 在注入的主脚本中#>
🌐 require() in the injected main script
注入主脚本中的 require() 与未注入的模块可用的 require() 不同。目前,它没有非注入 require() 的任何属性,除了 require.main。
__filename 和 module.filename 在注入的主脚本中#>
🌐 __filename and module.filename in the injected main script
注入的主脚本中 __filename 和 module.filename 的值等于 process.execPath。
🌐 The values of __filename and module.filename in the injected main script
are equal to process.execPath.
注入的主脚本中的 __dirname#>
🌐 __dirname in the injected main script
注入的主脚本中 __dirname 的值等于 process.execPath 的目录名称。
🌐 The value of __dirname in the injected main script is equal to the directory
name of process.execPath.
import.meta 在注入的主脚本中#>
🌐 import.meta in the injected main script
在使用 "mainFormat": "module" 时,import.meta 可在注入的主脚本中使用,具有以下属性:
🌐 When using "mainFormat": "module", import.meta is available in the
injected main script with the following properties:
import.meta.url:一个对应于process.execPath的file:URL。import.meta.filename:等于process.execPath。import.meta.dirname:process.execPath的目录名称。import.meta.main:true.
import.meta.resolve 当前不受支持。
import() 在注入的主脚本中#>
🌐 import() in the injected main script
在使用 "mainFormat": "module" 时,可以使用 import() 来动态加载内置模块。尝试使用 import() 从文件系统加载模块会抛出错误。
🌐 When using "mainFormat": "module", import() can be used to dynamically
load built-in modules. Attempting to use import() to load modules from
the file system will throw an error.
在注入的主脚本中使用本地插件#>
🌐 Using native addons in the injected main script
本地插件可以通过在用于生成单文件可执行应用准备块的配置文件的 assets 字段中指定它们,作为资源打包到单文件可执行应用中。然后,可以在注入的主脚本中通过将资源写入临时文件并使用 process.dlopen() 加载它来加载该插件。
🌐 Native addons can be bundled as assets into the single-executable application
by specifying them in the assets field of the configuration file used to
generate the single-executable application preparation blob.
The addon can then be loaded in the injected main script by writing the asset
to a temporary file and loading it with process.dlopen().
{
"main": "/path/to/bundled/script.js",
"output": "/path/to/write/the/generated/executable",
"assets": {
"myaddon.node": "/path/to/myaddon/build/Release/myaddon.node"
}
}
// script.js
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { getRawAsset } = require('node:sea');
const addonPath = path.join(os.tmpdir(), 'myaddon.node');
fs.writeFileSync(addonPath, new Uint8Array(getRawAsset('myaddon.node')));
const myaddon = { exports: {} };
process.dlopen(myaddon, addonPath);
console.log(myaddon.exports);
fs.rmSync(addonPath);
已知警告:如果单文件可执行应用是由在 Linux arm64 Docker 容器中运行的 postject 生成的,生成的 ELF 二进制文件没有用于加载插件的正确哈希表 和将在 process.dlopen() 上崩溃。请在其他平台上构建单文件可执行应用,或至少在非容器的 Linux arm64 环境中构建,以规避此问题。
🌐 Known caveat: if the single-executable application is produced by postject running on a Linux arm64 docker container,
the produced ELF binary does not have the correct hash table to load the addons and
will crash on process.dlopen(). Build the single-executable application on other platforms, or at least on
a non-container Linux arm64 environment to work around this issue.
注意事项#>
🌐 Notes
单个可执行应用创建过程#>
🌐 Single executable application creation process
这里记录的过程可能会发生变化。
🌐 The process documented here is subject to change.
1. 生成单个可执行准备块#>
🌐 1. Generating single executable preparation blobs
为了构建一个单一的可执行应用,Node.js 首先会生成一个包含运行打包脚本所需的所有信息的二进制大块。当使用 --build-sea 时,这一步会在内部完成,同时进行注入。
🌐 To build a single executable application, Node.js would first generate a blob
that contains all the necessary information to run the bundled script.
When using --build-sea, this step is done internally along with the injection.
将准备好的数据块转储到磁盘#>
🌐 Dumping the preparation blob to disk
在引入 --build-sea 之前,引入了一个较旧的工作流程,用于将准备好的 blob 写入磁盘,以便由外部工具注入。这仍然可以用于验证目的。
🌐 Before --build-sea was introduced, an older workflow was introduced to write the
preparation blob to disk for injection by external tools. This can still
be used for verification purposes.
要将准备好的 blob 转储到磁盘以进行验证,请使用 --experimental-sea-config。
这将写入一个文件,可以使用像 后射 这样的工具注入到 Node.js 二进制文件中。
🌐 To dump the preparation blob to disk for verification, use --experimental-sea-config.
This writes a file that can be injected into a Node.js binary using tools like postject.
该配置与 --build-sea 类似,只是 output 字段指定了写入生成的二进制文件的路径,而不是最终可执行文件的路径。
🌐 The configuration is similar to that of --build-sea, except that the
output field specifies the path to write the generated blob file instead of
the final executable.
{
"main": "/path/to/bundled/script.js",
// Instead of the final executable, this is the path to write the blob.
"output": "/path/to/write/the/generated/blob.blob"
}
2. 将准备的程序块注入 node 二进制文件#>
🌐 2. Injecting the preparation blob into the node binary
为了完成单一可执行应用的创建,生成的 blob 需要注入到 node 二进制文件的副本中,如下所述。
🌐 To complete the creation of a single executable application, the generated blob
needs to be injected into a copy of the node binary, as documented below.
在使用 --build-sea 时,这一步会在内部与 blob 生成一起完成。
🌐 When using --build-sea, this step is done internally along with the blob generation.
- 如果
node二进制文件是 体育 文件,则该 blob 应作为名为NODE_SEA_BLOB的资源注入。 - 如果
node二进制文件是一个 Mach-O 文件,则应该将 blob 注入到NODE_SEA段中名为NODE_SEA_BLOB的节中。 - 如果
node二进制文件是 精灵 文件,则该 blob 应作为名为NODE_SEA_BLOB的注释注入。
然后,SEA 构建过程会在二进制文件中搜索 NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0 保险丝 字符串,并将最后一个字符翻转为 1,以表示已注入资源。
🌐 Then, the SEA building process searches the binary for the
NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0 fuse string and flip the
last character to 1 to indicate that a resource has been injected.
手动注入配制剂团#>
🌐 Injecting the preparation blob manually
在引入 --build-sea 之前,引入了一个较早的工作流,以允许外部工具将生成的 blob 注入到 node 二进制文件的副本中。
🌐 Before --build-sea was introduced, an older workflow was introduced to allow
external tools to inject the generated blob into a copy of the node binary.
例如,对于 后射:
🌐 For example, with postject:
-
创建一个
node可执行文件的副本,并根据你的需要命名:- 在非 Windows 系统上:
cp $(command -v node) hello- 在 Windows 上:
node -e "require('fs').copyFileSync(process.execPath, 'hello.exe')".exe扩展名是必要的。 -
移除二进制文件的签名(仅限 macOS 和 Windows):
- 在 macOS 上:
codesign --remove-signature hello- 在 Windows 上(可选):
签名工具 可以从已安装的 Windows SDK 使用。如果跳过此步骤,请忽略来自 postject 的任何与签名相关的警告。
signtool remove /s hello.exe -
通过运行
postject并使用以下选项,将二进制副本注入 blob:hello/hello.exe- 在步骤4中创建的node可执行文件副本的名称。NODE_SEA_BLOB- 在二进制文件中用于存储该 blob 内容的资源/注释/部分的名称。sea-prep.blob- 步骤1中创建的 blob 的名称。--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2- Node.js 项目用来检测文件是否被注入的 保险丝。--macho-segment-name NODE_SEA(仅在 macOS 上需要)- 二进制中将存储 blob 内容的段的名称。
总而言之,这是每个平台所需的命令:
-
在 Linux 上:
npx postject hello NODE_SEA_BLOB sea-prep.blob \ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 -
在 Windows 上 - PowerShell:
npx postject hello.exe NODE_SEA_BLOB sea-prep.blob ` --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 -
在 Windows 上 - 命令提示符:
npx postject hello.exe NODE_SEA_BLOB sea-prep.blob ^ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 -
在 macOS 上:
npx postject hello NODE_SEA_BLOB sea-prep.blob \ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \ --macho-segment-name NODE_SEA
平台支持#>
🌐 Platform support
单一可执行文件支持仅在以下平台上通过 CI 定期测试:
🌐 Single-executable support is tested regularly on CI only on the following platforms:
- Windows
- macOS
- Linux(除 Alpine 之外的所有发行版 由 Node.js 支持,以及除 s390x 之外的所有架构 由 Node.js 支持)
这是由于缺乏更好的工具来生成可用于在其他平台上测试此功能的单一可执行文件。
🌐 This is due to a lack of better tools to generate single-executables that can be used to test this feature on other platforms.
欢迎提供其他资源注入工具/工作流程的建议。请在 https://github.com/nodejs/single-executable/discussions 发起讨论,以帮助我们记录它们。