@tanstack/react-router
Version:
Modern and scalable routing for React applications
1 lines • 10.6 kB
Source Map (JSON)
{"version":3,"file":"Asset.cjs","names":[],"sources":["../../src/Asset.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { isServer } from '@tanstack/router-core/isServer'\nimport { useRouter } from './useRouter'\nimport { useHydrated } from './ClientOnly'\nimport type { RouterManagedTag } from '@tanstack/router-core'\n\nconst INLINE_CSS_HYDRATION_ATTR = 'data-tsr-inline-css'\n\ninterface ScriptAttrs {\n [key: string]: string | boolean | undefined\n src?: string\n suppressHydrationWarning?: boolean\n}\n\nconst noopScriptHandler = () => {}\n\nfunction setScriptAttrs(\n script: HTMLScriptElement,\n attrs: ScriptAttrs | undefined,\n) {\n if (!attrs) {\n return\n }\n\n for (const [key, value] of Object.entries(attrs)) {\n if (\n key !== 'suppressHydrationWarning' &&\n value !== undefined &&\n value !== false\n ) {\n script.setAttribute(key, typeof value === 'boolean' ? '' : String(value))\n }\n }\n}\n\nexport function Asset(\n asset: RouterManagedTag & {\n nonce?: string\n preventScriptHoist?: boolean\n },\n): React.ReactElement | null {\n const { attrs, children, nonce, preventScriptHoist } = asset\n\n switch (asset.tag) {\n case 'title':\n return (\n <title {...attrs} suppressHydrationWarning>\n {children}\n </title>\n )\n case 'meta':\n return <meta {...attrs} suppressHydrationWarning />\n case 'link':\n return (\n <link\n {...attrs}\n precedence={\n attrs?.precedence ??\n (attrs?.rel === 'stylesheet' ? 'default' : undefined)\n }\n nonce={nonce}\n suppressHydrationWarning\n />\n )\n case 'style':\n if (\n asset.inlineCss &&\n (process.env.TSS_INLINE_CSS_ENABLED === 'true' ||\n (process.env.TSS_INLINE_CSS_ENABLED === undefined && isServer))\n ) {\n return (\n <InlineCssStyle attrs={attrs} nonce={nonce}>\n {children}\n </InlineCssStyle>\n )\n }\n\n return (\n <style\n {...attrs}\n dangerouslySetInnerHTML={{ __html: children as string }}\n nonce={nonce}\n />\n )\n case 'script':\n return (\n <Script attrs={attrs} preventScriptHoist={preventScriptHoist}>\n {children}\n </Script>\n )\n default:\n return null\n }\n}\n\nfunction InlineCssStyle({\n attrs,\n children,\n nonce,\n}: {\n attrs?: Record<string, any>\n children?: RouterManagedTag['children']\n nonce?: string\n}) {\n const isInlineCssPlaceholder = children === undefined\n const [hydratedInlineCss] = React.useState(() => {\n if (!isInlineCssPlaceholder || typeof document === 'undefined') {\n return undefined\n }\n\n return (\n document.querySelector<HTMLStyleElement>(\n `style[${INLINE_CSS_HYDRATION_ATTR}]`,\n )?.textContent ?? undefined\n )\n })\n const html = isInlineCssPlaceholder\n ? (hydratedInlineCss ?? '')\n : (children ?? '')\n\n return (\n <style\n {...attrs}\n {...{ [INLINE_CSS_HYDRATION_ATTR]: '' }}\n dangerouslySetInnerHTML={{ __html: html }}\n nonce={nonce}\n suppressHydrationWarning\n />\n )\n}\n\nfunction Script({\n attrs,\n children,\n preventScriptHoist,\n}: {\n attrs?: ScriptAttrs\n children?: string\n preventScriptHoist?: boolean\n}) {\n const router = useRouter()\n const hydrated = useHydrated()\n const dataScript =\n typeof attrs?.type === 'string' &&\n attrs.type !== '' &&\n attrs.type !== 'text/javascript' &&\n attrs.type !== 'module'\n\n if (\n process.env.NODE_ENV !== 'production' &&\n attrs?.src &&\n typeof children === 'string' &&\n children.trim().length\n ) {\n console.warn(\n '[TanStack Router] <Script> received both `src` and `children`. The `children` content will be ignored. Remove `children` or remove `src`.',\n )\n }\n\n React.useEffect(() => {\n if (dataScript) return\n\n if (attrs?.src) {\n const normSrc = (() => {\n try {\n const base = document.baseURI || window.location.href\n return new URL(attrs.src, base).href\n } catch {\n return attrs.src\n }\n })()\n for (const el of document.querySelectorAll('script[src]')) {\n if ((el as HTMLScriptElement).src === normSrc) {\n return\n }\n }\n\n const script = document.createElement('script')\n\n setScriptAttrs(script, attrs)\n\n document.head.appendChild(script)\n\n return () => script.remove()\n }\n\n if (typeof children === 'string') {\n const typeAttr =\n typeof attrs?.type === 'string' ? attrs.type : 'text/javascript'\n const nonceAttr =\n typeof attrs?.nonce === 'string' ? attrs.nonce : undefined\n for (const el of document.querySelectorAll('script:not([src])')) {\n if (!(el instanceof HTMLScriptElement)) {\n continue\n }\n\n const sType = el.getAttribute('type') ?? 'text/javascript'\n const sNonce = el.getAttribute('nonce') ?? undefined\n if (\n el.textContent === children &&\n sType === typeAttr &&\n sNonce === nonceAttr\n ) {\n return\n }\n }\n\n const script = document.createElement('script')\n script.textContent = children\n setScriptAttrs(script, attrs)\n\n document.head.appendChild(script)\n\n return () => script.remove()\n }\n\n return undefined\n }, [attrs, children, dataScript])\n\n // --- Server rendering ---\n if (isServer ?? router.isServer) {\n if (attrs?.src) {\n if (!preventScriptHoist) {\n return <script {...attrs} suppressHydrationWarning />\n }\n\n return (\n <script\n {...attrs}\n // React hoists async src scripts into <head> during SSR unless they\n // have an event handler. Start's client entry must stay after router\n // dehydration.\n onLoad={noopScriptHandler}\n suppressHydrationWarning\n />\n )\n }\n\n if (typeof children === 'string') {\n return (\n <script\n {...attrs}\n dangerouslySetInnerHTML={{ __html: children }}\n suppressHydrationWarning\n />\n )\n }\n\n return null\n }\n\n // --- Client rendering ---\n\n // Data scripts (e.g. application/ld+json) are rendered in the tree;\n // the useEffect intentionally skips them.\n if (dataScript && typeof children === 'string') {\n return (\n <script\n {...attrs}\n suppressHydrationWarning\n dangerouslySetInnerHTML={{ __html: children }}\n />\n )\n }\n\n // During hydration (before useEffect has fired), render the script element\n // to match the server-rendered HTML and avoid structural hydration mismatches.\n // After hydration, return null — the useEffect handles imperative injection.\n if (!hydrated) {\n if (attrs?.src) {\n return <script {...attrs} suppressHydrationWarning />\n }\n\n if (typeof children === 'string') {\n return (\n <script\n {...attrs}\n dangerouslySetInnerHTML={{ __html: children }}\n suppressHydrationWarning\n />\n )\n }\n }\n\n return null\n}\n"],"mappings":"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"}