Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 23 additions & 21 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ so mounting one is gated on its own flag rather than on `--allow-fs-read` or
`--allow-fs-write`.

```console
$ node --experimental-vfs --permission --allow-fs-vfs app.js
$ node --permission --allow-fs-vfs app.js
```

### `--allow-fs-write`
Expand Down Expand Up @@ -1671,16 +1671,6 @@ with AND, so a test must satisfy every expression to run.
A malformed expression causes the test runner to exit with a non-zero status
before running any tests.

### `--experimental-vfs`

<!-- YAML
added: v26.4.0
-->

> Stability: 1 - Experimental

Enable the experimental [`node:vfs`][] module.

### `--experimental-vm-modules`

<!-- YAML
Expand Down Expand Up @@ -2323,6 +2313,18 @@ changes:

Disable the experimental [`node:sqlite`][] module.

### `--no-experimental-vfs`

<!-- YAML
added: v26.4.0
changes:
- version: v27.0.0
pr-url: https://github.com/nodejs/node/pull/66318
description: VFS is unflagged but still experimental.
-->

Disable the experimental [`node:vfs`][] module and `--vfs-load`.

### `--no-experimental-webstorage`

<!-- YAML
Expand Down Expand Up @@ -3859,11 +3861,13 @@ added: v26.10.0

* `source` {string} A directory or an archive file to mount and run.

Requires [`--experimental-vfs`][]. May be given at most once.
May be given at most once.

Mounts `source` as a virtual file system ([`node:vfs`][]), and runs the entry
point and all subsequent `require()`/`import` resolution against that mount
rather than the real file system. The mount is placed at a reserved mount point
rather than the real file system. This option is unavailable when
`--no-experimental-vfs` disables [`node:vfs`][]. The mount is placed at a
reserved mount point
assigned by Node.js, so it never shadows real paths and no target can be
chosen. The entry point is taken from the mount the same way `node <directory>`
takes one: the mount's own `package.json` `"main"`, or `index.js`. Any
Expand Down Expand Up @@ -3894,18 +3898,17 @@ same thing in all of them.

A worker created with its own `execArgv` inherits none of the parent's options,
and so does not mount the source at all. To run a script from the mount, such a
worker must be given the same options again, `--experimental-vfs` and
`--vfs-load`; without them, that thread has no mount for the script to come
from, and the worker fails to load it. `--experimental-vfs` is also what makes
[`node:vfs`][] available to the worker's own code. A worker whose script comes
from anywhere else, such as the real file system, needs nothing added.
worker must be given `--vfs-load` again; without it, that thread has no mount
for the script to come from, and the worker fails to load it. [`node:vfs`][] is
available to worker code without an experimental flag. A worker whose script
comes from anywhere else, such as the real file system, needs nothing added.

`--vfs-load` is not permitted in [`NODE_OPTIONS`][]: which entry point runs is
the command line's decision, and the environment must not be able to redirect
it.

```console
$ node --experimental-vfs --vfs-load=app.zip
$ node --vfs-load=app.zip
```

### `--watch`
Expand Down Expand Up @@ -4231,7 +4234,6 @@ one is included in the list below.
* `--experimental-stream-iter`
* `--experimental-test-isolation`
* `--experimental-top-level-await`
* `--experimental-vfs`
* `--experimental-vm-modules`
* `--experimental-wasi-unstable-preview1`
* `--experimental-web-worker`
Expand Down Expand Up @@ -4267,6 +4269,7 @@ one is included in the list below.
* `--no-experimental-global-navigator`
* `--no-experimental-sqlite`
* `--no-experimental-strip-types`
* `--no-experimental-vfs`
* `--no-experimental-webstorage`
* `--no-extra-info-on-fatal-exception`
* `--no-force-async-hooks-checks`
Expand Down Expand Up @@ -4864,7 +4867,6 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
[`--env-file-if-exists`]: #--env-file-if-existsfile
[`--env-file`]: #--env-filefile
[`--experimental-sea-config`]: single-executable-applications.md#1-generating-single-executable-preparation-blobs
[`--experimental-vfs`]: #--experimental-vfs
[`--heap-prof-dir`]: #--heap-prof-dir
[`--import`]: #--importmodule
[`--no-require-module`]: #--no-require-module
Expand Down
16 changes: 9 additions & 7 deletions doc/api/vfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import vfs from 'node:vfs';
const vfs = require('node:vfs');
```

This module is only available under the `node:` scheme, and only when Node.js
is started with the `--experimental-vfs` flag.
This module is only available under the `node:` scheme. Loading it emits an
`ExperimentalWarning`.

## Security

Expand Down Expand Up @@ -77,8 +77,9 @@ added: v26.4.0
* `provider` {VirtualProvider} The provider to use. **Default:**
`new MemoryProvider()`.
* `options` {Object}
* `emitExperimentalWarning` {boolean} Whether to emit the experimental
warning when the instance is created. **Default:** `true`.
* `emitExperimentalWarning` {boolean} Whether to emit an experimental warning
when an instance is created. **Default:** `true`. Loading `node:vfs` emits
the warning regardless of this option.
* Returns: {VirtualFileSystem}

Convenience factory equivalent to `new VirtualFileSystem(provider, options)`.
Expand Down Expand Up @@ -148,7 +149,7 @@ vfs.registerProvider({
```

