You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The validate pass round-trips each DOM template through a body-context fragment parse and
compares serializations. A template whose root is <html> (a root document: `…
…`) can never pass that comparison — body-context `innerHTML`
parsing strips the ``/``/`` wrappers, so the "browser" serialization never
matches the input, regardless of whether the markup is actually well-formed.
Through 2.0.0-rc.4 this printed the malformed-HTML warning and emitted anyway. Since 2.0.0-rc.5
(#3099 — the right call for genuine restructuring) it is a compile error, so a module containing
root-document JSX fails to compile at all in generate: 'dom', hydratable: false mode. Merely
importing the module is fatal; no template has to be instantiated.
The validator already handles context-sensitive fragments: <td>/<tr>/<col>/table components
are wrapped in a synthetic <table> before parsing. ^<html> needs the analogous treatment
(validate in the document context, or skip/downgrade for document shells).
Where this bites: apps whose root component owns the document shell — e.g. a TanStack Solid Start
root route — when that component is compiled in plain client mode, which is the natural
configuration for a jsdom/vitest component-test project. The route tree transitively imports the
root route, so the whole test import chain dies. (Dev/build pipelines using hydratable client
compiles are unaffected, which hides the problem until someone runs component tests.)
hydratable: true client compiles do not hit the error for the same input, so the mode that
actually hydrates real documents is already outside the check's reach.
Save as repro.mjs and run node repro.mjs. Tested on Linux with Node 24.19.0; this is a
compile-time issue, so no browser is involved.
Output at 2.0.0-rc.6:
{"generate":"dom","hydratable":false} → THROWS: /path/to/root.tsx: The HTML provided is malformed and will yield unexpected output when evaluated by a browser.
{"generate":"dom","hydratable":true} → OK
{"generate":"ssr","hydratable":true} → OK
At 2.0.0-rc.3/rc.4 the same input prints the diagnostic as a warning and compiles.
Expected behavior
A well-formed document-shell template validates (parsed in the document context, the way table
fragments are parsed in a synthetic table), or at minimum the document-shell case degrades to the
pre-#3099 warning instead of failing the compile.
Summary
The
…`) can never pass that comparison — body-context `innerHTML` parsing strips the ``/``/`` wrappers, so the "browser" serialization never matches the input, regardless of whether the markup is actually well-formed.validatepass round-trips each DOM template through a body-context fragment parse andcompares serializations. A template whose root is
<html>(a root document: `…Through 2.0.0-rc.4 this printed the malformed-HTML warning and emitted anyway. Since 2.0.0-rc.5
(#3099 — the right call for genuine restructuring) it is a compile error, so a module containing
root-document JSX fails to compile at all in
generate: 'dom', hydratable: falsemode. Merelyimporting the module is fatal; no template has to be instantiated.
The validator already handles context-sensitive fragments:
<td>/<tr>/<col>/table componentsare wrapped in a synthetic
<table>before parsing.^<html>needs the analogous treatment(validate in the document context, or skip/downgrade for document shells).
Where this bites: apps whose root component owns the document shell — e.g. a TanStack Solid Start
root route — when that component is compiled in plain client mode, which is the natural
configuration for a jsdom/vitest component-test project. The route tree transitively imports the
root route, so the whole test import chain dies. (Dev/build pipelines using hydratable client
compiles are unaffected, which hides the problem until someone runs component tests.)
Two smaller observations while here:
(This is an error on an internal node. Probably an internal error.)instead of a source code frame, so this configuration still loses the user-code location
promised by [compiler]
validatewarns but still emits the broken template walk #3099.hydratable: trueclient compiles do not hit the error for the same input, so the mode thatactually hydrates real documents is already outside the check's reach.
Reproduction
Save as
repro.mjsand runnode repro.mjs. Tested on Linux with Node 24.19.0; this is acompile-time issue, so no browser is involved.
Output at 2.0.0-rc.6:
At 2.0.0-rc.3/rc.4 the same input prints the diagnostic as a warning and compiles.
Expected behavior
A well-formed document-shell template validates (parsed in the document context, the way table
fragments are parsed in a synthetic table), or at minimum the document-shell case degrades to the
pre-#3099 warning instead of failing the compile.