Repository navigation
Commit fa0cf00
Stop the hero destroying its own model in StrictMode (#383)
* fix(bench): make a run prove which build it measured
Closes #355.
`bench:matrix` printed `Error: Port 4173 is already in use` and then ran the
entire matrix against whatever was already there — another worktree's
`preview:bench` — writing ordinary-looking artifacts that described a different
branch's code. On #327 that inverted a conclusion for hours: post-fix runs kept
reporting `partial`, which read as "your fix did not work" rather than "you are
measuring someone else's build".
The hole is in `waitForServer`: it asks whether SOMETHING answers, and a foreign
server answers instantly. Nothing downstream ever asked *what* answered.
`vite build` now mints a fresh id, writes it to `dist/bench-build-id.txt`, and
injects the same value into the bundle, which publishes it on `<html>`. Two
independent checks read it:
- `bench-matrix.mjs` fetches the id from the server before running anything, so
a collision fails in the first second with the port to look at rather than
after a full matrix.
- `bench.spec.ts` compares the served id to `dist/` before it measures, so a run
driven any other way — directly, from an editor, with a hand-set BASE_URL —
gets the same protection.
A git SHA cannot do this job: the tree is dirty for most of a development loop,
so the SHA is identical across builds that differ. A per-build id answers the
question actually being asked, and catches a stale `dist/` and a forgotten
rebuild as well.
`PRETABLE_BENCH_SKIP_BUILD_CHECK=1` opts out when the target is deliberately not
a local build.
Verified against the live collision that motivated it — the other worktree's
server still holding 4173:
Error: http://127.0.0.1:4173 is not serving the build this checkout just produced
expected (dist/): 03f00ae1-…
served: (no id — an older build, or not a bench server)
Check `lsof -ti:4173`.
and no benchmark ran. The spec-level check was mutation-tested the same way, by
pointing it at a server serving a different id. A pre-check build reports no id
rather than its index.html, because the preview server falls back to that page
for anything it cannot find — only an id-shaped token counts as an answer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(website): stop the hero destroying its own model in StrictMode
Closes #382.
Loading the site in `next dev` rendered no grid at all — one page error before a
single row painted:
RowLayoutControllerError: A disposed row-layout controller cannot change its
columns. at usePretableModelInternal.useLayoutEffect at HeroGrid
The hero holds its row model in `useState` and disposed it in an effect cleanup:
useEffect(() => () => rowModel.dispose(), [rowModel]);
StrictMode mounts, unmounts and remounts every component in dev, and `useState`
hands the same instance back — so the rehearsal unmount destroyed the model
permanently. The layout controller then marked itself disposed through its
model-subscription failure path and threw out of a layout effect. Bisected: the
grid has rendered nothing in dev since #321, on every consumer with StrictMode
on, which is Next's default.
Disposal is now deferred by a microtask and cancelled by the remount — the same
shape `usePretable` already uses for the models it owns. A real unmount has no
remount to cancel it, so the model is still disposed.
Fixing that surfaced a second StrictMode fault behind it: the reduced-motion
seed ran `applyTransaction({ add })` twice against a model that now survives the
rehearsal, throwing "Row ID NVDA already exists". Seeding is now one-shot.
`setRows` would be the idempotent call, but it settles through the model's
rebuild rather than committing in place, which leaves the snapshot empty for
that frame — and a settled snapshot that paints nothing is the whole failure
that branch exists to avoid.
Why no test caught either: every website e2e run is against `next start`, a
production build, where StrictMode does not double-invoke. The suite was 100/100
green the entire time the dev grid was dead. The new test renders the hero inside
`<StrictMode>` and fails without the disposal fix with the exact production
error.
Verified in Chromium against the dev server, StrictMode on: `grids=1 rows=13`,
no page errors. The library is not at fault — the grouping fixture renders
correctly in dev throughout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>1 parent 6f8ae91 commit fa0cf00
2 files changed
Lines changed: 65 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
141 | 141 | | |
142 | 142 | | |
143 | 143 | | |
144 | | - | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
145 | 156 | | |
146 | 157 | | |
147 | 158 | | |
| |||
219 | 230 | | |
220 | 231 | | |
221 | 232 | | |
222 | | - | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
223 | 259 | | |
224 | 260 | | |
225 | 261 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| |||
111 | 112 | | |
112 | 113 | | |
113 | 114 | | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
114 | 141 | | |
115 | 142 | | |
116 | 143 | | |
| |||
0 commit comments