Skip to content

vfs: integrate with CJS and ESM module loaders - #4

Closed
mcollina wants to merge 15 commits into
mainfrom
vfs-module-loader-integration
Closed

vfs: integrate with CJS and ESM module loaders#4
mcollina wants to merge 15 commits into
mainfrom
vfs-module-loader-integration

Conversation

@mcollina

Copy link
Copy Markdown
Owner

Route loader fs and package.json operations through toggleable wrappers so the VFS can resolve and load modules from mounted paths.

Renegade334 and others added 15 commits May 28, 2026 12:12
PR-URL: nodejs#62331
Refs: nodejs#61478
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Signed-off-by: Renegade334 <contact.9a5d6388@renegade334.me.uk>
Signed-off-by: RafaelGSS <rafael.nunu@hotmail.com>
PR-URL: nodejs#63583
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Since the ESM loader is captured in the snapshot now, there's
no need to lazy load the helpers. Load them eagerly to capture
them into the snapshot. This also reduces the noise coming out
of --print-bytecode since we no longer compile the helper
functions at run time.

Signed-off-by: Joyee Cheung <joyeec9h3@gmail.com>
PR-URL: nodejs#63550
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Ensure overlapping next() calls on a single share() consumer resolve
in the same order they were requested.

Fixes: nodejs#63477

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: openai:gpt-5.5
PR-URL: nodejs#63478
Fixes: nodejs#63477
Reviewed-By: James M Snell <jasnell@gmail.com>
Refs: nodejs#63489

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
Assisted-by: openai:gpt-5.5
PR-URL: nodejs#63541
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: nodejs#63586
Refs: nodejs/node-core-utils#1043
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net>
PR-URL: nodejs#63588
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Signed-off-by: Tim Perry <pimterry@gmail.com>
PR-URL: nodejs#63198
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Signed-off-by: Chengzhong Wu <legendecas@gmail.com>
PR-URL: nodejs#63591
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Forward Node.js tail stream data through a pipe-style data listener
instead of manually draining readable events. This keeps compose closer
to the stream pipe hot path while preserving backpressure with pause
and resume.

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: openai:gpt-5.5
PR-URL: nodejs#63593
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
The 8 KiB default has been unchanged since 2015. With the threshold
check `size < (Buffer.poolSize >>> 1)`, this means allocations of 4 KiB
or larger bypass the pool entirely — including 4 KiB itself, a common
page and HTTP-frame size.

Raising the default to 64 KiB extends pool coverage to ~32 KiB
allocations, capturing common sizes used by HTTP parsers, stream
chunks, and small file reads.

Throughput improvements on workers-k=8 fs.readFileSync benchmarks
(Linux/glibc) at the affected sizes, with no regressions elsewhere:

  file size  |  8 KiB pool  |  64 KiB pool  |  delta
  -----------+--------------+---------------+-------
   4 KiB     |  326k ops/s  |  360k ops/s   |  +10%
   8 KiB     |  202k ops/s  |  254k ops/s   |  +26%
  16 KiB     |  148k ops/s  |  181k ops/s   |  +23%
  64 KiB     |   86k ops/s  |   87k ops/s   |   ~
   1 MiB     |   12k ops/s  |   13k ops/s   |   ~

Cost: +56 KiB RSS per realm at startup.
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#63597
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Add mount/unmount lifecycle on `VirtualFileSystem`, a handler registry
that fs.js and fs/promises.js consult via `vfsState.handlers`, and a
router that maps absolute paths to the VFS that owns them. When a VFS
is mounted, the public `fs.*` and `fs/promises` APIs (including
streams, `fs.watch`, and `opendir`) dispatch to the provider for paths
under the mount point, and fall through to the real filesystem
otherwise. Includes per-method dispatch tests, error-path coverage,
multi-mount routing tests, and router unit tests.

Ref: nodejs#63115

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: nodejs#63537
Refs: nodejs#63115
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Defer non-critical warnings to the next event loop iteration when
can_call_into_js() returns false. This prevents crashes when V8
emits warnings during REPL preview evaluation or other contexts
where JavaScript execution is temporarily forbidden.

When a warning is emitted inside DisallowJavascriptExecutionScope,
ProcessEmitWarningGeneric cannot be called immediately. Instead,
use env->SetImmediate() to queue the warning emission for after
the scope exits. This preserves full warning formatting, deprecation
codes, and --redirect-warnings routing.

Signed-off-by: Divyanshu Sharma <Divyanshu88999@gmail.com>
PR-URL: nodejs#63491
Fixes: nodejs#63473
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
PR-URL: nodejs#62999
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Route loader fs and package.json operations through toggleable
wrappers so the VFS can resolve and load modules from mounted paths.
@mcollina

Copy link
Copy Markdown
Owner Author

Reopening against nodejs/node main

@mcollina mcollina closed this May 30, 2026
mcollina pushed a commit that referenced this pull request Jun 7, 2026
This function call can fail with `Z_VERSION_ERROR` if the compiled
library vs loaded library mismatched in version number or in
stream structure size.
In those cases, zlib doesn't initialize the `strm_.msg` field to
null. Therefore, when a `CompressionError` object is created via
`ErrorForMessage()`, it can read a stale or uninitialized `strm_.msg`
pointer that will cause a crash.

Example ASAN report:
```
AddressSanitizer: SEGV on unknown address
    #0 __strlen_avx2
        string/../sysdeps/x86_64/multiarch/strlen-avx2.S:76
    #1 strlen (/work/node/out/Debug/node+0x1a42ab7)
    #2 v8::(anonymous namespace)::StringLength(char const*)
        /work/node/out/../deps/v8/src/api/api.cc:7581:16
    #3 v8::(anonymous namespace)::StringLength(unsigned char const*)
        /work/node/out/../deps/v8/src/api/api.cc:7587:10
    #4 v8::String::NewFromOneByte(v8::Isolate*,
        unsigned char const*, v8::NewStringType, int)
        /work/node/out/../deps/v8/src/api/api.cc:7677:3
    #5 node::OneByteString(v8::Isolate*,
        char const*, int, v8::NewStringType)
        /work/node/out/../src/util-inl.h:166:10
    #6 node::(anonymous namespace)::CompressionStream<
        node::(anonymous namespace)::ZlibContext>
        ::EmitError(node::(anonymous namespace)
        ::CompressionError const&)
        /work/node/out/../src/node_zlib.cc:565:7
    #7 node::(anonymous namespace)::CompressionStream<
        node::(anonymous namespace)::ZlibContext>
        ::CheckError()
        /work/node/out/../src/node_zlib.cc:519:5
    #8 node::(anonymous namespace)::CompressionStream<
        node::(anonymous namespace)::ZlibContext>
        ::AfterThreadPoolWork(int)
        /work/node/out/../src/node_zlib.cc:543:10
    #9 node::ThreadPoolWork::ScheduleWork()
        ::'lambda'(uv_work_s*, int)
        ::operator()(uv_work_s*, int) const
        /work/node/out/../src/threadpoolwork-inl.h:57:15
    nodejs#10 node::ThreadPoolWork::ScheduleWork()
        ::'lambda'(uv_work_s*, int)
        ::__invoke(uv_work_s*, int)
        /work/node/out/../src/threadpoolwork-inl.h:48:7
    nodejs#11 uv__work_done /work/libuv-1.51.0/src/threadpool.c:330:5
    nodejs#12 uv__async_io.part.0
        /work/libuv-1.51.0/src/unix/async.c:208:5
```

Signed-off-by: ndossche <nora.dossche@ugent.be>
PR-URL: nodejs#63476
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants