vinext: 0.1.2
Summary. Three related defects in the next/script shim around beforeInteractive:
- Hydration duplication. SSR splices the beforeInteractive script into the pre-head, but the emitted node carries no marker. On the client,
<Script> re-renders the element because it can't tell the server already handled it (the nav runtime may not be registered yet — dev loads it as an async ESM module). Result: a duplicate script element and a hydration mismatch on essentially every page.
src scripts bypass the server registry. Only inline beforeInteractive content is registered into the pre-head splice path. A beforeInteractive script with src falls through to the normal React element path, so it does not get the same pre-head ordering, marker, or client dedupe treatment as inline scripts.
- Attribute mapping gaps.
REACT_TO_HTML_ATTR maps className/htmlFor/httpEquiv but not crossOrigin → crossorigin or referrerPolicy → referrerpolicy, so server-spliced script attrs are not normalized to the same HTML spelling Next uses.
Reproduce.
- Add
<Script id="x" strategy="beforeInteractive">…</Script> (and separately one with src=…).
- Load/hydrate the page.
- Observe: two copies of the inline script + a hydration warning (defect 1); the
src script is not emitted through the same server splice/marker/dedupe path as inline beforeInteractive scripts (defect 2); crossOrigin/referrerPolicy are not normalized in the server-spliced string attrs (defect 3).
Where (0.1.2 dist).
dist/server/app-ssr-entry.js:80 — renderBeforeInteractiveInlineScripts emits scripts with no identifying marker.
dist/shims/script.js:113 — REACT_TO_HTML_ATTR missing crossOrigin/referrerPolicy.
dist/shims/script.js beforeInteractive branch (~L269 / ~L353) — only handles inline content (inlineContent !== null) and dedups only via hasAppNavigationRuntimeBootstrap().
Suggested fix.
- Emit a marker on SSR scripts:
data-vinext-before-interactive="" (in renderBeforeInteractiveInlineScripts).
- On the client, also treat a matching spliced DOM node (by marker +
id/src) as "server already handled it" → return null instead of rendering a duplicate.
- Register
src beforeInteractive scripts too (inlineContent !== null || src), passing src through the registered attributes.
- Add
crossOrigin: "crossorigin" and referrerPolicy: "referrerpolicy" to REACT_TO_HTML_ATTR.
Related existing issues: #1518 and #1557 cover earlier beforeInteractive head-placement/order failures; #1517 covers nonce/stylesheets/bootstrap preinit. This report is narrower: server/client duplicate-dedupe marker, src parity with the beforeInteractive server registry, and the remaining attr-map gaps. Defect 3 is independent and tiny enough to split if maintainers prefer, but keeping it here is reasonable because the fix is in the same next/script attr collection/emission path.
vinext: 0.1.2
Summary. Three related defects in the
next/scriptshim aroundbeforeInteractive:<Script>re-renders the element because it can't tell the server already handled it (the nav runtime may not be registered yet — dev loads it as an async ESM module). Result: a duplicate script element and a hydration mismatch on essentially every page.srcscripts bypass the server registry. Only inlinebeforeInteractivecontent is registered into the pre-head splice path. AbeforeInteractivescript withsrcfalls through to the normal React element path, so it does not get the same pre-head ordering, marker, or client dedupe treatment as inline scripts.REACT_TO_HTML_ATTRmapsclassName/htmlFor/httpEquivbut notcrossOrigin→crossoriginorreferrerPolicy→referrerpolicy, so server-spliced script attrs are not normalized to the same HTML spelling Next uses.Reproduce.
<Script id="x" strategy="beforeInteractive">…</Script>(and separately one withsrc=…).srcscript is not emitted through the same server splice/marker/dedupe path as inlinebeforeInteractivescripts (defect 2);crossOrigin/referrerPolicyare not normalized in the server-spliced string attrs (defect 3).Where (0.1.2 dist).
dist/server/app-ssr-entry.js:80—renderBeforeInteractiveInlineScriptsemits scripts with no identifying marker.dist/shims/script.js:113—REACT_TO_HTML_ATTRmissingcrossOrigin/referrerPolicy.dist/shims/script.jsbeforeInteractive branch (~L269 / ~L353) — only handles inline content (inlineContent !== null) and dedups only viahasAppNavigationRuntimeBootstrap().Suggested fix.
data-vinext-before-interactive=""(inrenderBeforeInteractiveInlineScripts).id/src) as "server already handled it" → returnnullinstead of rendering a duplicate.srcbeforeInteractive scripts too (inlineContent !== null || src), passingsrcthrough the registered attributes.crossOrigin: "crossorigin"andreferrerPolicy: "referrerpolicy"toREACT_TO_HTML_ATTR.Related existing issues: #1518 and #1557 cover earlier
beforeInteractivehead-placement/order failures; #1517 covers nonce/stylesheets/bootstrap preinit. This report is narrower: server/client duplicate-dedupe marker,srcparity with the beforeInteractive server registry, and the remaining attr-map gaps. Defect 3 is independent and tiny enough to split if maintainers prefer, but keeping it here is reasonable because the fix is in the samenext/scriptattr collection/emission path.