```console
$ node --experimental-vfs --require ./provider.js \
$ node --require ./provider.js \
--vfs-load archive.customfmt
```

Expand Down Expand Up @@ -193,8 +194,9 @@ added: v26.4.0
* `provider` {VirtualProvider} The provider to use. **Default:**
`new MemoryProvider()`.
* `options` {Object}
* `emitExperimentalWarning` {boolean} Whether to emit the experimental
warning. **Default:** `true`.
* `emitExperimentalWarning` {boolean} Whether to emit an experimental warning
when an instance is created. **Default:** `true`. Loading `node:vfs` emits
the warning regardless of this option.

### `vfs.mount()`

Expand Down
29 changes: 15 additions & 14 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ A mounted VFS serves paths that the file system permissions do not describe,
so mounting one is gated on its own flag rather than on \fB--allow-fs-read\fR or
\fB--allow-fs-write\fR.
.Bd -literal
$ node --experimental-vfs --permission --allow-fs-vfs app.js
$ node --permission --allow-fs-vfs app.js
.Ed
.
.It Fl -allow-fs-write
Expand Down Expand Up @@ -896,9 +896,6 @@ with AND, so a test must satisfy every expression to run.
A malformed expression causes the test runner to exit with a non-zero status
before running any tests.
.
.It Fl -experimental-vfs
Enable the experimental \fBnode:vfs\fR module.
.
.It Fl -experimental-vm-modules
Enable experimental ES Module support in the \fBnode:vm\fR module.
.
Expand Down Expand Up @@ -1197,6 +1194,9 @@ Legacy alias for \fB--no-require-module\fR.
.It Fl -no-experimental-sqlite
Disable the experimental \fBnode:sqlite\fR module.
.
.It Fl -no-experimental-vfs
Disable the experimental \fBnode:vfs\fR module and \fB--vfs-load\fR.
.
.It Fl -no-experimental-webstorage
Disable \fBWeb Storage\fR support.
.
Expand Down Expand Up @@ -1932,10 +1932,12 @@ Print node's version.
.It
\fBsource\fR \fB{string}\fR A directory or an archive file to mount and run.
.El
Requires \fB--experimental-vfs\fR. May be given at most once.
May be given at most once.
Mounts \fBsource\fR as a virtual file system (\fBnode:vfs\fR), and runs the entry
point and all subsequent \fBrequire()\fR/\fBimport\fR resolution against that mount
rather than the real file system. The mount is placed at a reserved mount point
rather than the real file system. This option is unavailable when
\fB--no-experimental-vfs\fR disables \fBnode:vfs\fR. The mount is placed at a
reserved mount point
assigned by Node.js, so it never shadows real paths and no target can be
chosen. The entry point is taken from the mount the same way \fBnode <directory>\fR
takes one: the mount's own \fBpackage.json\fR \fB"main"\fR, or \fBindex.js\fR. Any
Expand Down Expand Up @@ -1963,16 +1965,15 @@ mounts it, whatever else that thread mounts, so a path into the mount means the
same thing in all of them.
A worker created with its own \fBexecArgv\fR inherits none of the parent's options,
and so does not mount the source at all. To run a script from the mount, such a
worker must be given the same options again, \fB--experimental-vfs\fR and
\fB--vfs-load\fR; without them, that thread has no mount for the script to come
from, and the worker fails to load it. \fB--experimental-vfs\fR is also what makes
\fBnode:vfs\fR available to the worker's own code. A worker whose script comes
from anywhere else, such as the real file system, needs nothing added.
worker must be given \fB--vfs-load\fR again; without it, that thread has no mount
for the script to come from, and the worker fails to load it. \fBnode:vfs\fR is
available to worker code without an experimental flag. A worker whose script
comes from anywhere else, such as the real file system, needs nothing added.
\fB--vfs-load\fR is not permitted in \fBNODE_OPTIONS\fR: which entry point runs is
the command line's decision, and the environment must not be able to redirect
it.
.Bd -literal
$ node --experimental-vfs --vfs-load=app.zip
$ node --vfs-load=app.zip
.Ed
.
.It Fl -watch
Expand Down Expand Up @@ -2228,8 +2229,6 @@ one is included in the list below.
.It
\fB--experimental-top-level-await\fR
.It
\fB--experimental-vfs\fR
.It
\fB--experimental-vm-modules\fR
.It
\fB--experimental-wasi-unstable-preview1\fR
Expand Down Expand Up @@ -2300,6 +2299,8 @@ one is included in the list below.
.It
\fB--no-experimental-strip-types\fR
.It
\fB--no-experimental-vfs\fR
.It
\fB--no-experimental-webstorage\fR
.It
\fB--no-extra-info-on-fatal-exception\fR
Expand Down
3 changes: 1 addition & 2 deletions lib/internal/vfs/file_system.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const {
ERR_INVALID_STATE,
},
} = require('internal/errors');
const { validateBoolean } = require('internal/validators');
const { MemoryProvider } = require('internal/vfs/providers/memory');
const path = require('path');
const { posix: pathPosix, resolve: resolvePath, sep, toNamespacedPath } = path;
Expand All @@ -39,6 +38,7 @@ const {
const { VirtualReadStream, VirtualWriteStream } = require('internal/vfs/streams');
const { VirtualDir } = require('internal/vfs/dir');
const { emitExperimentalWarning, kEmptyObject } = require('internal/util');
const { validateBoolean } = require('internal/validators');
let debug = require('internal/util/debuglog').debuglog('vfs', (fn) => {
debug = fn;
});
Expand Down Expand Up @@ -111,7 +111,6 @@ class VirtualFileSystem {
/**
* @param {VirtualProvider|object} [providerOrOptions] The provider to use, or options
* @param {object} [options] Configuration options
* @param {boolean} [options.emitExperimentalWarning] Emit the experimental warning (default: true)
*/
constructor(providerOrOptions, options = kEmptyObject) {
let provider = null;
Expand Down
3 changes: 3 additions & 0 deletions lib/vfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const {
FunctionPrototypeSymbolHasInstance,
} = primordials;

const { emitExperimentalWarning } = require('internal/util');
emitExperimentalWarning('VirtualFileSystem');

const { VirtualFileSystem } = require('internal/vfs/file_system');
const { VirtualProvider } = require('internal/vfs/provider');
const { MemoryProvider } = require('internal/vfs/providers/memory');
Expand Down
2 changes: 1 addition & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,7 @@ static ExitCode InitializeNodeWithArgsInternal(
{
auto* env_options = per_process::cli_options->per_isolate->per_env.get();
if (!env_options->experimental_vfs && env_options->vfs_load) {
errors->push_back("--vfs-load requires --experimental-vfs");
errors->push_back("--vfs-load requires node:vfs to be enabled");
}
// A second --vfs-load would silently replace the first, and the option
// itself cannot say how often it was given; count it in the node options
Expand Down
5 changes: 3 additions & 2 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,8 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--experimental-vfs",
"experimental node:vfs module",
BOOL_FIELD(experimental_vfs),
kAllowedInEnvvar);
kAllowedInEnvvar,
true);
// Choosing the entry point is the command line's alone: an environment
// variable must not be able to redirect what a `node <args>` invocation runs,
// so this is rejected in NODE_OPTIONS. The source and whether to run from it
Expand All @@ -801,7 +802,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--vfs-load",
"mount a directory or archive as a virtual file system and run the "
"entry point and module resolution against it instead of the real "
"file system (may be given once; requires --experimental-vfs)",
"file system (may be given once)",
&EnvironmentOptions::vfs_load_source,
kDisallowedInEnvvar);
AddOption("[vfs_load_set]", "", BOOL_FIELD(vfs_load));
Expand Down
2 changes: 1 addition & 1 deletion src/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ class EnvironmentOptions : public Options {
DEFINE_BOOL_FIELD(experimental_websocket) = true;
DEFINE_BOOL_FIELD(experimental_sqlite) = HAVE_SQLITE;
DEFINE_BOOL_FIELD(experimental_stream_iter) = EXPERIMENTALS_DEFAULT_VALUE;
DEFINE_BOOL_FIELD(experimental_vfs) = EXPERIMENTALS_DEFAULT_VALUE;
DEFINE_BOOL_FIELD(experimental_vfs) = true;
DEFINE_BOOL_FIELD(vfs_load) = false;
DEFINE_BOOL_FIELD(webstorage) = HAVE_SQLITE;
DEFINE_BOOL_FIELD(experimental_dtls) = EXPERIMENTALS_DEFAULT_VALUE;
Expand Down
2 changes: 1 addition & 1 deletion test/ffi/test-ffi-vfs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --experimental-vfs
// Flags: --disable-warning=ExperimentalWarning
'use strict';
const common = require('../common');
common.skipIfFFIMissing();
Expand Down
11 changes: 9 additions & 2 deletions test/parallel/test-module-builtin-experimental.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Flags: --disable-warning=ExperimentalWarning
'use strict';

const common = require('../common');
Expand All @@ -8,7 +9,6 @@ const experimentalBuiltins = [
['bench/reporters', '--experimental-bench', true],
['dtls', '--experimental-dtls', common.hasDtls],
['quic', '--experimental-quic', common.hasQuic],
['vfs', '--experimental-vfs', true],
].filter(([, , available]) => available);

for (const [id, flag] of experimentalBuiltins) {
Expand Down Expand Up @@ -51,7 +51,14 @@ if (common.hasFFI) {
], { status: 0 });
}

const schemeOnlyBuiltins = ['node:test', 'node:sea'];
// node:vfs is enabled by default and can be disabled with
// --no-experimental-vfs.
spawnSyncAndAssert(process.execPath, [
'--no-experimental-vfs',
'-e', `const m = require('node:module'); if (m.builtinModules.includes('node:vfs')) process.exit(1); try { require('node:vfs'); } catch (e) { if (e.code === 'ERR_UNKNOWN_BUILTIN_MODULE') process.exit(0); } process.exit(1);`,
], { status: 0 });

const schemeOnlyBuiltins = ['node:test', 'node:sea', 'node:vfs'];
if (common.hasFFI) {
schemeOnlyBuiltins.push('node:ffi');
}
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-permission-dlopen-binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function run(...permissions) {
`;
const vfsRun = (...permissions) => spawnSync(
process.execPath,
['--experimental-vfs', '--permission', '--allow-fs-read=*',
['--permission', '--allow-fs-read=*',
...permissions, '-e', mounted],
{ encoding: 'utf8' });

Expand Down
2 changes: 0 additions & 2 deletions test/parallel/test-require-resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ require(fixtures.path('resolve-paths', 'default', 'verify-paths.js'));
builtinModules.forEach((mod) => {
// TODO(@jasnell): Remove once node:quic is no longer flagged
if (mod === 'node:quic') return;
// Remove once node:vfs is no longer flagged
if (mod === 'node:vfs') return;
if (mod === 'node:sqlite' && !common.hasSQLite) return;
assert.strictEqual(require.resolve.paths(mod), null);
if (!mod.startsWith('node:')) {
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-vfs-access-modes.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --experimental-vfs
// Flags: --disable-warning=ExperimentalWarning
'use strict';

// access / accessSync honour the R_OK / W_OK / X_OK / F_OK mode bits and
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-vfs-addon.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --experimental-vfs
// Flags: --disable-warning=ExperimentalWarning
'use strict';
const common = require('../common');
const assert = require('assert');
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-vfs-append-write.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --experimental-vfs
// Flags: --disable-warning=ExperimentalWarning
'use strict';

// writeSync in append mode must append, not overwrite.
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-vfs-bigint-position.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --experimental-vfs
// Flags: --disable-warning=ExperimentalWarning
'use strict';

// VFS readSync should accept a BigInt position parameter.
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-vfs-callback-api.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --experimental-vfs
// Flags: --disable-warning=ExperimentalWarning
'use strict';

// Exercise the VFS callback-style async API on every method.
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-vfs-copyfile-mode.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Flags: --experimental-vfs
// Flags: --disable-warning=ExperimentalWarning
'use strict';

// Tests for VFS copyFile mode support:
Expand Down
Loading