Repository navigation
Treat marker-less HTML starting with a doctype or <html> as a document - #11877
Merged
brophdawg11 merged 2 commits intoSep 22, 2026
Merged
Conversation
devtechedge
added a commit
to devtechedge/oss-contributions
that referenced
this pull request
Sep 15, 2026
`renderToString` strips flush markers before returning, so its output carries no `<!-- rmx:flush document -->` marker and the client runtime never takes the full-document-reload path. The response is diffed as a fragment instead, which parses it inside a `<template>`, drops the `<html>`/`<head>`/`<body>` wrappers, and throws HierarchyRequestError while diffing against `documentElement`. When a frame receives HTML with no flush marker, infer the kind from the markup instead of defaulting to `fragment`: HTML starting with a doctype or `<html>` is a whole document. This also covers static output that lost its comments to a minifier. Fixes #11808
devtechedge
force-pushed
the
devtechedge/flush-kind-inference
branch
from
September 15, 2026 16:07
eb316b7 to
eb23084
Compare
devtechedge
force-pushed
the
devtechedge/flush-kind-inference
branch
from
September 15, 2026 16:33
eb23084 to
f485114
Compare
Contributor
|
/review |
Author
|
Matt, thanks for reviewing and merging this one. Seeing Aron independently reproduce it and land on the same marker-less inference approach gave me a lot of confidence the fix was shaped right. The fragment-versus-document classification was the real lesson here, and working through it with this codebase was a ton of fun. 🚀 |
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.
When a frame receives HTML with no flush marker, the flush kind is now inferred from the markup instead of defaulting to
fragment. HTML that starts with a doctype or<html>is treated as a whole document.Why
renderToStringstrips flush markers before returning, so its output carries no<!-- rmx:flush document -->marker.createFrameonly takes the full-document-reload path whenflushKind === 'document', andrenderFrameStreamapplied its end-of-stream remainder as a fragment. Marker-less document HTML therefore went throughcreateFragmentFromString, which parses inside a<template>and drops the<html>/<head>/<body>wrappers.diffNodesthen tried to insert those nodes besidedocumentElementand Chromium threw:The Navigation API keeps the committed URL and fires
navigateerror, so a click looked like a no-op: the URL changed, the document did not, and nothing appeared in the console.Inferring the kind also covers static output that lost its comments to a minifier, and restores the document sniffing
finalizeHtmldid before #11353.Reproduction
https://github.com/devtechedge/remix-render-to-string-navigation
A minimal app with a client entry on page A and two destination pages, one rendered with
renderToStreamand one withrenderToString.npm run verifyclicks both links in Chromium and prints the URL, title, and heading before and after each click. Before this change only therenderToStreamlink navigates; after it both do.Tests
Three regressions in
packages/ui/src/test/frame.test.tscover the stream path, the string path, and realrenderToStringoutput. All three fail onmainwith theHierarchyRequestErrorabove and pass with this change.The full
packages/uisuite is green: 1081 tests, 1056 pass, 0 fail, 24 todo.Fixes #11808