From f7fef95c0396fbc7f3fdd3662a699cb9def06296 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 02:43:33 +0000 Subject: [PATCH] docs: onFlush and the hydration tracking run in the skill and cheatsheet; cached import() note (#4332) - solid-2.0 skill: land a write on its own with onFlush; never cache a promise or import() created inside a compute (hydration's tracking run). - CHEATSHEET: onFlush import and example; hydration adopts server answers, a hydrated Errored keeps the server fallback, no promise caches in computes. - 05-async-data: a cached dynamic import() under Vite's __vitePreload is the fake Promise too (#4332). - babel-plugin README: runs on @babel/core 7.20.12+ and 8. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0117BoWLQXHbGurmfMSCBeKX --- documentation/solid-2.0/05-async-data.md | 2 ++ packages/babel-plugin/README.md | 2 ++ packages/solid/CHEATSHEET.md | 17 ++++++++++++++++- packages/solid/skills/solid-2.0/SKILL.md | 8 ++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/documentation/solid-2.0/05-async-data.md b/documentation/solid-2.0/05-async-data.md index b0a8044871..2a83aa834e 100644 --- a/documentation/solid-2.0/05-async-data.md +++ b/documentation/solid-2.0/05-async-data.md @@ -269,6 +269,8 @@ const user = createMemo(() => { // `Promise.resolve(value)` inside the compute is the fake too, and never settles either. ``` +A cached dynamic `import()` hangs the same way ([#4332](https://github.com/solidjs/solid/issues/4332)). In a Vite build every `import()` goes through `__vitePreload`, which starts from `Promise.resolve()` read off the global at call time, so the module promise stored in a de-duplication map during the tracking run is the fake. The memo itself hydrates from the server's value, so the page looks right; the next caller that hits the map (a later mount, a navigation) waits forever and no request for the chunk is made. Use `lazy()` for components (it already refuses to cache a load made during a trace), and keep a module cache out of hydrated computes or apply the rule below. + The rule for a cache seeded from hydration data: while `isHydrating()` (`solid-js`) is true, treat the seeded value as fresh, and do not populate the cache by running the fetcher. To wrap a hydrated value in a real promise, capture the constructor at module load. The fakes only replace the global inside the window. ```js diff --git a/packages/babel-plugin/README.md b/packages/babel-plugin/README.md index a54765e9c8..2833416081 100644 --- a/packages/babel-plugin/README.md +++ b/packages/babel-plugin/README.md @@ -4,6 +4,8 @@ Solid 2.0's Babel compiler integration. Configure this plugin once in a Babel pi The native Oxc compiler — [`@solidjs/compiler`](../compiler) — is the default in `vite-plugin-solid`. Use this plugin when you need a Babel pipeline (or as the JavaScript fallback). +It runs on `@babel/core` 7 (7.20.12 or later) and 8. + > **Solid 2.0 (Release Candidate).** Pin exact versions. ## Features diff --git a/packages/solid/CHEATSHEET.md b/packages/solid/CHEATSHEET.md index 653e4ed7a7..a8e91c33af 100644 --- a/packages/solid/CHEATSHEET.md +++ b/packages/solid/CHEATSHEET.md @@ -40,6 +40,7 @@ import { untrack, flush, onSettled, + onFlush, createContext, useContext, children, @@ -140,7 +141,19 @@ onSettled(() => { }); ``` -`onSettled` works in component bodies (after first reactive settle) **and** in event handlers (defer work until the triggered transition settles). For component-level setup-and-teardown, **use `onSettled` with a returned cleanup, not `onCleanup` directly** — `onCleanup` is reserved for reactive cleanup inside computations (see Advanced). +`onSettled` works in component bodies (after first reactive settle) **and** in event handlers (defer work until the triggered transition settles). + +```ts +// Keep a write out of another update's hold: runs once right after the +// pending flush, never waits on async. For event handlers and effect +// callbacks (dev warns ON_FLUSH_IN_OWNED_SCOPE in a body or computation). +const select = (id: string) => { + onFlush(() => setOpen(false)); // closes now even if onSelect navigates + props.onSelect?.(id); +}; +``` + +For component-level setup-and-teardown, **use `onSettled` with a returned cleanup, not `onCleanup` directly** — `onCleanup` is reserved for reactive cleanup inside computations (see Advanced). --- @@ -573,6 +586,8 @@ return
  • ; import { renderToString, renderToStream, isServer, isDev } from "@solidjs/web"; ``` +Hydration adopts each async read the server answered (value or error) and never asks again; a hydrated `` keeps the server's fallback until an input changes or `reset()`. Adopted computes still run once to track reads, with the global `Promise` and `fetch` faked (never settle): don't cache promises or `import()`s created in a compute. + `Portal` throws on the server. `Reveal` `order="together"` and `collapsed` require streaming (`renderToStream` — awaiting it yields the fully settled HTML string). --- diff --git a/packages/solid/skills/solid-2.0/SKILL.md b/packages/solid/skills/solid-2.0/SKILL.md index 9b971e38f6..d4cab765eb 100644 --- a/packages/solid/skills/solid-2.0/SKILL.md +++ b/packages/solid/skills/solid-2.0/SKILL.md @@ -62,6 +62,14 @@ Also: The memo's `equals` (default `===`) stops the re-run. - No writes inside a memo, effect compute, or component body (dev throws). Write from event handlers, `onSettled`, or actions. +- Writes in one synchronous frame land together: if one starts async work + (a navigation, a refetch), the rest are held with it. To land a write on + its own (close a menu before calling `props.onSelect`), wrap it in + `onFlush(() => setOpen(false))`. Not `queueMicrotask` or `setTimeout`. +- Hydration adopts server answers without re-asking, but runs each adopted + compute once to track reads with fake `Promise`/`fetch` that never settle. + Never store a promise or `import()` created inside a compute in a cache + that outlives it; cache resolved values, or start the load outside. - No reactive reads at the top of a component body; read in JSX, a memo, or `untrack`. Flow callbacks (``, ``, ``) are owners, not tracking scopes: read their accessor arguments in JSX, not at the top.