- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- 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 单个可执行应用程序
Node.js v22.12.0 文档
- Node.js v22.12.0
- 目录
-
导航
- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- 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 单个可执行应用程序
- 其他版本
单个可执行应用#
¥Single executable applications
¥Stability: 1.1 - Active development
源代码: 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 注入 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 模块系统运行单个嵌入式脚本。
¥The single executable application feature currently only supports running a single embedded script using the CommonJS 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.
以下是使用此类工具 postject 创建单个可执行应用的步骤:
¥Here are the steps for creating a single executable application using one such tool, postject:
-
创建一个 JavaScript 文件:
¥Create a JavaScript file:
echo 'console.log(`Hello, ${process.argv[2]}!`);' > hello.js
-
创建一个配置文件,构建一个可以注入单个可执行应用的 blob(有关详细信息,请参阅 生成单个可执行准备 blob):
¥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
-
生成要注入的 blob:
¥Generate the blob to be injected:
node --experimental-sea-config sea-config.json
-
创建
node
可执行文件的副本并根据需要命名:¥Create a copy of the
node
executable and name it according to your needs:-
在 Windows 以外的系统上:
¥On systems other than Windows:
cp $(command -v node) hello
-
在 Windows 上:
¥On Windows:
node -e "require('fs').copyFileSync(process.execPath, 'hello.exe')"
.exe
扩展名是必需的。¥The
.exe
extension is necessary. -
-
删除二进制文件的签名(仅限 macOS 和 Windows):
¥Remove the signature of the binary (macOS and Windows only):
-
在 macOS 上:
¥On macOS:
codesign --remove-signature hello
-
在 Windows 上(可选):
¥On Windows (optional):
signtool 可以从已安装的 Windows SDK 使用。如果跳过此步骤,请忽略来自 postject 的任何与签名相关的警告。
¥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
-
-
通过使用以下选项运行
postject
将 blob 注入到复制的二进制文件中:¥Inject the blob into the copied binary by running
postject
with the following options:-
hello
/hello.exe
- 在步骤 4 中创建的node
可执行文件副本的名称。¥
hello
/hello.exe
- The name of the copy of thenode
executable created in step 4. -
NODE_SEA_BLOB
- 二进制文件中将存储 blob 内容的资源/注释/部分的名称。¥
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
- 在步骤 1 中创建的 blob 的名称。¥
sea-prep.blob
- The name of the blob created in step 1. -
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
- Node.js 项目用来检测文件是否被注入的 fuse。¥
--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
(仅在 macOS 上需要) - 二进制文件中将存储 blob 内容的段的名称。¥
--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:
-
在 Linux 上:
¥On Linux:
npx postject hello NODE_SEA_BLOB sea-prep.blob \ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
-
在 Windows 上 - 电源外壳:
¥On Windows - PowerShell:
npx postject hello.exe NODE_SEA_BLOB sea-prep.blob ` --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
-
在 Windows 上 - 命令提示符:
¥On Windows - Command Prompt:
npx postject hello.exe NODE_SEA_BLOB sea-prep.blob ^ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
-
在 macOS 上:
¥On macOS:
npx postject hello NODE_SEA_BLOB sea-prep.blob \ --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \ --macho-segment-name NODE_SEA
-
-
签署二进制文件(仅限 macOS 和 Windows):
¥Sign the binary (macOS and Windows only):
-
在 macOS 上:
¥On macOS:
codesign --sign - hello
-
在 Windows 上(可选):
¥On Windows (optional):
需要有证书才能工作。但是,未签名的二进制文件仍然可以运行。
¥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:
-
在 Windows 以外的系统上
¥On systems other than Windows
$ ./hello world Hello, world!
-
在 Windows 上
¥On Windows
$ .\hello.exe world Hello, world!
-
生成单个可执行准备 blob#
¥Generating single executable preparation blobs
可以使用将用于构建单个可执行文件的 Node.js 二进制文件的 --experimental-sea-config
标志生成注入到应用中的单个可执行文件准备 blob。它采用 JSON 格式的配置文件路径。如果传递给它的路径不是绝对路径,Node.js 将使用相对于当前工作目录的路径。
¥Single executable preparation blobs that are injected into the application can
be generated using the --experimental-sea-config
flag of the Node.js binary
that will be used to build the single executable. 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",
"output": "/path/to/write/the/generated/blob.blob",
"disableExperimentalSEAWarning": true, // Default: false
"useSnapshot": false, // Default: false
"useCodeCache": true, // Default: false
"assets": { // Optional
"a.dat": "/path/to/a.dat",
"b.txt": "/path/to/b.txt"
}
}
如果路径不是绝对路径,Node.js 将使用相对于当前工作目录的路径。用于生成 blob 的 Node.js 二进制文件的版本必须与将注入 blob 的版本相同。
¥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/blob.blob",
"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 } = require('node:sea');
// 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()
API 的文档。
¥See documentation of the sea.getAsset()
, sea.getAssetAsBlob()
and sea.getRawAsset()
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 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()
配置一个 main 函数。该函数将被编译并序列化到快照中,但不会在构建时调用。¥At build time, on the building machine, the main script is run to initialize the heap to a state that's ready to take user input. The script should also configure a main function with
v8.startupSnapshot.setDeserializeMainFunction()
. This function will be compiled and serialized into the snapshot, but not invoked at build time. -
在运行时,主函数将在用户计算机上的反序列化堆之上运行,以处理用户输入并生成输出。
¥At run time, the main function will be run on top of the deserialized heap on the user machine to process user input and generate output.
当用于为单个可执行应用构建快照时,启动快照脚本的一般约束也适用于主脚本,并且主脚本可以使用 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()
不起作用。
¥Note: import()
does not work when useCodeCache
is true
.
在注入的主脚本中#
¥In the injected main script
单个可执行应用 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> 该脚本是否在单个可执行应用内运行。
¥Returns: <boolean> Whether this script is running inside a single-executable application.
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
字段指定的字典中资源的键。¥
key
<string> the key for the asset in the dictionary specified by theassets
field in the single-executable application configuration. -
encoding
<string> 如果指定,资源将被解码为字符串。接受TextDecoder
支持的任何编码。如果未指定,则将返回包含资源副本的ArrayBuffer
。¥
encoding
<string> If specified, the asset will be decoded as a string. Any encoding supported by theTextDecoder
is accepted. If unspecified, anArrayBuffer
containing a copy of the asset would be returned instead. -
返回:<string> | <ArrayBuffer>
¥Returns: <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
字段指定的字典中资源的键。¥
key
<string> the key for the asset in the dictionary specified by theassets
field in the single-executable application configuration. -
options
<Object> -
返回:<Blob>
¥Returns: <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
字段指定的字典中资源的键。¥
key
<string> the key for the asset in the dictionary specified by theassets
field in the single-executable application configuration. -
返回:<string> | <ArrayBuffer>
¥Returns: <string> | <ArrayBuffer>
注入的主脚本中的 require(id)
不是基于文件的#
¥require(id)
in the injected main script is not file based
注入的主脚本中的 require()
与未注入的模块可用的 require()
不同。除 require.main
外,它也不具有非注入 require()
所具有的任何属性。它只能用于加载内置模块。尝试加载只能在文件系统中找到的模块将引发错误。
¥require()
in the injected main script is not the same as the require()
available to modules that are not injected. It also does not have any of the
properties that non-injected require()
has except require.main
. It
can only be used to load built-in modules. Attempting to load a module that can
only be found in the file system will throw an error.
用户可以将他们的应用打包到一个独立的 JavaScript 文件中以注入可执行文件,而不是依赖于基于 require()
的文件。这也确保了更具确定性的依赖图。
¥Instead of relying on a file based require()
, users can bundle their
application into a standalone JavaScript file to inject into the executable.
This also ensures a more deterministic dependency graph.
但是,如果仍然需要基于 require()
的文件,也可以实现:
¥However, if a file based require()
is still needed, that can also be achieved:
const { createRequire } = require('node:module');
require = createRequire(__filename);
注入主脚本中的 __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
.
注意事项#
¥Notes
单个可执行应用创建过程#
¥Single executable application creation process
旨在创建单个可执行 Node.js 应用的工具必须将使用 --experimental-sea-config"
准备的 blob 的内容注入到:
¥A tool aiming to create a single executable Node.js application must
inject the contents of the blob prepared with --experimental-sea-config"
into:
-
如果
node
二进制文件是 PE 文件,则名为NODE_SEA_BLOB
的资源¥a resource named
NODE_SEA_BLOB
if thenode
binary is a PE file -
如果
node
二进制文件是 Mach-O 文件,则NODE_SEA
段中名为NODE_SEA_BLOB
的部分¥a section named
NODE_SEA_BLOB
in theNODE_SEA
segment if thenode
binary is a Mach-O file -
如果
node
二进制文件是 ELF 文件,则名为NODE_SEA_BLOB
的注释¥a note named
NODE_SEA_BLOB
if thenode
binary is an ELF file
在二进制文件中搜索 NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0
fuse 字符串并将最后一个字符翻转为 1
以指示已注入资源。
¥Search 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.
平台支持#
¥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 支持)
¥Linux (all distributions supported by Node.js except Alpine and all architectures supported by Node.js except s390x)
这是由于缺乏更好的工具来生成可用于在其他平台上测试此功能的单一可执行文件。
¥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 开始讨论以帮助我们记录它们。
¥Suggestions for other resource injection tools/workflows are welcomed. Please start a discussion at https://github.com/nodejs/single-executable/discussions to help us document them.