UNPKG

@tanstack/solid-router

Version:

Modern and scalable routing for Solid applications

1 lines 10.4 kB
{"version":3,"file":"headContentUtils.cjs","names":["Solid","escapeHtml","getAssetCrossOrigin","resolveManifestAssetLink","useRouter","AssetCrossOriginConfig","RouterManagedTag","useTags","assetCrossOrigin","router","nonce","options","ssr","getTagKey","tag","JSON","stringify","activeMatches","createMemo","stores","activeMatchesSnapshot","state","routeMeta","map","match","meta","filter","Boolean","Accessor","Array","resultMeta","metaByAttribute","Record","title","routeMetasArray","i","length","metas","j","m","children","json","push","attrs","type","attribute","name","property","content","reverse","links","matches","constructed","flat","link","manifest","assets","routes","routeId","asset","crossOrigin","preloadLinks","looseRoutesById","forEach","route","id","preloads","preload","preloadLink","rel","href","styles","style","headScripts","script","prev","next","uniqBy","every","index","arr","T","fn","item","seen","Set","key","has","add"],"sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport {\n escapeHtml,\n getAssetCrossOrigin,\n resolveManifestAssetLink,\n} from '@tanstack/router-core'\nimport { useRouter } from './useRouter'\nimport type {\n AssetCrossOriginConfig,\n RouterManagedTag,\n} from '@tanstack/router-core'\n\n/**\n * Build the list of head/link/meta/script tags to render for active matches.\n * Used internally by `HeadContent`.\n */\nexport const useTags = (assetCrossOrigin?: AssetCrossOriginConfig) => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n const getTagKey = (tag: RouterManagedTag) => JSON.stringify(tag)\n const activeMatches = Solid.createMemo(\n () => router.stores.activeMatchesSnapshot.state,\n )\n const routeMeta = Solid.createMemo(() =>\n activeMatches()\n .map((match) => match.meta!)\n .filter(Boolean),\n )\n\n const meta: Solid.Accessor<Array<RouterManagedTag>> = Solid.createMemo(() => {\n const resultMeta: Array<RouterManagedTag> = []\n const metaByAttribute: Record<string, true> = {}\n let title: RouterManagedTag | undefined\n const routeMetasArray = routeMeta()\n for (let i = routeMetasArray.length - 1; i >= 0; i--) {\n const metas = routeMetasArray[i]!\n for (let j = metas.length - 1; j >= 0; j--) {\n const m = metas[j]\n if (!m) continue\n\n if (m.title) {\n if (!title) {\n title = {\n tag: 'title',\n children: m.title,\n }\n }\n } else if ('script:ld+json' in m) {\n // Handle JSON-LD structured data\n // Content is HTML-escaped to prevent XSS when injected via innerHTML\n try {\n const json = JSON.stringify(m['script:ld+json'])\n resultMeta.push({\n tag: 'script',\n attrs: {\n type: 'application/ld+json',\n },\n children: escapeHtml(json),\n })\n } catch {\n // Skip invalid JSON-LD objects\n }\n } else {\n const attribute = m.name ?? m.property\n if (attribute) {\n if (metaByAttribute[attribute]) {\n continue\n } else {\n metaByAttribute[attribute] = true\n }\n }\n\n resultMeta.push({\n tag: 'meta',\n attrs: {\n ...m,\n nonce,\n },\n })\n }\n }\n }\n\n if (title) {\n resultMeta.push(title)\n }\n\n if (router.options.ssr?.nonce) {\n resultMeta.push({\n tag: 'meta',\n attrs: {\n property: 'csp-nonce',\n content: router.options.ssr.nonce,\n },\n })\n }\n resultMeta.reverse()\n\n return resultMeta\n })\n\n const links = Solid.createMemo(() => {\n const matches = activeMatches()\n const constructed = matches\n .map((match) => match.links!)\n .filter(Boolean)\n .flat(1)\n .map((link) => ({\n tag: 'link',\n attrs: {\n ...link,\n nonce,\n },\n })) satisfies Array<RouterManagedTag>\n\n const manifest = router.ssr?.manifest\n\n const assets = matches\n .map((match) => manifest?.routes[match.routeId]?.assets ?? [])\n .filter(Boolean)\n .flat(1)\n .filter((asset) => asset.tag === 'link')\n .map(\n (asset) =>\n ({\n tag: 'link',\n attrs: {\n ...asset.attrs,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'stylesheet') ??\n asset.attrs?.crossOrigin,\n nonce,\n },\n }) satisfies RouterManagedTag,\n )\n\n return [...constructed, ...assets]\n })\n\n const preloadLinks = Solid.createMemo(() => {\n const matches = activeMatches()\n const preloadLinks: Array<RouterManagedTag> = []\n\n matches\n .map((match) => router.looseRoutesById[match.routeId]!)\n .forEach((route) =>\n router.ssr?.manifest?.routes[route.id]?.preloads\n ?.filter(Boolean)\n .forEach((preload) => {\n const preloadLink = resolveManifestAssetLink(preload)\n preloadLinks.push({\n tag: 'link',\n attrs: {\n rel: 'modulepreload',\n href: preloadLink.href,\n crossOrigin:\n getAssetCrossOrigin(assetCrossOrigin, 'modulepreload') ??\n preloadLink.crossOrigin,\n nonce,\n },\n })\n }),\n )\n\n return preloadLinks\n })\n\n const styles = Solid.createMemo(() =>\n (\n activeMatches()\n .map((match) => match.styles!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(({ children, ...style }) => ({\n tag: 'style',\n attrs: {\n ...style,\n nonce,\n },\n children,\n })),\n )\n\n const headScripts = Solid.createMemo(() =>\n (\n activeMatches()\n .map((match) => match.headScripts!)\n .flat(1)\n .filter(Boolean) as Array<RouterManagedTag>\n ).map(({ children, ...script }) => ({\n tag: 'script',\n attrs: {\n ...script,\n nonce,\n },\n children,\n })),\n )\n\n return Solid.createMemo((prev: Array<RouterManagedTag> | undefined) => {\n const next = uniqBy(\n [\n ...meta(),\n ...preloadLinks(),\n ...links(),\n ...styles(),\n ...headScripts(),\n ] as Array<RouterManagedTag>,\n getTagKey,\n )\n\n if (\n prev &&\n prev.length === next.length &&\n prev.every((tag, index) => getTagKey(tag) === getTagKey(next[index]!))\n ) {\n return prev\n }\n\n return next\n })\n}\n\nexport function uniqBy<T>(arr: Array<T>, fn: (item: T) => string) {\n const seen = new Set<string>()\n return arr.filter((item) => {\n const key = fn(item)\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n"],"mappings":"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"}