Skip to content

Commit 148a0d7

Browse files
committed
doc: document the SEA virtual file system option
Document "useVfs" in the SEA configuration and how bundled assets are accessed through the mounted virtual file system, and add a Single Executable Applications section to the VFS documentation. Signed-off-by: Matteo Collina <hello@matteocollina.com>
1 parent 8e6f9c2 commit 148a0d7

2 files changed

Lines changed: 114 additions & 0 deletions

File tree

doc/api/single-executable-applications.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ The configuration currently reads the following top-level fields:
116116
"disableExperimentalSEAWarning": true, // Default: false
117117
"useSnapshot": false, // Default: false
118118
"useCodeCache": true, // Default: false
119+
"useVfs": true, // Default: false
119120
"execArgv": ["--no-warnings", "--max-old-space-size=4096"], // Optional
120121
"execArgvExtension": "env", // Default: "env", options: "none", "env", "cli"
121122
"assets": { // Optional
@@ -175,6 +176,86 @@ const raw = getRawAsset('a.jpg');
175176
See documentation of the [`sea.getAsset()`][], [`sea.getAssetAsBlob()`][],
176177
[`sea.getRawAsset()`][] and [`sea.getAssetKeys()`][] APIs for more information.
177178

179+
### Virtual file system (VFS) for assets
180+
181+
<!-- YAML
182+
added: REPLACEME
183+
-->
184+
185+
> Stability: 1 - Experimental
186+
187+
In addition to using the `node:sea` API to access individual assets, the
188+
bundled assets can be exposed as a read-only [virtual file system][] and
189+
accessed through standard `node:fs` APIs. To enable this, set
190+
`"useVfs": true` in the SEA configuration.
191+
192+
A virtual file system never shadows the real file system: it is mounted at a
193+
reserved mount point that cannot exist on the real file system, and the mount
194+
point is chosen at runtime rather than being a fixed path. When `useVfs` is
195+
enabled, the injected main script itself is placed at the root of the mount
196+
and executed from there, so `__filename` and `__dirname` point inside the
197+
virtual file system instead of reflecting [`process.execPath`][]. Bundled
198+
code therefore reaches the assets through `__dirname`-relative paths and
199+
relative [`require()`][] calls, without having to know the mount point:
200+
201+
```cjs
202+
const fs = require('node:fs');
203+
const path = require('node:path');
204+
205+
// __dirname is the root of the virtual file system holding the assets.
206+
const rawConfig = fs.readFileSync(path.join(__dirname, 'config.json'), 'utf8');
207+
const data = fs.readFileSync(path.join(__dirname, 'data/file.txt'));
208+
209+
// Directory operations work too.
210+
const files = fs.readdirSync(path.join(__dirname, 'assets'));
211+
212+
// Check if a bundled file exists.
213+
if (fs.existsSync(path.join(__dirname, 'optional.json'))) {
214+
// ...
215+
}
216+
```
217+
218+
The VFS supports the `node:fs` operations for reading files and directories.
219+
Since the SEA VFS is read-only, write operations fail with `EROFS`. See the
220+
[VFS documentation][] for the full list of supported operations.
221+
222+
#### Loading modules from the VFS in a SEA
223+
224+
When `useVfs` is enabled, the main script is executed from inside the
225+
virtual file system, and `require()` uses the [module loader
226+
integration][] of the VFS to load modules from the bundled assets. This
227+
supports relative requires (e.g. `require('./helper.js')`) as well as
228+
`node_modules` package lookups, which are confined to the mount:
229+
230+
```cjs
231+
// Require bundled modules using relative paths.
232+
const myModule = require('./lib/mymodule.js');
233+
234+
// Packages bundled under the node_modules asset prefix also resolve.
235+
const dep = require('some-package');
236+
```
237+
238+
#### ESM limitations
239+
240+
The `useVfs` option does not currently support ESM entry points. Using
241+
`"useVfs": true` together with `"mainFormat": "module"` is not supported.
242+
The main script must use CommonJS (`require()`) when VFS is enabled.
243+
244+
#### Snapshot and code caching limitations
245+
246+
`"useVfs": true` cannot be used together with `"useSnapshot": true` or
247+
`"useCodeCache": true`. The code cache limitation is due to incomplete
248+
implementation, not a technical impossibility. Consider bundling the
249+
application if startup performance matters and do not rely on module loading
250+
from the VFS in that case.
251+
252+
#### Native addon limitations
253+
254+
Native addons (`.node` files) cannot be loaded directly from the VFS because
255+
`process.dlopen()` requires files on the real file system. To use native
256+
addons in a SEA with VFS, write the asset to a temporary file first. See
257+
[Using native addons in the injected main script][] for an example.
258+
178259
### Startup snapshot support
179260

180261
The `useSnapshot` field can be used to enable startup snapshot support. In this
@@ -648,6 +729,8 @@ to help us document them.
648729
[Generating single executable preparation blobs]: #1-generating-single-executable-preparation-blobs
649730
[Mach-O]: https://en.wikipedia.org/wiki/Mach-O
650731
[PE]: https://en.wikipedia.org/wiki/Portable_Executable
732+
[Using native addons in the injected main script]: #using-native-addons-in-the-injected-main-script
733+
[VFS documentation]: vfs.md
651734
[Windows SDK]: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
652735
[`process.execPath`]: process.md#processexecpath
653736
[`require()`]: modules.md#requireid
@@ -660,8 +743,10 @@ to help us document them.
660743
[`v8.startupSnapshot` API]: v8.md#startup-snapshot-api
661744
[documentation about startup snapshot support in Node.js]: cli.md#--build-snapshot
662745
[fuse]: https://www.electronjs.org/docs/latest/tutorial/fuses
746+
[module loader integration]: vfs.md#module-loader-integration
663747
[postject]: https://github.com/nodejs/postject
664748
[postject-linux-arm64-issue]: https://github.com/nodejs/postject/issues/105
665749
[signtool]: https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool
666750
[single executable applications]: https://github.com/nodejs/single-executable
667751
[supported by Node.js]: https://github.com/nodejs/node/blob/main/BUILDING.md#platform-list
752+
[virtual file system]: vfs.md

doc/api/vfs.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,34 @@ system, the callers are responsible for avoiding removal or
417417
invalidation of modules in the virtual file system while they are
418418
being loaded.
419419

420+
## Use with Single Executable Applications
421+
422+
When running as a [Single Executable Application][] built with
423+
`"useVfs": true` in the SEA configuration, the bundled assets are
424+
automatically mounted as a read-only virtual file system and the injected
425+
main script is executed from the root of the mount. No additional setup is
426+
required. Since the mount point is reserved and chosen at runtime, bundled
427+
code accesses the assets through `__dirname`-relative paths and relative
428+
`require()` calls rather than through a fixed path:
429+
430+
```cjs
431+
// In the SEA main script, __dirname is the root of the mounted assets.
432+
const fs = require('node:fs');
433+
const path = require('node:path');
434+
435+
const config = JSON.parse(
436+
fs.readFileSync(path.join(__dirname, 'config.json'), 'utf8'));
437+
const template = fs.readFileSync(
438+
path.join(__dirname, 'templates/index.html'), 'utf8');
439+
```
440+
441+
`"useVfs"` cannot be used together with `"useSnapshot"`, `"useCodeCache"`, or
442+
`"mainFormat": "module"`. The SEA configuration parser will error if any of
443+
these combinations are detected.
444+
445+
See the [Single Executable Application][] documentation for more information
446+
on creating SEA builds with assets.
447+
420448
## Class: `VirtualProvider`
421449

422450
<!-- YAML
@@ -540,6 +568,7 @@ fields use synthetic but stable values:
540568
[CommonJS resolution algorithm]: modules.md#all-together
541569
[ES modules resolution algorithm]: esm.md#resolution-algorithm
542570
[Explicit Resource Management]: https://github.com/tc39/proposal-explicit-resource-management
571+
[Single Executable Application]: single-executable-applications.md
543572
[`MemoryProvider`]: #class-memoryprovider
544573
[`RealFSProvider`]: #class-realfsprovider
545574
[`VirtualFileSystem`]: #class-virtualfilesystem

0 commit comments

Comments
 (0)