Repository navigation
test(router-plugin): implementation-agnostic code-splitting tests and the compiler test harness - #8906
test(router-plugin): implementation-agnostic code-splitting tests and the compiler test harness#8906Sheraff wants to merge 18 commits into
Conversation
… the compiler test harness Adds `@tanstack/compiler-test-utils`, the harness of #8817's compiler test suite: real Vite, Rsbuild, Rspack and webpack builds and dev servers, route apps in pages of a real Chromium, and one merged diagnostic channel. Only the parts the route code splitting tests use come along. Adds #8817's route code splitting tests that pass on main's compilers: whole files where every test passes, and the passing describe groups and table rows of mixed files. Its one pin that main passes (Rolldown, a `var` declared again in a head or a pattern) lands as an ordinary test. The slow tier runs as router-plugin `test:integration`. Deletes main's Babel-specific splitting tests the new ones replace: the code-splitter snapshot matrix (except the four fixtures that cover shapes the new tests do not reach yet), shared-bindings-helpers, utils, delete-nodes, the old regression suites, production-warnings and source-maps. Main's route HMR tests stay, in their own `unit-babel` project, until the route HMR slice replaces them. Takes #8817's sass bump of the css-modules e2e apps, so that the harness and the plugins load one copy of vite and vitest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
WalkthroughWarning Review details and warnings were omitted to fit the comment limit. |
|
View your CI Pipeline Execution ↗ for commit ad808b6
💡 With Ultracache enabled, Nx Cloud learns each task's file inputs in CI and uses them on later runs. Turn on Ultracache in workspace settings ↗ · Read docs ↗ ☁️ Nx Cloud last updated this comment at |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
🚀 Changeset Version Preview2 package(s) bumped directly, 3 bumped as dependents. 🟨 Minor bumps
🟩 Patch bumps
|
… map-name checks The slice has no test for two behaviours main guards: a webpack or Rspack production build whose configuration has no `mode` ships no splitter warning (#8269), and on webpack and Rspack the maps of a split component and of shared code name the route file, not the `?tsr-split` id (#8860). Keep those cases of main's tests, cut to what the slice does not cover: the `mode: 'production'` rows, the line mapping and Vite's dev server are asserted in the integration tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merging this PR will improve performance by 7.53%2 warnings
Performance Changes
Tip Curious why performance improved? Comment Comparing Footnotes
|
Takes #8907, which restores main's start-plugin-core build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bundle Size Benchmarks
The following scenarios have bundle-size changes compared with the baseline:
Current gzip tracks all emitted client JS chunks. Initial gzip tracks only the entry/import graph. Trend sparkline is historical current gzip ending with this PR measurement; lower is better. |
…e run pages (#8817 5bd6685) Takes #8817's test infrastructure changes since 294b3f3 that apply here: - router-plugin's `test:integration` runs as four Nx shard targets (Vitest `--shard`), and `test:integration:whole` runs the tier in one Vitest run, for file filters and budget measurements; - each test file gets its own run pages and browser context, closed when the file ends (`onFileFinished` in `test-scope`), so a later file inherits none of their memory or cache; - SPEC and the harness notes, as in #8817. #8817's new splitting tests (`code-splitter-effect-timing`) and the changed `code-splitter-kept-reports` fail on main, so they stay out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes main's pnpm 12 upgrade (#8912), the RSC dependency bump (#8919) and the react-start HMR e2e fix (#8913). The lockfile is main's, regenerated with pnpm 12 for the slice's packages. pnpm 12 merges a version a package names directly into the other packages' ranges, so two ranges of the slice are set to the versions main already resolves, to leave every other package's resolution as on main: the harness's `esbuild` (^0.28.1; ^0.28.2 added a second esbuild and moved webpack's peer variant) and router-plugin's `@babel/preset-typescript` (7.27.1; ^7.28.5 moved esbuild-plugin-solid's preset and the preset's own helpers). The only change left outside the slice's packages is the css-modules e2e apps' sass bump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes #8817's test changes since 5bd6685 that apply on main's compilers: - harness: the pin check (a pin passes only on an assertion error), edits without their outcome fail as assertions, child Node runs report the step they were in and time out below the test timeout, watch rebuilds wait for the build that saw the edit, binary app files, map helpers for the new map-source test, and its new controls (`pins`, `run-directory`); - new passing code-splitting tests: `build-map-sources` (it replaces the copy of main's webpack/Rspack map-name check), `build-js-extension-assets`, `code-splitter-other-names`, `-pure-framework-calls` (Vue, Solid), `-unreadable-loader`, `-value-own-writes`, `-const-chains`, `-effect-timing` (decorators), `route-unrecognized-fixes`, `vite-unanalysed-modules`, 14 new shapes of `code-splitter-state-read-at-load` and one effectful-declaration row; - `code-splitter-reexported-factory` goes as in #8817: main passes it only because its compile crashes on a duplicate `createFileRoute`; - the `integrationProject` refactor of router-plugin's Vitest config. Left out because they fail on main: #8817's new rows of `build-source-maps`, `plugin-options` (esbuild), `code-splitter-route-options` (object loaders with a spread) and the failing rows of the new files. Left out because they need #8817's core: the compiler stats check of `test-scope-setup` and its `TSR_COMPILER_STATS` knob. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…shot suite this PR deletes Review S1. The snapshot guidance and the invariant-suite pointer go with the suite; the two tiers, behaviour tests through loadRoute, no output snapshots and the unit-main project come in. The route HMR bullets stay: main's HMR tests stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…with its message again
Review S2. Main's test that tanstackRouter({ autoCodeSplitting: true }) throws comes back in esbuild.test.ts, with main's message. The either-or build test's comment no longer calls the refusal a bug.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lformed split id error Review S3 and S4. The ported page test only checks that a Solid or Vue route compiled with HMR stays valid and renders; main's test that the route HMR plugin adds its Vite HMR handling (without code splitting) stays next to the webpack one. Main's test of the error for a split module id without a split value (router-code-splitter-plugin.ts) stays too, with its helper (createCodeSplitterTransforms) back in regression-helpers.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review S5. KNOWN-BUGS.md drops the rows that call Babel and unplugin bugs fixed (they are live on main) and the rows whose pins or workarounds sit in test files main does not have. The harness AGENTS.md drops the Start hosts, the integration-alone process and the react-start build, which only the later suites need. The known-bugs test files no longer say each test is a bug today's compiler fixes, nor point at KNOWN-BUGS sections that are not here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review S6. Removed: the TSR_COMPILER_VERIFY variable (nothing on main reads it) and its self-test; the @tanstack/history build dependency of test:integration; the budgets of packages that do not use the reporter here; settlePage and the hmr-sync scripts with their self-test (the slice uses trackRequests only); reorderings, reorderedRecords and expectDeterministic with their self-tests (the slice uses expectRelocatable only). describeHmr stays: the dev-server harness's own controls use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd a client run is bounded
Review S7. openPage closes its context (and frees its slot) when a step after opening it fails, e.g. a refused navigation: callers without registerCleanup (runInBrowser) had nothing to close, and after openPageLimit such failures every later openPage waited forever. runInBrowser races the page's load and script against a timeout (default 25 s, below the tiers' 30 s test timeout; run(script, { timeout })), as runInPage does. Two controls fail before the fix (both time out) and pass after it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… for the function case it tests Review S8. The header and fixture lose the class case the slice does not test. The user-side chunk group now leaves out every module id with a query, instead of matching the compiler's split query (`tsr-split=export---` is #8817's id format), and 'unreported' means no warning names the route file, instead of a match on the warning's text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-fixes Review S9. Its two 'is reported nothing' tests pass on main only because main has no such report; their positive cases fail on main. The file comes with the PR that brings the reports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Yuku with a compiler Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hout design-doc references Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
First slice of #8817's test suite, landing on
mainbefore the compiler swap. Tests only: no published code changes.The harness
packages/compiler-test-utils(private) is the test harness of #8817's suite. Tests use it to drive the router plugin the way an app does:The tests go through the public plugins and options only. They check what a user sees (what renders, what loads lazily, what a build reports), never the compiler's output text. Any correct compiler should pass them, Babel-based or not.
Only the parts this slice uses come along. These are left out:
global-trap,rsbuild-plugin-host,workspace-packages,native-import.cjs,TSR_COMPILER_VERIFY, unused exports (most ofhmr-syncanddeterminism), and the harness self-tests of those modules.oracle/KNOWN-BUGS.mdkeeps only the upstream issues the harness code cites. The pins list comes with the swap.@tanstack/compiler-vite-versionsholds Vite 6 and 7 forvite-versions.test.ts.What the slice covers
#8817's route code splitting tests (router-plugin, area rules of the split plan), re-run on current
mainwith this harness, every test twice:.failspin in #8817No test gave different results in the two runs. 21 tests that failed on Nov 3 pass now, after this week's fixes on
main.This PR first brought 1,012 of the passing tests; after the re-syncs with #8817 and the review fixes below it carries 1,090:
describegroups and table rows of 42 mixed files. These files keep refactor(compiler)!: replace Babel with a Yuku-based compiler core for Router and Start #8817's structure, so its merge only adds the rest back;vardeclared again in a for-in/of head or a pattern), as an ordinary test. The swap turns it back into a pin, so the change from main's behaviour shows in the swap's diff.18 passing tests stay out, because they share a table cell with failing ones. Cutting them would need a per-bundler condition in the test, so they come with the fix.
Only tests that pass on main
There are no new
.failspins and no skipped tests. A test that fails on main comes with the PR that fixes it.CI wiring
test:unitis the fast tier. It runs in process, with client checks in Chromium pages.test:integrationis the slow tier: real builds, Rsbuild dev servers, child Node runs and browsers. It runs two Vitest projects,integrationandintegration-pages.test:integrationas four shard targets,test:integration--shard-<i>-of-4(Vitest--shard). They run one after another on a machine, are spread over CI's agents, and each is cached on its own.test:integration:wholeruns the tier in one Vitest run, for file filters and budget measurements.test:integrationtarget default innx.json(andtest:unitignorestests/integration/**),parallelism: false, and at most 4 workers.pnpm test:pralready runstest:integration.compiler-test-utilshas its owntest:unitandtest:integration(the harness self-tests).test:unitopens pages.sassbump (^1.105.1). Otherwise pnpm resolves two copies ofviteandvitestfor the harness and the plugins.ad808b6(an element read while detached,"", on a plain-CSS element) passed 3/3 locally on this branch and on main, and 40/40 under load, so I re-ran it.Main's tests that stay run in their own
unit-mainproject, as they always did: sequential, and with the generator's temporary files in the package. These are:add-hmr,handle-route-update,react-refresh-route-components,router-plugin-context, and the Solid/Vue and webpack HMR tests ofcode-splitter-plugin-pipeline;config;production-warnings(see below).What's deleted, and coverage
Deleted: main's Babel-specific splitting tests that the new ones replace.
shared-bindings-helpers,utilsanddelete-nodes(with its 32 snapshot files).code-splitter-dead-code,-imports-exports,-module-stateand-plugin-pipeline, except its HMR tests and its malformed split id test).production-warnings(fix(router-plugin): omit browser warnings from production bundles #8269) that the slice asserts:mode: 'production', in integrationknown-bugs-code-splitter-client-output"production builds", on webpack and Rspack, withNODE_ENVunset and set. The page logs nothing, and the component is split or the build warns. Its case withoutmodehas no equivalent in refactor(compiler)!: replace Babel with a Yuku-based compiler core for Router and Start #8817's tests, so it stays.source-maps(fix(router-plugin): point split routes' source maps at the route file #8860): integrationbuild-map-sourcesasserts that every map of a webpack or Rspack build (production and development) names the route file, never?tsr-split;build-source-mapsanddev-source-mapscover the line mapping and Vite dev.code-splitter-jsx,-pragmas,-route-options,-scope,-runtimeandesbuild, replaced at the same paths by refactor(compiler)!: replace Babel with a Yuku-based compiler core for Router and Start #8817's.Coverage was measured with V8 line and branch coverage, on the same denominators, over router-plugin's tests. Main's suite today is compared with the suite after this PR:
core/code-splitter/compilers.tscore/router-code-splitter-plugin.tscore/code-splitter/framework-options.tscore/code-splitter/plugins/*core/router-generator-plugin.tscore/utils.tsNo file covers less. To get there, two of main's tests stay, because the new suite doesn't reach their code yet:
code-splitter.test.ts, cut down to the 4 inputs that cover it:using.tsx: the one-callcreateFileRoute({ … })form;boolean-null-literals.tsx;retain-exports-destructured.tsx:export const { a } = …;destructured-export-multiple.tsx.The cut file also keeps the Solid input, and the React Refresh lowercase-rename test (HMR).
detect-route-codesplit-groupings.test.ts: groupings read from the one-call form.Lines only main's suite still reaches:
compilers.ts:51(removeBindingsDependingOnRoute, which only tests call), androuter-code-splitter-plugin.ts:224(the error for a split module id without a split value), which the keptcode-splitter-plugin-pipelinetest covers.CI cost
Measured locally: Nx, dependencies already built, 4 workers, 3 runs. Peak memory is the summed PSS of the process tree, Chromium included.
test:unit(main today)test:unit(this PR)test:integration(new), as 4 shards in sequencetest:integration:whole(one Vitest run)test:unit(new)test:integration(new)That is about 115 s of test time on one machine, against 9 s today. On CI the shards run on separate agents. Before sharding, CI took 3 m 58 s for router-plugin
test:integrationon one agent.CI on this PR: main's build was broken (fixed by #8907)
Before #8907, main itself didn't build. These jobs fail on
start-plugin-core:buildwithsrc/rsbuild/virtual-modules.ts:602: TS2552: Cannot find name 'paths':The client-side benchmarks pass because they don't build Start. Main's own Bundle Size, Benchmarks and Release runs on
c156097786fail with the same error.The cause is two of today's Start PRs crossing:
pathsbinding withpathsOf();tryWriteModule(…, paths.manifest, …)inupdateManifest.pathsOf().manifestat that line makes the build pass locally. The fix belongs on main, not in this tests-only PR.On every Compiler Platforms job (Windows x64, macOS arm64, Linux arm64, Linux x64 musl), the steps this PR adds pass: Chromium installs, and router-plugin's
test:unitpasses (234/234 on33bf9b5). The failure is the later "Production builds" step, which builds Start.Bundle Size: Rsbuild module ids only, no code change
The Bundle Size job reports +6 B raw (+8 to +12 B gzip) for
react-start.rsbuild.{minimal,minimal-iife,full}; the Vite scenarios are unchanged. No built code changes. Only Rspack's module and chunk ids move:sass1.97.2 with 1.105.1 in the css-modules e2e apps.vite, so every package withvitein its peer chain gets a new.pnpmdirectory name.unplugin3.7.0, which provides the router plugin's Rspack loader, moves fromunplugin@3.7.0_…_f1bc3eee…tounplugin@3.7.0_…_e5f03c08….70bbd11025and this branch:sourcesare identical);9on main and"w"here (+2 B per use).#8817 takes the same sass bump, so it will show the same shift.
Re-sync with #8817
5bd66855c3Applied from #8817 since
294b3f36e1:nx.jsondefaults;browser.ts,test-scope.ts,test-scope-setup.ts);SPEC.mdand the harness notes.Not applied:
hmr-sync.ts's newerrorsOutsideReloads, used only by Start's route-edit tests;code-splitter-effect-timingtests (6) and the changedcode-splitter-kept-reports(4), which fail on main in both runs.#8817 removed or renamed no test in this slice.
Re-sync with #8817
ac17b427d3Main is merged in (
e7358c36d8: pnpm 12, the RSC bump). The lockfile is main's, regenerated with pnpm 12. pnpm 12 merges a version a package names directly into other packages' ranges, so two ranges differ from #8817's to leave every other package resolving as on main: the harness'sesbuild(^0.28.1) and router-plugin's@babel/preset-typescript(7.27.1). Outside the slice's packages, only the css-modules apps' sass bump changes.Applied from #8817 since
5bd66855c3:pinsandrun-directorycontrols;integrationProjectrefactor of router-plugin's Vitest config;build-map-sources,build-js-extension-assets,code-splitter-other-names,-pure-framework-calls(Vue, Solid),-unreadable-loader,-value-own-writes,-const-chains,-effect-timing(decorators),vite-unanalysed-modules, 14 new shapes ofcode-splitter-state-read-at-load, one effectful-declaration row.Not applied:
build-source-maps,plugin-options(esbuild) andcode-splitter-route-options(object loaders with a spread), the 5 failing state-read shapes, the failing rows of the new files;test-scope-setup's compiler-stats check and theTSR_COMPILER_STATSknob;compilerSelfChecksNx input (its smoke target and its compiler's self-checks).Mirrored: #8817 deletes
code-splitter-reexported-factory.test.ts. Main passed it only by accident: its compile crashes on a duplicatecreateFileRouteimport, and the crash's code frame contains the expected text.Review fixes (independent review, 2026-11-12)
Each item was checked on this branch first, then fixed:
AGENTS.mdpointed at the deleted snapshot suiteloadRoute/build,targetFrameworkand theunit-mainproject301cbd8896esbuild.test.tsasserts main's error text forautoCodeSplitting: true; the build test's "Bug:" comment says refusing is valid76f0a4d38ecode-splitter-plugin-pipeline.test.ts(Vite HMR handling appended, route unchanged)7083a064ffThe split value for the virtual route…7083a064ffKNOWN-BUGS.mddrops the 9 rows nothing here cites; the harnessAGENTS.mdand the known-bugs headers say what holds on mainc035cbc3f2TSR_COMPILER_VERIFYand its self-test, the harness's Nx dependency on@tanstack/history, other packages' budgets,hmr-syncexcepttrackRequests, anddeterminism's reordering helpers with their self-tests.describeHmrstays: the dev-server self-tests use itc051f66f56openPageleaked its slot and context when a page failed to open;runInBrowsercould wait forever52f98bdf02code-splitter-extracted-export-chunkingmixed cases and read an internal query32cc29c26broute-unrecognized-fixesb326834dc0SPEC.mdis unchanged, as #8817 has it)ad808b62a9ifin page-side strings ofroute-app.ts34f9d75283oracle/README.md15a5c9bc7aNot changed:
unitnow (8.3–10.9 s before), under its 10 s. The reporter only reports.ac17b427d3" section explains both ranges.route-hmr-page.tsandtrackRequestsstay for the two refresh-pragma tests (split vs unsplit after an edit). They are good tests, and the harness file is refactor(compiler)!: replace Babel with a Yuku-based compiler core for Router and Start #8817's as is.F4: which branch the either-or tests take on main. I logged each test's branch with temporary instrumentation (not committed):
imported-options: the route works;route-redeclared: refused with an error on Vite and Rspack;errorComponentshapes: 4 lazy, 1 reported;production-warnings: not split, warns, on Rspack and webpack.Each test still asserts something useful on main. A refusal must be a build error that names the cause, never a broken page or a silent unsplit build.
For #8817: take the S7 fix and its self-tests (
52f98bdf02:src/browser.ts,src/build-harness.tsand two harness self-tests; it applies to #8817's copies of those files), and retitle "a namespace of types only stays out of every chunk" there too. Everything else conflicts on paths #8817 already owns, and resolves to its side or to deletion as before.Validation at
ad808b62a9(maine7358c36d8, no newer commit):test:unit,test:typesandtest:eslintfor router-plugin, router-utils and compiler-test-utils: 18/18.start-plugin-core:buildpasses.Relation to #8817
I merged this branch into
mainlocally, then test-merged #8817's head (ac17b427d3) on top. That gives 74 conflicts, and each one resolves to #8817's side:nx.json, the workflow, router-plugin'spackage.json,vite.config.tsandeslint.config.js, the same-path test files, pluspnpm-lock.yamlandpackages/react-start-rsc/package.json, which are main (pnpm 12, fix(react-start-rsc): bump RSC bundler deps for RSC #8919) against refactor(compiler)!: replace Babel with a Yuku-based compiler core for Router and Start #8817;code-splitter.test.ts,code-splitter-plugin-pipeline.test.ts,regression-helpers.ts,router-plugin-context.test.tsandproduction-warnings.test.ts. Resolve by deleting them.With every conflict taken from #8817's side, the merged tree equals #8817's head except for main's commits #8817 hasn't merged yet (#8907, #8912, #8913, #8919) and the autofix bot's
labeler-config.ymlentries. Nothing from the slice differs.Still open for #8817: a webpack or Rspack production build without
modeof a route that exports a component ships no splitter warning (kept here asproduction-warnings.test.ts). #8817's no-moderows (build-production*.test.ts) compare against a no-modecontrol on a route without exports. The map-name gap is closed:build-map-sourcescovers it.🤖 Generated with Claude Code