Fix React #418 hydration errors and keep the copy-page button after navigation - #1261
Open
willeastcott wants to merge 2 commits into
Open
willeastcott wants to merge 2 commits into
willeastcott wants to merge 2 commits into
Conversation
Two third-party scripts changed the server-rendered HTML before React hydrated it: - redocusaurus provides prismjs for every free `Prism` reference, which puts Prism's core in the main bundle, and that core highlights every code block on DOMContentLoaded. Set `Prism.manual` from a client module. - docusaurus-plugin-copy-page-button inserts its button into the article or ToC 100 ms after DOMContentLoaded, often mid-hydration. Run it with `injectButton: false` and load its client module from the first `onRouteDidUpdate` instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plugin re-checks its button when the URL changes, but Docusaurus is still showing the old page then, so the button is left in place and goes with the old article when the new page replaces it. The plugin also re-checks on a `docusaurus-route-update` event that Docusaurus never sends, so send it from `onRouteDidUpdate`, which runs once the new page is in the DOM. Hash-only changes keep the same page and are skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
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.
Summary
Docs pages log a recoverable React #418 hydration error, and the Copy page button disappears after client-side navigation. On production the button is often missing on first load too, because React client-renders the mismatched tree and drops it. This PR fixes both problems.
#418: third-party scripts changing the SSR HTML before hydration
prismjsfor every freePrismreference in the bundle (webpackProvidePlugin). As a result, the Prism language components loaded forprism.additionalLanguagespull Prism's core into the main bundle, and that core highlights every code block onDOMContentLoaded. A new client module,src/client-modules/prism-manual.js, setsPrism.manual = true. Docusaurus and Redoc both highlight explicitly, so nothing depended on the automatic pass.prismjsbecomes a direct dependency; it was already installed transitively at 1.30.0.<article>or ToC 100 ms afterDOMContentLoaded, often mid-hydration. It now runs withinjectButton: false, andsrc/client-modules/copy-page-button.jsloads the plugin's own client module from the firstonRouteDidUpdate, after hydration.The button vanishing after navigation
The plugin detects navigation by patching
history.pushStateand polling the URL. When the URL changes, Docusaurus is still showing the old page while it preloads the next route. The plugin finds its button still attached and does nothing, so the button goes with the old article when React mounts the new one. The plugin also listens for adocusaurus-route-updateevent that Docusaurus never dispatches. The client module now dispatches that event from lateronRouteDidUpdatecalls, which run in a layout effect after the new route is committed. Hash-only changes keep the same page and are skipped.The commits are separate: the first is the #418 fix and the second is the navigation fix.
Test plan
npm run build(en + ja) passes with no warningsnpm run serveand drove headless Chrome over CDP with real clicks on sidebar links (through the mobile drawer below 996 px). After every navigation there is exactly one button, and a MutationObserver confirms two never exist at once./user-manual/scripting/and siblings): button at the top of the ToC rail/user-manual/react/examples/*) and switching between no-ToC and ToC pages: after the breadcrumbs or on the rail, as appropriateNot fixed here: leaving
/user-manual/react/examples/physics/through the sidebar shows "This page crashed" (Cannot read properties of null (reading 'deleteBuffer')). It also happens on production and is being investigated separately.🤖 Generated with Claude Code