Skip to content

Move the pre-paint scripts out of <head> so cold loads stop failing to hydrate - #43

Merged
renrenmimi merged 1 commit into
mainfrom
fix/pre-paint-scripts-in-body
Oct 9, 2026
Merged

renrenmimi merged 1 commit into
mainfrom
fix/pre-paint-scripts-in-body

Conversation

@renrenmimi

Copy link
Copy Markdown
Owner

Summary

Follow-up to #36, whose PR left the trigger of React error #418 unlocated.

On a cold cache, React still gives up hydrating the root now and then and renders it again on the client. Measured on production before this change: 120 cold-cache loads in headless Chrome at 1440×900, rotating through /, /array, /stack, /hash, /heap and /atlas, with dd-lang = zh and dd-theme = light stored before any script ran. Error #418 appeared 2 times (on /heap and /atlas). Thanks to #36 no setting was lost in either case, but the whole root was still rendered again.

The trigger. The two hand-written pre-paint scripts sat in <head>. React matches those nodes one by one during hydration, while the webpack runtime removes the chunk <script> tags it has finished loading from the same <head>. When a removal lands in the middle of that matching, hydration fails.

The change. The scripts now sit at the top of <body>. They still run before the first paint, because they are the first thing the parser meets in <body>. The settings restore from #36 stays as a safety net. A comment in theme-provider.tsx that said the script is in <head> is updated.

AlgoAlgo has the same shell and the same failure, and the same move fixed it there (renrenmimi/AlgoAlgo#15). Before it, 5 of 120 cold loads failed on production; after it, 0 of 240.

Test plan

  • npx tsc --noEmit, npm test (104 passed), npm run build.
  • Playwright locally with system Chrome: 56 passed, including the title and settings flows for a Chinese reader.
  • After deploy: the same 120+ cold loads on production, expecting no #418. A local production server does not reproduce the failure, as AlgoAlgo showed, so the check has to run on production.

🤖 Generated with Claude Code

…o hydrate

On a cold cache, React still gave up hydrating the root now and then
(minified error #418): 2 of 120 cold loads on production. #36 made the
consequence harmless by restoring the settings from storage, but left the
trigger: the two hand-written pre-paint scripts in <head>, which React
matches node by node while the webpack runtime removes the chunk <script>
tags it has finished loading from the same <head>.

The scripts now sit at the top of <body>, as in AlgoAlgo, where the same
move took cold-load failures from 5 of 120 to 0 of 240 on production. They
still run before the first paint, because they are the first thing the
parser meets in <body>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 9, 2026 14:20
@vercel

vercel Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
data-data Ready Ready Preview Oct 9, 2026 2:22pm UTC

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-09T14:22:14.531899Z d5e1360 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@renrenmimi
renrenmimi merged commit a073eb5 into main Oct 9, 2026
3 checks passed
@renrenmimi
renrenmimi deleted the fix/pre-paint-scripts-in-body branch October 9, 2026 14:23
@renrenmimi

Copy link
Copy Markdown
Owner Author

Measured on production after the merge (deployment of a073eb5): the same 240 cold-cache loads in headless Chrome at 1440×900, rotating through /, /array, /stack, /hash, /heap and /atlas, with dd-lang = zh and dd-theme = light stored before any script ran.

  • React #418: 0 of 240 (before: 2 of 120).
  • Settings lost: 0 of 240.
  • Load errors: 0.

At the old rate of 2 in 120, 240 clean loads in a row would happen with probability about 0.018. Together with AlgoAlgo, where the same move took the rate from 5 of 120 to 0 of 240, this confirms the scripts in <head> were the trigger.

This branch was successfully deployed

1 active deployment
Preview — d5e13605 Deployed Oct 9, 2026 by vercel[bot]
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