bench(startup): add ESM variant that exercises the iitm loader#8956
Conversation
The startup variants load the fixture through CommonJS require, which goes through require-in-the-middle and never registers the iitm ESM loader. That loader is what the synchronous module.registerHooks work changes from an off-thread async loader to an in-thread sync one, so the suite reported no movement for that change: nothing put the loader on a measured path. with-tracer-everything-esm registers the loader via --import ../../../register.js and imports the same fixture through ESM, so every dependency and its transitive graph flow through the loader's resolve/load hooks. The fixture's index.mjs reads the same dependencies as index.js, so the dependency list stays single-sourced in package.json. Refs: #8942
Overall package sizeSelf size: 6.25 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.2 | 85.93 kB | 825.11 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
BenchmarksBenchmark execution time: 2026-06-17 13:45:19 Comparing candidate commit 4766a8f in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 1950 metrics, 15 unstable metrics.
|
The startup variants load the fixture through CommonJS require, which goes through require-in-the-middle and never registers the iitm ESM loader. That loader is what the synchronous module.registerHooks work changes from an off-thread async loader to an in-thread sync one, so the suite reported no movement for that change: nothing put the loader on a measured path. with-tracer-everything-esm registers the loader via --import ../../../register.js and imports the same fixture through ESM, so every dependency and its transitive graph flow through the loader's resolve/load hooks. The fixture's index.mjs reads the same dependencies as index.js, so the dependency list stays single-sourced in package.json. Refs: #8942
The startup variants load the fixture through CommonJS require, which goes through require-in-the-middle and never registers the iitm ESM loader. That loader is what the synchronous module.registerHooks work changes from an off-thread async loader to an in-thread sync one, so the suite reported no movement for that change: nothing put the loader on a measured path. with-tracer-everything-esm registers the loader via --import ../../../register.js and imports the same fixture through ESM, so every dependency and its transitive graph flow through the loader's resolve/load hooks. The fixture's index.mjs reads the same dependencies as index.js, so the dependency list stays single-sourced in package.json. Refs: #8942
The startup variants load the fixture through CommonJS require, which goes through require-in-the-middle and never registers the iitm ESM loader. That loader is what the synchronous module.registerHooks work changes from an off-thread async loader to an in-thread sync one, so the suite reported no movement for that change: nothing put the loader on a measured path. with-tracer-everything-esm registers the loader via --import ../../../register.js and imports the same fixture through ESM, so every dependency and its transitive graph flow through the loader's resolve/load hooks. The fixture's index.mjs reads the same dependencies as index.js, so the dependency list stays single-sourced in package.json. Refs: #8942
Summary
The
startupsirun variants loadeverything-fixturethrough CommonJSrequire, which goes through require-in-the-middle and never registers the iitm ESM loader. That loader is what #8942 changes from an off-thread asynchronous loader (module.register) to an in-thread synchronous one (module.registerHooks), so the benchmark suite reported "performance is the same" for that PR — no variant put the loader on a measured path.with-tracer-everything-esmregisters the loader via--import ../../../register.jsand imports the same fixture through ESM, so every dependency and its transitive graph flow through the loader's resolve/load hooks. On master this measures the async loader; on #8942 (sync loader on capable Node) the A/B renders the difference.index.mjsreads the samedependenciesasindex.js, so the dependency list stays single-sourced inpackage.json— updating one updates both.registerHooks, so perf(loader): use synchronous iitm hooks when available #8942 keeps the async loader there (no delta); 24/26 show the sync win.Why
#8942's 56% Vitest startup reduction was invisible to CI because the existing startup variants are CJS-only. This closes that coverage gap and guards the ESM loader path against future regressions.
Test plan
startup / with-tracer-everything-esmreports stableinstructionsandwall.timeon Node 20/24/26.Note on local validation: macOS sirun hangs on every
startupvariant (including the existing ones), so stability was checked with direct process timing — steady-state ~0.69s, ~2% spread, all three variants exit 0 on Node 20/24/26 — and the sirun numbers are left to CI's pinned isolated core, per the benchmark guidance.Refs: #8942