Skip to content

feat: build the client head snapshot from the DOM without html-react-parser - #4

Merged
MatthewPattell merged 2 commits into
prodfrom
feature/client-without-html-parser
Sep 5, 2026
Merged

feat: build the client head snapshot from the DOM without html-react-parser#4
MatthewPattell merged 2 commits into
prodfrom
feature/client-without-html-parser

Conversation

@MatthewPattell

Copy link
Copy Markdown
Contributor

Goal

Ship no HTML parser in the browser bundle and stop the manager from destroying root attributes it does not own.

Changes

  • analyzeClientHead() reads the existing <head>, <html> and <body> from the live DOM (attributes, text of title/style/script/noscript) instead of parsing innerHTML with html-react-parser; entries get their DOM node attached by identity instead of by child index, so whitespace or comments between head tags no longer misalign them. Keys, order, container ownership and status stay identical to the parser algorithm, proven by an oracle test that runs the old algorithm (kept as a test helper) over fixtures including the real server-rendered head of the minimal template.
  • Root attribute fixes: one attribute-name table used in both directions (className/class, htmlFor/for, charSet/charset, httpEquiv/http-equiv, crossOrigin, referrerPolicy, tabIndex, hrefLang, imageSrcSet, imageSizes, fetchPriority, noModule, srcSet, acceptCharset, itemProp, itemScope, itemType, itemID, itemRef); syncMeta compares mapped names, so <html lang="en" class="dark"> keeps its class after the first <Meta> push (before: class removed and a useless classname attribute written); boolean props write empty attributes and false/null/undefined remove them.
  • Ownership: the manager tracks the attributes, class tokens and style properties it applied and removes or restores only those; classes or attributes added at runtime by other code (dark-mode toggles, data-theme) survive Meta pushes, removals, navigation and the delayed sync.
  • html-react-parser stays a runtime dependency for the server helper only; sideEffects: false; npm run test:package builds, packs and checks a temporary consumer (client graph free of parser packages, server entry works).
  • Build on Node 22: rollup-plugin-ts is loaded through its CommonJS entry (declaration output byte-identical to the Node 20 build); CI uses Node 22.23.2 (Node 20 reached end of life in April 2026).

Verification

  • npm run lint:check, npm run ts:check, npm test on React 18.2.0 and 19.2.8 (36 tests each), npm run build on Node 22, npm run test:package.
  • Minimal template with the packed build: main chunk 104,762 → 95,994 bytes gzip (−8.8 KB, −8.4 percent); client sourcemaps contain no html-react-parser, html-dom-parser, htmlparser2, domhandler, entities, style-to-js or inline-style-parser sources; npm run smoke green.
  • Browser check on that build: hydration with a single <head>, no console errors; document.documentElement.classList.add('dark') and a runtime data-theme on <body> survive //about/ navigation; title and description return to the home values on the way back (with the published 2.1.2 they stay on the About values).

@sonarqubecloud

sonarqubecloud Bot commented Sep 5, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
B Security Rating on New Code (required ≥ A)
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Comment thread scripts/test-package.mjs
delete env.NO_COLOR;

const npm = (args, cwd, capture = false) =>
execFileSync('npm', args, {
@sonarqubecloud

sonarqubecloud Bot commented Sep 5, 2026

Copy link
Copy Markdown

@MatthewPattell
MatthewPattell merged commit b913b79 into prod Sep 5, 2026
5 checks passed
@MatthewPattell
MatthewPattell deleted the feature/client-without-html-parser branch September 5, 2026 20:12
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 2.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants