Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/server-component-hydration-installs-from-frames.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"solid-js": patch
"@solidjs/web": patch
---

The server-component half of hydration installs from `@solidjs/web/frames`' `installServerComponents()`, not from `hydrate()`: `sharedConfig.holdBoundary` (the client hold on adopted markup counted as a pending boundary), `sharedConfig.hydrateWindow` (the claim window an adopted occurrence re-enters hydration through), fragment ownership by rendering (the `_$HY.fa` term of the reveal policy) and the ledger's published answer `_$HY.fr` on the solid side; the declared claim roots (`sharedConfig.claimRoots`) and the frame-region exclusion of the root sweep on the DOM runtime's side. A hydrating page without server components carries none of it — −686 B minified / ≈ −205…−243 B brotli on the hydrating apps (this returns the bytes the frames A0 correctness pass added to every hydrating page); a server-component page pays the two installers' glue (≈ +220 B minified).

Public surface (`@internal`): `enableServerComponentHydration()` on `solid-js` (runtime) and `solid-js/internal` (typed), a no-op on the server entry; `installServerComponentHydration()` on `@solidjs/web`, which installs both halves — the frames client calls it where it installs its reveal hook.
7 changes: 7 additions & 0 deletions .changeset/store-hydration-adapters-ride-the-trace-chunk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"solid-js": patch
---

The store hydration adapters (`createStore(fn)` / `createProjection` / `createOptimisticStore(fn)` under hydration: snapshot adoption, the parked patch backlog, the hybrid handoff) move to their own source module, and `solid-js/internal/container-trace` — the frames traces tier's materializer, a lazy chunk — bundles its own copy of it instead of reading the eager slot `enableHydration()` fills through `withStoreHydration`. Reading the slot from the lazy chunk pinned every adapter into the entry chunk of a server-component page that never creates a client store (an app bundler keeps a module eager whenever an eager module imports it); the copy is inert by construction — the adapters declare no module-level state, and every piece of shared state is read back from the one `solid-js` instance. −2,550 B minified / ≈ −575 B brotli on the compiled server-component page; 0 on pages whose root pass creates a derived store (they keep the eager install); the lazy `trace.js` chunk grows ≈ 0.5 KB brotli.

Public surface (`@internal`, stripped from the declarations): `withStoreHydration` is removed from the `solid-js` client and server entries (its only consumer was the trace entry); the client entry gains the runtime exports the adapter copy reads — `readSerializedOrCompute`, `subFetch`, `readHydratedValue`, `wrapFirstYield`, `adoptedAnswerStream`, `withHydrationGate`, `onHydrationEnd`, `noHydrationId`, `markTopLevelSnapshotScope`, `hasLoadingWindow`, `isAsyncIterable`, `syncThenable`, `UNASKED` — mirrored on the server entry as inert stubs for export parity.
5 changes: 5 additions & 0 deletions .changeset/web-read-shallow-own-keys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/web": patch
---

`readShallow` (the compiler's one-layer tracked read of an object-valued `class`/`style`) reads a proxy's keys with `Reflect.ownKeys` directly — what `sourceKeys(value, SOURCE_PROXY)` resolves to by definition — instead of through `sourceKeys`, whose runtime kind argument kept the merge/omit view walkers of `@solidjs/signals` in every compiled page with a dynamic `class` or `style`, reached by nothing. Identical behaviour; −1,165 B minified / ≈ −350 B brotli on the compiled server-component page (a page with an element spread keeps the walkers through `spread()`).
10 changes: 10 additions & 0 deletions documentation/plans/frames-savings-pass.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,16 @@ Pages (br; the whole page, lazy chunks not counted):
| compiled hydrating | 30,943 (at its 30.93 cap) | **≈ 30,990** (the same +≈ 45) | 31,075 (+52 — Phase A's) | unchanged | +45 | **cap raise needed — the maintainer's** |
| frames eager | 13,770 | ≈ 7,600 (7.8 reading; the C6 gate is 8.5 before the residual R / D cuts land) / ≈ 8,150 (8.0) | **13,083** (40,000 min; **−704 br**; chunks `trace.js` 8,176 / `regions.js` 805 / `assets.js` 783 br, lazy) | **≈ 7,250 / ≈ 7,800** | **−6.5 KB (−47 %)** | ≈ 10,500 |

The hydration pass (2026-10-07, `size/hydration-pass`;
`hydration-split-measured.md`) returned the Phase A bytes to the plain
hydrating pages and more — `app: hydrating (no stores)` 17,894 → 17,689 br
and `compiled hydrating` 31,155 → 30,991 against `next` @ `d231b9911` — by
moving the server-component half of hydration (the hold, the claim window,
fragment ownership, `_$HY.fr`, the claim-roots walk and the frame exclusion
of the root sweep) behind `installServerComponents()`, and took `page:
compiled base SC` 35,146 → 34,321 br with the store hydration adapters as
the trace chunk's own copy and `readShallow` off the view walkers.

### 4.1 Measured (2026-10-06)

The Phase D estimates above, turned into numbers by a measurement pass on
Expand Down
Loading
Loading