Conversation
Blog posts logged dozens of console errors on every load - repeated "Minified React error #418" (hydration failed, the initial UI does not match the server render) followed by "#423" (React gave up and switched the entire root to client rendering, discarding the SSR output). Running the production bundle against a development React build named the cause: "validateDOMNesting(...): <p> cannot appear as a descendant of <p>" and "Expected server HTML to contain a matching <p> in <p>". MDX parses the body of a multi-line JSX element as Markdown, so <p> Some text. </p> compiles to <p><p>Some text.</p></p>. That markup is invalid, so the browser closes the outer <p> before the nested one and the parsed DOM no longer matches the tree React renders on the client. The same happened wherever a heading, list, table, <div> or code block was written inside a hand-written <p>, and for every Markdown image, because the MDX image component wrapped each one in a <div> while sitting inside a paragraph. Fixes, all at the source: - Add a rehype plugin that rewrites the tree the way the HTML parser would: nested paragraphs collapse into their parent (keeping whichever wrapper carries the attributes), and other block-level children are hoisted out of the paragraph as siblings. It also lifts a lone Markdown paragraph out of components that render a single text element, such as Typography. - Wrap MDX images in a display:block <span> instead of a <div>, which is valid inside the paragraph the image renders in. - Close the paragraph before the list on the Sistent color page. Verified with a lite blog build served locally and loaded in Chromium, in both light and dark color schemes: /blog/engineering/why-claude-code-cant-find-your-tools 53 -> 0 /blog/engineering/claude-code-skills-not-found-... 34 -> 0 /blog, / (controls) 0 -> 0 Invalid block-in-paragraph nesting across the whole built site dropped from 517 occurrences on 118 pages to zero. Signed-off-by: Lee Calcote <leecalcote@gmail.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Contributor
|
Preview deployment for PR #8072 removed. This PR preview was automatically pruned because we keep only the 3 most recently updated previews on GitHub Pages to stay within deployment size limits. If needed, push a new commit to this PR to generate a fresh preview. |
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.
Description
This PR fixes #
Blog post pages logged dozens of React errors on every load, on production and on a local build: repeated
Minified React error #418(hydration failed, the initial UI does not match the server render) followed by#423(React gave up and switched the entire root to client rendering, discarding the SSR output - slower first paint, layout shift, no SEO benefit from SSR).Root cause
Rebuilding the production bundle against a non-minified React named it exactly:
MDX parses the body of a multi-line JSX element as Markdown, so a post written as
compiles to
<p><p>You run ...</p></p>. That markup is invalid, so the browser's parser closes the outer<p>before the nested one and the parsed DOM no longer matches the tree React renders on the client. Hydration then fails. The same thing happened wherever a heading, list, table,<div>or code block was written inside a hand-written<p>, and for every Markdown image, because the MDX image component wrapped each one in a<div>while sitting inside a paragraph.This also explains why the error count tracked the post rather than the theme: it is identical in light and dark mode, and posts with no such markup were already clean. Date formatting,
Math.random/Date.now,localStoragetheme reads and the Related Blogs carousel were all ruled out - dates come from the GraphQLformatStringat build time, and the carousel is already gated behind a post-hydration state flag.The fix
All at the source - no
suppressHydrationWarning:rehype-fix-paragraph-nesting.js- a rehype plugin registered ongatsby-plugin-mdxthat rewrites the tree the way the HTML parser would, so the emitted HTML is valid: nested paragraphs collapse into their parent (keeping whichever wrapper carries the attributes), and other block-level children are hoisted out of the paragraph as siblings. It also lifts a lone Markdown paragraph out of components that render a single text element, such asTypography.root-wrapper.js- the MDX image wrapper is adisplay: block<span>instead of a<div>, which is valid inside the paragraph the image renders in and lays out identically.Before / after
Lite blog build (
BUILD_FULL_SITE=false LITE_BUILD_PROFILE=blog gatsby build), served withgatsby serveand loaded in headless Chromium, counting console errors, in both light and dark color schemes (identical results in each):/blog/engineering/why-claude-code-cant-find-your-tools/blog/engineering/claude-code-skills-not-found-after-npx-install/blog/engineering/the-claude-code-source-leak-.../blog/ai/agentsmd-one-file-to-guide-them-all(control)/blog/community/announcing-meshmates(control)/blog(non-post)/(non-blog)Scanning every page in the built site for block-level elements nested inside a
<p>:Notes for Reviewers
<p>around Markdown in MDX is still worth avoiding, but it is no longer a bug./projects/sistent/components/accordion. Its<p>nesting is fixed, but MUI/emotion styles are not extracted during SSR there, so the server HTML carries 85 inline<style data-emotion>elements that do not exist in the client render. That needs an emotion SSR cache and is a separate change.npx eslintreports no new problems; the pre-existing repo-wide lint failures are unchanged.Signed commits
Generated by Claude Code