feat: support Node 24 - #88
Conversation
`--no-opt` is only an alias for `--no-turbofan`. Maglev is compiled out of Node < 24 (`v8_enable_maglev=0`), but Node 24 ships it enabled by default, so hot functions still tier up under the analysis flag set: whole-process callgrind Ir drops from 167.0M (22.20.0) to 111.9M (24.19.0) on a hot-loop probe, and steady-state per-iteration cost falls 286.7k -> 64.2k Ir. Adding `--no-maglev` restores the same tiering state as Node 22 (`%GetOptimizationStatus` 0x8003 on both) and a comparable Ir level (179.5M). `--scavenge-task` was renamed to `--minor-gc-task` in V8 11.3, so since Node 20 the analysis flags contained no minor-GC-task suppression at all.
Node 24 dropped support for the legacy `assert { type: "json" }` import
attribute syntax, but rollup still defaults `importAttributesKey` to
`assert` when it bundles the TypeScript config file. That makes every
`rollup -c rollup.config.ts` build fail with
`SyntaxError: Unexpected identifier 'assert'`.
Pass `--configImportAttributesKey with` in the build scripts and
normalize the one config still written with `assert`.
|
@greptileai review |
Greptile SummaryThe PR moves repository automation and compatibility coverage to Node 24 while retaining Node 22 example coverage.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains within the follow-up review scope. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/core/src/introspection.ts | Extends analysis-mode V8 flags for current Node/V8 garbage collection and Maglev behavior. |
| packages/core/src/native_core/linux_perf/utils.h | Replaces removed V8 string APIs with v8::String::Utf8Value for Node 24 compatibility. |
| .github/workflows/ci.yml | Updates setup actions and moves example compatibility coverage to Node 22 and 24. |
| .github/workflows/release.yml | Updates the release toolchain and switches npm publication from a repository token to trusted-publisher OIDC. |
| packages/tinybench-plugin/package.json | Uses the in-process tsx loader for the plugin’s ESM TypeScript benchmark. |
| rollup.options.mjs | Migrates shared Rollup configuration to native ESM for Node 24-compatible config loading. |
Reviews (2): Last reviewed commit: "chore: clear CI warnings" | Re-trigger Greptile
Merging this PR will regress 32 benchmarks
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Memory | switch 2 |
1 B | 13,664 B | -99.99% |
| ❌ | Memory | test_iterative_fibo_100 |
400 B | 13,736 B | -97.09% |
| ❌ | Simulation | switch 1 |
247.4 µs | 1,318.5 µs | -81.23% |
| ❌ | Simulation | recursive fibo 10 |
279.7 µs | 1,373 µs | -79.63% |
| ❌ | WallTime | test_recursive_cached_fibo_10 |
1.1 µs | 2.5 µs | -57.28% |
| ❌ | Simulation | short body 2 |
122.9 µs | 215.9 µs | -43.09% |
| ❌ | Simulation | recursive fibo 15 with hooks |
381 µs | 661.5 µs | -42.41% |
| ❌ | Simulation | recursive fibo 15 with hooks |
380.9 µs | 661.3 µs | -42.4% |
| ❌ | Memory | test_iterative_fibo_10 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test_recursive_cached_fibo_20 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test_recursive_fibo_20 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test_recursive_cached_fibo_20 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test_recursive_cached_fibo_30 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test_recursive_fibo_20 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test_iterative_fibo_100 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test sync baz 100 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test_recursive_cached_fibo_30 |
400 B | 656 B | -39.02% |
| ❌ | Memory | switch 2 |
400 B | 656 B | -39.02% |
| ❌ | Memory | test sync baz 100 |
400 B | 656 B | -39.02% |
| ❌ | Simulation | test_recursive_cached_fibo_10 |
52.2 µs | 83.4 µs | -37.47% |
| ... | ... | ... | ... | ... | ... |
ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing chore/node-24 (534b22a) with main (1999ec9)
6f7391b to
534b22a
Compare
- bump `.nvmrc` and `engines.node` to 24.19.0, which also moves the CodSpeed instrumented, memory and walltime runs to Node 24 - add Node 24 to the example matrix. Its Node 20 entry moves from the stale 20.5.1 pin (it only mirrored the old `engines` value) to 20, because `node --import` needs `module.register`, added in 20.6.0 - run the ESM TypeScript benches with tsx: esbuild-register's ESM loader no longer intercepts `.ts` on Node >= 22, so those benches died with `Cannot use import statement outside a module`. `node --import tsx` keeps the benchmark in a single process, so the runner's PATH shim still delivers the V8 flags through `process.execArgv` - import the plugin by name in its own bench, since tsx resolves a relative directory import to `index.ts` instead of going through the package exports
The hardcoded flag list broke on Node 24, which adds --no-maglev; asserting the plugin wiring instead of duplicating the version-dependent flag list keeps the test valid across Node majors.
Node 24 bundles npm 11.17.0, clearing the npm >= 11.5.1 floor that made trusted publishing unavailable on the previous 20.5.1 pin, so publishing no longer needs a long-lived token. pnpm 10 shells out to the ambient npm, which performs the OIDC exchange before any configured token is used, so the publish command itself is unchanged. Verbose logging keeps the exchange result visible in the release log. The exchange is scoped per package name, so every published package needs a trusted publisher registered for this repository and release.yml.
534b22a to
0062a25
Compare
- bump `actions/setup-node` and `pnpm/action-setup` to the majors that run on Node 24, the runners now warn about the Node 20 based ones - use the `simulation` runner mode in the example matrix, `instrumentation` is deprecated - widen the root `engines.node` to `>=22`, the exact pin made every Node 22 example job print an unsupported engine warning - pass `sourceMap`/`outputToFilesystem` to the rollup config plugin, which otherwise warns while compiling `rollup.config.ts` - move the runner mode helpers to their own module: `introspection.ts` imported them from the barrel file, so rollup reported a cycle - ignore the `EVAL` warning for `optimization.ts`, %OptimizeFunctionOnNextCall has no non-eval entry point - build the symbol names with `v8::String::Utf8Value`, `Utf8Length` and `WriteUtf8` are deprecated as of the V8 shipped with Node 24
0062a25 to
5c0fb41
Compare
|
@greptileai review |
What
Adds Node 24 to CI and moves the repo (and therefore the CodSpeed runs) onto it.
.nvmrcandengines.nodego to24.19.0, which switches theCodSpeedworkflow (instrumented, simulation, memory, walltime, walltime-macos) and theCIcheck/release jobs to Node 24["22", "24"], dropping the EOL 18 and 20 entries@types/nodemoves to^24Issues found and fixed
rollup -c rollup.config.tsbuild fails withSyntaxError: Unexpected identifier 'assert'output.importAttributesKeyto the legacyassertkey when bundling the TS config, and Node 24 removed support for it--configImportAttributesKey within the five build scripts, plus the one config still written withassertCannot use import statement outside a moduleesbuild-register's ESM loader no longer intercepts.tsunder Node >= 22 module resolutionnode --import tsx <file>inpackages/tinybench-pluginand the four ESM examples;esbuild-registergives way totsxtherepnpm --filter @codspeed/tinybench-plugin benchfails withERR_MODULE_NOT_FOUND .../index.tsbenches/sample.tsimported"..", and tsx resolves a relative directory import toindex.tsinstead of the packageexportsdist/index.es5.jsCJS examples and
@codspeed/benchmark.js-pluginkeepnode -r esbuild-register; that path works unchanged on 18, 20 and 24.Why
--import tsxand not thetsxCLIThe runner delivers V8 flags with a PATH shim that re-execs
$REAL_NODE_PATH $V8_FLAGS "$@", andcheckV8Flagsreads them back fromprocess.execArgv. ThetsxCLI spawns a child throughprocess.execPathcarrying only its own loader flags, so that child would bypass the shim and quietly lose--allow-natives-syntaxand friends.--import tsxstays in one process.Verification
On Node 18.20.8, 20.19.2 and 24.19.0:
pnpm turbo run build --force: green on all threeformat lint typecheck24/24 green, including the@types/nodebumpnode --import tsxbenches in default and simulation mode: flags harvested and present inprocess.execArgv, no[CodSpeed] missing required flagswarning; the same run without the shim does warn, which confirms the check is liveWall-time impact of the loader swap is a one-off
+23msat startup (65ms vs 42ms). Bench durations and per-task latencies are unchanged within the local noise floor (repeating one command three times spans 9%).Release prerequisite
Publishing now authenticates to npm over GitHub OIDC, so a trusted publisher must exist before the next
v*tag. npm's token exchange is scoped per package name, so all five published packages need their own entry (npmjs.com → package → Settings → Trusted Publisher → GitHub Actions):CodSpeedHQcodspeed-noderelease.ymlnpm publishPackages:
@codspeed/core,@codspeed/benchmark.js-plugin,@codspeed/tinybench-plugin,@codspeed/vitest-plugin,@codspeed/playwright-plugin.This needs an npm org owner. Until it lands, a tag push fails at the publish step; re-adding
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}to that step'senvrestores token publishing.Note
Unit tests in
vitest-pluginandtinybench-pluginfail when the repo is checked out as a git worktree, becausegetGitDir()looks for a.gitdirectory while a worktree has a.gitfile, so benchmark URIs pick up an extra path segment. Pre-existing and unrelated to this branch (it reproduces on Node 22 before these commits) and CI is unaffected, so it is left alone here.