fix(site): pre-bundle react-dom so dev islands hydrate#1711
Draft
decepulis wants to merge 2 commits into
Draft
Conversation
The Vite dev optimizer was serving react-dom/client as a raw CommonJS
module, so the @astrojs/react client renderer's
`import { createRoot, hydrateRoot } from 'react-dom/client'` failed to
link with `SyntaxError: Importing binding name 'createRoot' is not found`,
leaving every React island unhydrated in dev.
The React integration adds react-dom/react-dom/client to optimizeDeps
.include, but the site's own vite.optimizeDeps (which set only `exclude`
for @videojs/* and @resvg) shadowed that per-environment include, so
react-dom was never pre-bundled. Re-declaring the include here restores
the CJS→ESM interop wrapper. Dev only; the production Rollup build was
unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0189rofb2dpGEtCWDxZAmWxi
✅ Deploy Preview for vjs10-site ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📦 Bundle Size Report🎨 @videojs/html — no changesPresets (7)
Media (10)
Players (5)
Skins (30)
UI Components (38)
Sizes are marginal over the root entry point. ⚛️ @videojs/react — no changesPresets (7)
Media (9)
Skins (27)
UI Components (32)
Sizes are marginal over the root entry point. 🧩 @videojs/core — no changesEntries (14)
🏷️ @videojs/element — no changesEntries (2)
📦 @videojs/store — no changesEntries (3)
🔧 @videojs/utils — no changesEntries (10)
📦 @videojs/spf — no changesEntries (4)
ℹ️ How to interpretAll sizes are standalone totals (minified + brotli).
Run |
The tech-stack list still said Astro 5.14.4 (and stale Shiki/Vitest versions); the site moved to Astro 6.3.1 + Vite 7 in #946. Update the versions and add a "Dependency Optimization" note explaining why a root-level vite.optimizeDeps shadows a renderer integration's per-environment include under Vite's Environment API — the cause of the dev-only createRoot hydration failure. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0189rofb2dpGEtCWDxZAmWxi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
Running the site locally (
pnpm dev) renders but never hydrates. The console fills with:Every React island fails to hydrate. Dev only — production builds are unaffected.
Root cause
@astrojs/react's client renderer doesimport { createRoot, hydrateRoot } from "react-dom/client".react-dom/clientis a CommonJS module with no native ESMcreateRootexport, so in dev it relies on Vite's optimizer pre-bundling it into an ESM-interop wrapper. Here it was being served raw instead:Why
react-domspecifically wasn't pre-bundled:@astrojs/reactintegration addsreact-dom/react-dom/clienttooptimizeDeps.include, but as of Astro 6 / Vite 7 it injects them at the client-environment layer via Vite's Environment API (configEnvironment).astro.config.mjssetsvite.optimizeDeps(with onlyexclude, for@videojs/*and@resvg/resvg-js) at the root/shared config layer.optimizeDepsshadows the integration's per-environmentinclude, soreact-domsilently dropped out of the optimized set.reactstill got pre-bundled (discovered via normal module scanning);react-dom/clientis only imported by the renderer that loads dynamically at hydration, so the scanner never saw it and — with theincludehint gone — it was served as raw CJS.That's why it was all islands and only in dev: the React DOM client renderer is the common dependency of every
client:*island, and dependency pre-bundling is a dev-server concern the production bundler doesn't rely on.When / why it broke
astro^5.14.4 → ^6.1.3(later^6.3.1in chore(site): upgrade astro to 6.3.1 #1499) and pulled in Vite 7 + the Environment API.experimental.fonts→ stablefonts, NetlifyenvironmentVariables). TheoptimizeDepsshadowing is an undocumented Vite-layer interaction — it only bites projects that both set a customvite.optimizeDepsand use a renderer integration that relies on per-environment includes, and only inpnpm dev. CI has no browser-hydration check against the dev server, so it went unnoticed for ~2 months.Fix
Re-declare the React DOM entries in the site's own
optimizeDeps.includeso they survive the merge regardless of which config layer the integration uses. After the fix the renderer links against the optimized dep with proper CJS interop:optimizeDepsonly affects the dev optimizer, so the production Rollup build is untouched.Verification (local, real browser)
Ran the actual dev server and loaded
localhost:4321in headless WebKit (matching the Safari error phrasing) before/after, against the real repo state:Also confirmed at the network level that the served renderer switched from importing raw
/@fs/.../react-dom/client.jsto the optimized/node_modules/.vite/deps/react-dom_client.js.Also in this PR
site/CLAUDE.mddocumented Astro 5.14.4 (plus stale Shiki/Vitest versions). Updated the tech-stack versions and added a "Dependency Optimization (Vite) — gotcha" note so the next person who editsvite.optimizeDepsor adds a renderer integration knows to include its client deps.Not in this PR (follow-up?)
The root
package.jsoncarries unusedreact@^18,react-dom@^18, andreact-compiler-runtime@^1devDependencies. Nothing at the root imports React, and they install a duplicate React 18 in a React 19 monorepo (which also makes the site resolvereact-compiler-runtimeto the React-18-bound copy). Removing them did not fix this bug, so I kept them out to stay focused — but they're stray and worth removing separately.🤖 Generated with Claude Code
https://claude.ai/code/session_0189rofb2dpGEtCWDxZAmWxi