Skip to content

Merge main into upgrade-solidjs-rc-0 - #8059

Merged
birkskyum merged 49 commits into
solid-router-v2-prefrom
upgrade-solidjs-rc-0-main-merge
Aug 13, 2026
Merged

Merge main into upgrade-solidjs-rc-0#8059
birkskyum merged 49 commits into
solid-router-v2-prefrom
upgrade-solidjs-rc-0-main-merge

Conversation

@brenelz

@brenelz brenelz commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Merges main into the Solid 2 rc branch and resolves ~90 conflicts.

Resolution summary

package.json (~75 files): kept the rc versions for the Solid family (solid-js, @solidjs/*, @tanstack/solid-*, @rsbuild/plugin-solid, catalog entries) and took main's newer versions for everything else (@tanstack/router-plugin ^1.168.30, @tanstack/history ^1.162.1, @tanstack/react-router ^1.170.27, etc.), unioning keys added by only one side.

CHANGELOGs: kept the 2.0.0-* entries, matching how previous main merges on this line were resolved.

Benchmarks (13 main.tsx files): kept Solid 2 imports (render from @solidjs/web) and adopted main's RouterHistory import from @tanstack/history.

Source files — ported main's changes onto the Solid 2 rewrites:

@tanstack/router-core and @tanstack/solid-router + @tanstack/solid-start-client pass tsc typechecks; lockfile verified consistent via pnpm install --lockfile-only.

🤖 Generated with Claude Code

Sheraff and others added 30 commits August 5, 2026 15:21
ci: changeset release

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(router): preserve raw params for match identity

* refactor(router): return matched routes as tuple

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix(react-router): prevent blank initial pending frame

* test(react-router): remove obsolete issue 4759 unit test

* alternative fix

* ci: apply automated fixes

* simplify code comment

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* test disabled viewport links in Vue

* test reactive intersection observer disabling

* pass intersection observer disabled state directly

* changeset
* test createFileRoute factory behavior

* create file routes directly

* preserve createFileRoute parameter name

* cleanup

* changeset
* perf(history): compact queued action kind

* perf(history): compact queued navigation state

* perf(history): derive queued action state

* perf(router-core): tuple lightweight route matches

* perf(solid-router): compact nearest match context

* perf(vue-router): reuse the computed scripts tuple

* perf(vue-router): flatten private href input

* perf(vue-router): flatten private active-state input

* perf(vue-router): flatten private style input

* perf(start): return fetch bodies without an internal wrapper

* test(history): cover browser action batching

* docs: record compact private boundary results

* Delete RESULT-optimization-compact-private-boundaries.md
ci: changeset release

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(router): retain mounted UI during revalidation

* fix(router): preserve initial pending presentation

* changeset

* test(router): make retained pending tests deterministic

* complete solid/vue suite
ci: changeset release

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…7978)

* perf(start-client-core): compact frame decoder result keys

* docs: record compact frame result evidence

* docs: record frame result attribution and e2e

* Delete RESULT-optimization-frame-decoder-compact-result.md

* changeset
* perf(solid-start): shorten private prefetch state

* perf(start): use locals for hydration wait state

* perf(start): compact visible observer registry entries

* test(start): cover hydration private-state lifecycles

* docs: record solid hydration bundle result

* Delete RESULT-optimization-solid-hydration-private-state.md

* changeset

* ci: Version Packages (#7993) [Self-Healing CI Rerun]

---------

Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
…state are unchanged (#7952)

* perf(react-router): bail out of Link re-renders when href and active state are unchanged

useLinkProps subscribes to the location store with an identity selector and an
href comparator, then derives href and isActive from the published location in
downstream memos. The comparator can only ask "is this a different URL?", never
"does this link care?", so every Link on the page re-renders on every navigation.

Move the location-derived values into the selector and compare them, so a link
whose resolved href and active state are unaffected by a navigation bails out.
buildLocation still runs once per link per location change; what goes away is the
React render and the host reconciliation under it.

doPreload no longer pre-supplies _builtLocation, because the built location is no
longer kept in render state. preloadRoute already falls back to building it, which
is what handleClick has always relied on for router.navigate.

The isActive and externalLink bodies move to module-level helpers unchanged so the
selector stays readable; activeOptions is spread into its four primitive fields in
the dependency list because callers routinely pass an inline object literal.

* refactor: trim redundant comments and brace single-line bodies

The comments explained the bail-out rationale twice — once on the LinkState type
and again above the selector — and two helper docblocks restated their function
names. The rationale now appears once, where a reader meets the selector; the
detail belongs in the PR description rather than the source.

Also braces the three single-line if bodies, per the AGENTS.md rule that if/else
bodies always use curly braces.

* refactor: publish link state as a tuple

The type is erased either way, but the object literal's property names survive
minification and a tuple's positions don't — so this drops three property names
from the selector's return plus the three property reads in compareLinkState.

Measured on the unminified build: -54 bytes in dist/esm/link.js and the same in
dist/cjs/link.cjs.

* test: assert the published link state, and drop a redundant cast

The render-count assertions proved the bail-out but not that the selector still
publishes correct values, so a selector returning a constant could have passed.
The test now also asserts that the link gaining active state carries
`data-status="active"` afterwards (and does not beforehand), and that the
unaffected link keeps its href and stays inactive.

Checked by sabotaging the selector: returning a constant tuple with a wrong href
but a correct active state now fails, where previously it passed.

Also drops `as any` from `new URL(to)` in resolveExternalLink — the guard above
already narrows `to` to string.

* refactor: pass activeOptions through instead of destructuring

Depends on the four fields rather than the object, with an exhaustive-deps
disable: callers routinely pass an inline literal, which would otherwise rebuild
the selector every render. resolveIsActive reads only those four fields, so the
disable is not hiding a live dependency.

-269 bytes on each of dist/esm/link.js and dist/cjs/link.cjs (unminified).

* perf: memoize the href derivation on the built href

The `useMemo` chain this replaced keyed `getHrefOption` and the external-link
resolution on the href string, so a navigation that left a link's href alone
skipped both. Deriving everything in the selector ran them on every location
notification instead, which showed up as a ~10% regression on the client-nav
rewrites benchmark, where rewrite handling makes `getHrefOption` expensive.

Cache both on the built href inside the selector closure. Measured on a
five-link root layout, per navigation: getHrefOption drops from 5 calls back to
0, matching the pre-change profile, with buildLocation and the active-state
derivation unchanged at 5.

* perf: keep _options referentially stable while its contents are equal

Links commonly pass inline `params` / `search` object literals. Those change
identity on every parent render, which rebuilt `_options`, which changed the
store selector's identity, which discarded useSyncExternalStoreWithSelector's
memoized selection. buildLocation then ran twice per navigation: once in the
notification check and once in the render-phase selection.

Measured on a replica of the client-nav rewrites scenario (six links, root
subscribed to the pathname via useLocation), buildLocation per navigation:
base 7, before this commit 12, after 7.

* revert: drop the href memoization, it measured no benefit

Reverts 409371b. It did cut getHrefOption from 5 calls per navigation to 0,
matching the pre-change profile, but that is not where the time went: on the
rewrites scenario it moved the number by 0.05% (medians 245.33 vs 245.21 hz over
four interleaved rounds). Not worth ~15 lines of mutable closure state.

The rewrites regression is fixed by the _options stabilisation instead.

* docs: explain why useValueStable exists

Replaces a leftover scratch note.

* perf: cut the bundle cost of the link state selector

Stabilise `activeOptions` with the same helper used for `search` / `params`,
so the selector depends on one value instead of four destructured fields. That
also makes the dependency array honest, so the exhaustive-deps disable goes.

Drop the reference-equality guard in useValueStable: deepEqual already
short-circuits on `a === b`, so the guard only saved a function call that
returns immediately.

Measured with benchmarks/bundle-size against this branch's base, gzip delta
across the eight React scenarios moves from +27/-7 to +11/-24, and raw bytes go
uniformly negative (-37 to -45 on every scenario).

* perf: pass _options to preloadRoute without the shallow clone

The spread existed to add _builtLocation, which is gone, and nothing on the
preload path mutates the options object: preloadRoute only reads
opts._builtLocation, build() only reads dest fields, and the search middleware
chain only reads dest.search. Search middlewares themselves receive
{ search, next }, never dest.

Saves an object allocation per hover. Bytes are unchanged on gzip, -5 raw.

* fix: do not collapse explicit-undefined params when stabilising link options

useValueStable compared with deepEqual's default ignoreUndefined: true, which
skips undefined-valued keys on both sides, so `{}` and `{ category: undefined }`
compared equal. Those build different locations: an explicit undefined clears an
inherited optional param while an empty object inherits it. A Link whose params
changed from one to the other kept publishing the stale href, and click and
preload used the stale options too.

Compare with ignoreUndefined: false. Adds a regression test covering the
/posts/tech -> /posts transition, which fails before this commit and passes
after, and passes on the pre-PR baseline.

* chore: empty commit to re-trigger CI

* chore: add changeset

---------

Co-authored-by: Flo <me@florianpellet.com>
ci: changeset release

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…ring (#8010)

* perf(router-core): faster enumerable-key collection in structural sharing

getEnumerableOwnKeys (used by replaceEqualDeep) called
Object.getOwnPropertyNames and then invoked propertyIsEnumerable once per
key to verify every own string prop is enumerable. Replace that O(n) loop
of JS method calls with Object.keys (native, enumerable-only) plus a
single length comparison against getOwnPropertyNames to detect
non-enumerable string props. Symbol handling is unchanged.

Behavior is identical (verified against the existing suite + fuzzing): the
function still returns the enumerable own keys in the same order and still
bails (returns false) for objects with any non-enumerable own string or
symbol property.

replaceEqualDeep runs on every selector result on every state update when
defaultStructuralSharing is enabled, so this is a hot client path for
selector-heavy apps. Measured ~1.3-1.5x faster on typical router state.

* style(router-core): address enumerable key review

---------

Co-authored-by: Yagiz Nizipli <yagiz@nizipli.com>
…8009)

The frame decoder dropped consumed chunks from its buffer with
bufferList.shift(), which is O(n). When a single large frame (e.g. a big
RawStream payload) is assembled from many small network reads, the
extract loop calls shift() once per chunk, making reassembly O(n^2).

Track the first un-consumed chunk with a head pointer and advance it in
O(1) instead of shifting. Consumed slots are released for GC, and the
buffer is compacted when fully drained (O(1) reset) or once the consumed
prefix grows past a small threshold (amortized O(1) per chunk).

A micro-benchmark draining 1000 small chunks is ~11x faster.

Co-authored-by: Yagiz Nizipli <yagiz@nizipli.com>
* perf(router-core): skip impossible JSON parses

* perf(router-core): refine JSON parse fast path

* changeset
ci: changeset release

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(router-core): handle excessive parent relative links

* changeset
ci: changeset release

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@nx-cloud

nx-cloud Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 6cb3c50

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 12m 17s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 2m 4s View ↗

☁️ Nx Cloud last updated this comment at 2026-08-13 04:41:54 UTC

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

No changeset entries found. Merging this PR will not cause a version bump for any packages.

@socket-security

socket-security Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​rolldown/​plugin-babel@​0.2.37310010089100
Addedbabel-plugin-react-compiler@​1.0.01001007990100

View full report

autofix-ci Bot and others added 3 commits August 13, 2026 04:12
The #8002 fix itself is merged; its changeset stays on main for the 1.x
release and would otherwise trigger a stray vue-router/solid-router bump
in the rc pre-release.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…/router into upgrade-solidjs-rc-0-main-merge
@codspeed-hq

codspeed-hq Bot commented Aug 13, 2026

Copy link
Copy Markdown

Hooray! CodSpeed harness just leveled up!

The base and head of this comparison were measured with different runner settings, so their benchmark values are not directly comparable.

What changed between base and head:

Re-run the base with the same settings to get a valid performance comparison.


Comparing upgrade-solidjs-rc-0-main-merge (6cb3c50) with upgrade-solidjs-rc-0 (9b77320)

Open in CodSpeed

The merge kept the rc branch's lockfile, which had drifted: @babel/traverse
resolved @babel/types 7.29.8 while router-plugin's direct dep stayed 7.28.5,
so main's new code-splitter code failed to typecheck in CI. Re-resolving from
main's lockfile (green with that code) plus the merged manifests restores a
consistent babel graph.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Bundle Size Benchmarks

  • Commit: b394f46d3840
  • Measured at: 2026-08-13T04:30:41.238Z
  • Baseline source: history:38485038c52f
  • Dashboard: bundle-size history

The following scenarios have bundle-size changes compared with the baseline:

Scenario Current (gzip) Delta vs baseline Initial gzip Raw Brotli Trend
solid-router.minimal 39.24 KiB +6.07 KiB (+18.31%) 39.12 KiB 112.36 KiB 35.47 KiB ▁▁▁▁▁▁▁▁▁▁▁█
solid-router.full 44.11 KiB +6.12 KiB (+16.10%) 43.99 KiB 127.69 KiB 39.85 KiB ▁▁▁▁▁▁▁▁▁▁▁█
solid-start.minimal 57.87 KiB +11.92 KiB (+25.93%) 57.74 KiB 168.94 KiB 51.80 KiB ▁▁▁▁▁▁▁▁▁▁▁█
solid-start.deferred-hydration 61.55 KiB +12.52 KiB (+25.54%) 58.27 KiB 177.06 KiB 55.24 KiB ▁▁▁▁▁▁▁▁▁▁▁█
solid-start.full 61.63 KiB +10.60 KiB (+20.78%) 61.50 KiB 180.29 KiB 55.15 KiB ▁▁▁▁▁▁▁▁▁▁▁█

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.

@brenelz
brenelz requested a review from birkskyum August 13, 2026 04:31
@pkg-pr-new

pkg-pr-new Bot commented Aug 13, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@8059

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/@tanstack/eslint-plugin-router@8059

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@8059

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@8059

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/@tanstack/nitro-v2-vite-plugin@8059

@tanstack/react-router

npm i https://pkg.pr.new/@tanstack/react-router@8059

@tanstack/react-router-devtools

npm i https://pkg.pr.new/@tanstack/react-router-devtools@8059

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/@tanstack/react-router-ssr-query@8059

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@8059

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@8059

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@8059

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@8059

@tanstack/router-cli

npm i https://pkg.pr.new/@tanstack/router-cli@8059

@tanstack/router-core

npm i https://pkg.pr.new/@tanstack/router-core@8059

@tanstack/router-devtools

npm i https://pkg.pr.new/@tanstack/router-devtools@8059

@tanstack/router-devtools-core

npm i https://pkg.pr.new/@tanstack/router-devtools-core@8059

@tanstack/router-generator

npm i https://pkg.pr.new/@tanstack/router-generator@8059

@tanstack/router-plugin

npm i https://pkg.pr.new/@tanstack/router-plugin@8059

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/@tanstack/router-ssr-query-core@8059

@tanstack/router-utils

npm i https://pkg.pr.new/@tanstack/router-utils@8059

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/@tanstack/router-vite-plugin@8059

@tanstack/solid-router

npm i https://pkg.pr.new/@tanstack/solid-router@8059

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/@tanstack/solid-router-devtools@8059

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/@tanstack/solid-router-ssr-query@8059

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@8059

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@8059

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@8059

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@8059

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@8059

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@8059

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@8059

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/@tanstack/start-static-server-functions@8059

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@8059

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@8059

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@8059

@tanstack/vue-router

npm i https://pkg.pr.new/@tanstack/vue-router@8059

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/@tanstack/vue-router-devtools@8059

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/@tanstack/vue-router-ssr-query@8059

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@8059

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@8059

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@8059

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@8059

commit: 6cb3c50

Base automatically changed from upgrade-solidjs-rc-0 to solid-router-v2-pre August 13, 2026 10:07
@birkskyum
birkskyum merged commit 1bdceb6 into solid-router-v2-pre Aug 13, 2026
25 of 27 checks passed
@birkskyum
birkskyum deleted the upgrade-solidjs-rc-0-main-merge branch August 13, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment