Skip to content

fix: send server environments their reload signal on hot update - #282

Merged
birkskyum merged 2 commits into
solidjs:nextfrom
brenelz:fix/server-env-reload-signal
Jul 28, 2026
Merged

fix: send server environments their reload signal on hot update#282
birkskyum merged 2 commits into
solidjs:nextfrom
brenelz:fix/server-env-reload-signal

Conversation

@brenelz

@brenelz brenelz commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Problem

hotUpdate returns [] for every non-client environment. The intent (per the comment) is sound: solid-refresh only injects HMR boundaries into client modules, so letting Vite's propagation run in server environments dead-ends into full-reload messages that race client-side HMR.

But emptying the modules array also suppresses the only reload signal that environment-runner based servers rely on. With nitro's Vite integration (nitro/vite), SSR runs in a persistent module runner inside a dev worker — evaluated modules live until that environment's hot channel receives a full-reload. Vite's default dead-end propagation would send exactly that, but it never runs because the modules array arrives empty (and downstream plugins like nitro's own hotUpdate are blinded the same way, since Vite feeds each hook the previous hook's filtered array).

Net effect in a vite-plugin-solid + nitro app: edit any SSR-rendered module (every route component) → client updates via HMR, server keeps rendering the old module until a manual dev-server restart → hydration key/markup mismatches on the next load (unclaimed server nodes, and in our repro a Cannot read properties of null (reading 'nextSibling') crash during hydration).

Full investigation with traces: nitrojs/nitro#4472 (this plugin's role: comment). The staleness also needs a nitro-side fix for its worker reload (nitrojs/nitro#4473) — but without this change, the reload is never even requested.

Fix

Keep the suppression, but send { type: "full-reload" } on the environment's own hot channel first (when the changed file has modules in that environment's graph):

  • For runner-based environments (nitro's dev worker), the channel reaches the runner — SSR picks up the edit.
  • For the default ssr environment, the channel is a no-op — nothing changes.
  • It is never the browser websocket, so the client-HMR race the original code guards against stays suppressed.

Verification

Reproduced and verified against a Solid 2 + nitro/vite playground (vite 8.0.10, vite-plugin-solid 3.0.0-next.15, nitro 3.0.260610-beta with the nitrojs/nitro#4473 fix applied):

  • Before: editing a route component leaves SSR output byte-identical across reloads until the dev server restarts; hydration mismatches on reload.
  • After (this patch alone, no userland workarounds): consecutive edits are reflected in SSR within ~2s each, hydration is clean, and client HMR still applies edits in place with page state preserved (no full browser reloads).

pnpm build (rollup + tsc) passes.

Returning [] from hotUpdate for non-client environments suppresses the
full-reload messages that would race client HMR, but it also suppresses
the only signal environment-runner based servers (e.g. nitro's dev
worker) have for re-evaluating modules: with the modules array emptied,
Vite's dead-end propagation never fires the environment-level
full-reload, so SSR keeps serving stale modules until the dev server is
restarted — and hydration mismatches against the freshly HMR-updated
client.

Keep the suppression, but send the reload on the environment's own hot
channel first. For runner-based environments that channel reaches the
runner; for the default ssr environment it is a no-op; it is never the
browser websocket, so client HMR stays free of full-reload races.
@changeset-bot

changeset-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b8470ec

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
vite-plugin-solid Patch

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

@pkg-pr-new

pkg-pr-new Bot commented Jul 23, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/vite-plugin-solid@282

commit: b8470ec

@birkskyum birkskyum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changeset missing

@birkskyum
birkskyum merged commit 62d9a89 into solidjs:next Jul 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants