@@ -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,105 @@ const raw = getRawAsset('a.jpg');
175176See 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.0 - Early development
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 entry points
239+
240+ ` "useVfs": true ` also supports ` "mainFormat": "module" ` . The ESM main
241+ script is loaded from inside the mount through the ESM loader, so
242+ ` import.meta.url ` , ` import.meta.filename ` , and ` import.meta.dirname `
243+ reflect the location of the main script in the virtual file system, and
244+ static and dynamic imports resolve against the bundled assets:
245+
246+ ``` mjs
247+ import fs from ' node:fs' ;
248+ import path from ' node:path' ;
249+
250+ // import.meta.dirname is the root of the virtual file system.
251+ const data = fs .readFileSync (
252+ path .join (import .meta.dirname, ' data/file.txt' ));
253+
254+ // Relative and bare specifier imports resolve inside the mount.
255+ import myModule from ' ./lib/mymodule.mjs' ;
256+ const lazy = await import (' ./lib/lazy.mjs' );
257+ ` ` `
258+
259+ Module format detection works the same way as on the real file
260+ system: name bundled ES modules with the ` .mjs ` extension (or provide the
261+ relevant ` package .json ` files as assets) so they are interpreted as ESM.
262+
263+ #### Snapshot and code caching limitations
264+
265+ ` " useVfs" : true ` cannot be used together with ` " useSnapshot" : true ` or
266+ ` " useCodeCache" : true ` . The code cache limitation is due to incomplete
267+ implementation, not a technical impossibility. Consider bundling the
268+ application if startup performance matters and do not rely on module loading
269+ from the VFS in that case.
270+
271+ #### Native addon limitations
272+
273+ Native addons (` .node ` files) cannot be loaded directly from the VFS because
274+ ` process .dlopen ()` requires files on the real file system. To use native
275+ addons in a SEA with VFS, write the asset to a temporary file first. See
276+ [Using native addons in the injected main script][] for an example.
277+
178278### Startup snapshot support
179279
180280The ` useSnapshot` field can be used to enable startup snapshot support. In this
@@ -648,6 +748,8 @@ to help us document them.
648748[Generating single executable preparation blobs]: #1 - generating- single- executable- preparation- blobs
649749[Mach- O ]: https: // en.wikipedia.org/wiki/Mach-O
650750[PE ]: https: // en.wikipedia.org/wiki/Portable_Executable
751+ [Using native addons in the injected main script]: #using- native- addons- in - the- injected- main- script
752+ [VFS documentation]: vfs .md
651753[Windows SDK ]: https: // developer.microsoft.com/en-us/windows/downloads/windows-sdk/
652754[` process.execPath` ]: process .md #processexecpath
653755[` require()` ]: modules .md #requireid
@@ -660,8 +762,10 @@ to help us document them.
660762[` v8.startupSnapshot` API ]: v8 .md #startup- snapshot- api
661763[documentation about startup snapshot support in Node .js ]: cli .md #-- build- snapshot
662764[fuse]: https: // www.electronjs.org/docs/latest/tutorial/fuses
765+ [module loader integration]: vfs .md #module - loader- integration
663766[postject]: https: // github.com/nodejs/postject
664767[postject- linux- arm64- issue]: https: // github.com/nodejs/postject/issues/105
665768[signtool]: https: // learn.microsoft.com/en-us/windows/win32/seccrypto/signtool
666769[single executable applications]: https: // github.com/nodejs/single-executable
667770[supported by Node .js ]: https: // github.com/nodejs/node/blob/main/BUILDING.md#platform-list
771+ [virtual file system]: vfs .md
0 commit comments