Repository navigation
fix(server): re-render live For rows that read async sources - #4069
Conversation
A sweep reused a row whenever its item looked unchanged, so a row that also read an async memo or projection (a selected id) kept stale markup, and an item edited in place compared equal to itself. Count reads of async sources (async memos, async projections, memos derived from them) and only reuse rows that made none; compare items against a deep copy taken when the row rendered. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VywmD8RauUVvMzG8pYPUX8
🦋 Changeset detectedLatest commit: 7c36f2b The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Size (brotli, eager entry chunk)
|
Coverage Report for CI Build 38633726246Coverage remained the same at 77.515%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Merging this PR will not alter performance
|
Requested by Ryan · project thread
Summary
Follow-up to #4057, which lets a server
Forinside a live hole reuse a row across sweeps when its item at the same index is unchanged.Before: reuse only looked at the item. A row that also read an async memo or projection outside its item, such as a "selected" mark driven by a selected id, kept the markup from the sweep that first rendered it, so the selection never moved. An item edited in place also compared equal to itself and kept its old row.
After: a row is reused only if it read no async source while rendering. Async sources are async memos, async projections, and memos derived from them. Items are compared against a deep copy taken when the row rendered, so an in-place edit renders the row again.
How (
packages/solid/src/server/signals.ts): async-source reads are counted. A memo compute takes a snapshot of the counter, and a memo read checks a flag. A sweep reuses a row only when its render made no such reads.Cost. Plain SSR pays one counter snapshot per memo compute and one flag check per memo read. The item copy and the row cache run only during live sweeps. The 5-run server bench lane showed only noise, so CodSpeed on this PR has the exact numbers. Size scenarios are unchanged: renderToString stays at 20,570 B, and the client bundles are untouched.
How did you test this change?
live-hole-for-rows-4056.spec.tsxgains cases for a row that reads an async memo or projection beside its item, and for an item edited in place. Each case now renders the row again on every sweep. Rows that read only their item are still reused.next@ 0109a56 afterpnpm build:solid-js860/860 pass.@solidjs/webDOM 1394/1394 and hydrate 506 pass. The web server suite has 1688 passing and 1 failure: the adapter-request "rebuild failure" test, which fails only on Node 22 in the cloud container and passes on Node 24, the version.nvmrcand CI use.scripts/size: renderToString is unchanged at 20,570 B / 72,373 minified.The fix was written in the "Diff payloads for live holes" thread, and this PR carries its patch unchanged.
🤖 Generated with Claude Code
https://claude.ai/code/session_01KRieFbP8sapvTBygyVm3mg
Generated by Claude Code