mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-30 21:01:54 +08:00
fix: suppress React 19 script warning in SsrScript (#1648)
This commit is contained in:
parent
a2889fc044
commit
7b0f430975
@ -1,6 +1,10 @@
|
||||
"use client";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
function escapeHtmlAttr(str: string): string {
|
||||
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
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>`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user