fix: suppress React 19 script warning in SsrScript (#1648)

This commit is contained in:
Konsti Wohlwend 2026-06-23 12:16:14 -07:00 committed by GitHub
parent a2889fc044
commit 7b0f430975
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,6 +1,10 @@
"use client";
import { useLayoutEffect } from "react";
function escapeHtmlAttr(str: string): string {
return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
export function SsrScript(props: { script: string, nonce?: string }) {
useLayoutEffect(() => {
// TODO fix workaround: React has a bug where it doesn't run the script on the first CSR render if SSR has been skipped due to suspense
@ -9,11 +13,19 @@ export function SsrScript(props: { script: string, nonce?: string }) {
(0, eval)(props.script);
}, []);
// Embed the <script> in a span's innerHTML rather than as a React <script> JSX element to
// avoid React 19's "Scripts inside React components are never executed when rendering on the
// client" warning. The browser still executes the script during SSR HTML parsing, and on the
// client React sets innerHTML but the browser won't re-execute the script (innerHTML scripts
// don't run). Using the same HTML on both sides avoids hydration mismatches.
const nonceAttr = props.nonce ? ` nonce="${escapeHtmlAttr(props.nonce)}"` : '';
return (
<script
<span
suppressHydrationWarning // the transpiler is setup differently for client/server targets, so if `script` was generated with Function.toString they will differ
nonce={props.nonce}
dangerouslySetInnerHTML={{ __html: props.script }}
dangerouslySetInnerHTML={{
__html: `<script${nonceAttr}>${props.script}</script>`,
}}
/>
);
}