import { useStore } from '@tanstack/react-store' import { deepEqual } from '@tanstack/router-core' import { isServer } from '@tanstack/router-core/isServer' import { Asset } from './Asset' import { useRouter } from './useRouter' import type { RouterManagedTag } from '@tanstack/router-core' /** * Render body script tags collected from route matches and SSR manifests. * Should be placed near the end of the document body. */ export const Scripts = () => { const router = useRouter() const nonce = router.options.ssr?.nonce const getAssetScripts = (matches: Array) => { const assetScripts: Array = [] const manifest = router.ssr?.manifest if (!manifest) { return [] } matches .map((match) => router.looseRoutesById[match.routeId]!) .forEach((route) => manifest.routes[route.id]?.assets ?.filter((d) => d.tag === 'script') .forEach((asset) => { assetScripts.push({ tag: 'script', attrs: { ...asset.attrs, nonce }, children: asset.children, } as any) }), ) return assetScripts } const getScripts = (matches: Array): Array => ( matches .map((match) => match.scripts!) .flat(1) .filter(Boolean) as Array ).map( ({ children, ...script }) => ({ tag: 'script', attrs: { ...script, suppressHydrationWarning: true, nonce, }, children, }) satisfies RouterManagedTag, ) if (isServer ?? router.isServer) { const activeMatches = router.stores.matches.get() const assetScripts = getAssetScripts(activeMatches) const scripts = getScripts(activeMatches) return renderScripts(router, scripts, assetScripts) } // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static const assetScripts = useStore( router.stores.matches, getAssetScripts, deepEqual, ) // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static const scripts = useStore(router.stores.matches, getScripts, deepEqual) return renderScripts(router, scripts, assetScripts) } function renderScripts( router: ReturnType, scripts: Array, assetScripts: Array, ) { let serverBufferedScript: RouterManagedTag | undefined = undefined if (router.serverSsr) { serverBufferedScript = router.serverSsr.takeBufferedScripts() } const allScripts = [...scripts, ...assetScripts] as Array if (serverBufferedScript) { allScripts.unshift(serverBufferedScript) } return ( <> {allScripts.map((asset, i) => ( ))} ) }