From 96ac0d01b81e7f25c560e465098ef41744081381 Mon Sep 17 00:00:00 2001 From: Sheraff Date: Mon, 26 Jan 2026 09:09:13 +0100 Subject: [PATCH 1/3] refactor(react-router): useTags performance --- .../react-router/src/headContentUtils.tsx | 288 +++++++++++------- 1 file changed, 173 insertions(+), 115 deletions(-) diff --git a/packages/react-router/src/headContentUtils.tsx b/packages/react-router/src/headContentUtils.tsx index 1345eebb22d..8d8edbe8846 100644 --- a/packages/react-router/src/headContentUtils.tsx +++ b/packages/react-router/src/headContentUtils.tsx @@ -13,14 +13,25 @@ export const useTags = () => { const nonce = router.options.ssr?.nonce const routeMeta = useRouterState({ select: (state) => { - return state.matches.map((match) => match.meta!).filter(Boolean) + const result = [] + for (const match of state.matches) { + const meta = match.meta + if (!meta) continue + result.push(meta) + } + return result }, + structuralSharing: true as any, }) - const meta: Array = React.useMemo(() => { - const resultMeta: Array = [] - const metaByAttribute: Record = {} + // Process routeMeta into separate arrays for each tag type + const { title, ldJsonScripts, metaTags } = React.useMemo(() => { + const ldJsonScripts: Array = [] + const seenLdJson = new Set() + const metaTags: Array = [] + const seenMeta = new Set() let title: RouterManagedTag | undefined + for (let i = routeMeta.length - 1; i >= 0; i--) { const metas = routeMeta[i]! for (let j = metas.length - 1; j >= 0; j--) { @@ -38,8 +49,11 @@ export const useTags = () => { // Handle JSON-LD structured data // Content is HTML-escaped to prevent XSS when injected via dangerouslySetInnerHTML try { + // Deduplicate by JSON content before creating the object const json = JSON.stringify(m['script:ld+json']) - resultMeta.push({ + if (seenLdJson.has(json)) continue + seenLdJson.add(json) + ldJsonScripts.push({ tag: 'script', attrs: { type: 'application/ld+json', @@ -50,16 +64,14 @@ export const useTags = () => { // Skip invalid JSON-LD objects } } else { - const attribute = m.name ?? m.property - if (attribute) { - if (metaByAttribute[attribute]) { - continue - } else { - metaByAttribute[attribute] = true - } + // Deduplicate by name or property attribute + const key = m.name ?? m.property ?? '' + if (key) { + if (seenMeta.has(key)) continue + seenMeta.add(key) } - resultMeta.push({ + metaTags.push({ tag: 'meta', attrs: { ...m, @@ -70,12 +82,9 @@ export const useTags = () => { } } - if (title) { - resultMeta.push(title) - } - - if (nonce) { - resultMeta.push({ + // Add CSP nonce meta tag if present + if (nonce && !seenMeta.has('csp-nonce')) { + metaTags.push({ tag: 'meta', attrs: { property: 'csp-nonce', @@ -83,135 +92,184 @@ export const useTags = () => { }, }) } - resultMeta.reverse() - return resultMeta + // Reverse to restore original order (we iterated backwards for deduplication) + ldJsonScripts.reverse() + metaTags.reverse() + + return { title, ldJsonScripts, metaTags } }, [routeMeta, nonce]) const links = useRouterState({ select: (state) => { - const constructed = state.matches - .map((match) => match.links!) - .filter(Boolean) - .flat(1) - .map((link) => ({ - tag: 'link', - attrs: { - ...link, - nonce, - }, - })) satisfies Array - + const result: Array = [] + const seen = new Set() const manifest = router.ssr?.manifest - // These are the assets extracted from the ViteManifest - // using the `startManifestPlugin` - const assets = state.matches - .map((match) => manifest?.routes[match.routeId]?.assets ?? []) - .filter(Boolean) - .flat(1) - .filter((asset) => asset.tag === 'link') - .map( - (asset) => - ({ + for (const match of state.matches) { + // Process constructed links from match.links + const matchLinks = match.links + if (matchLinks) { + for (const link of matchLinks) { + if (!link) continue + // Deduplicate by rel:href before creating the object + const key = `${link.rel ?? ''}:${link.href ?? ''}` + if (seen.has(key)) continue + seen.add(key) + result.push({ + tag: 'link', + attrs: { + ...link, + nonce, + }, + }) + } + } + + // Process assets from manifest + const assets = manifest?.routes[match.routeId]?.assets + if (assets) { + for (const asset of assets) { + if (asset.tag !== 'link') continue + // Deduplicate by rel:href before creating the object + const attrs = asset.attrs + const key = `${attrs?.rel ?? ''}:${attrs?.href ?? ''}` + if (seen.has(key)) continue + seen.add(key) + result.push({ tag: 'link', attrs: { - ...asset.attrs, + ...attrs, suppressHydrationWarning: true, nonce, }, - }) satisfies RouterManagedTag, - ) + }) + } + } + } - return [...constructed, ...assets] + return result }, structuralSharing: true as any, }) const preloadLinks = useRouterState({ select: (state) => { - const preloadLinks: Array = [] - - state.matches - .map((match) => router.looseRoutesById[match.routeId]!) - .forEach((route) => - router.ssr?.manifest?.routes[route.id]?.preloads - ?.filter(Boolean) - .forEach((preload) => { - preloadLinks.push({ - tag: 'link', - attrs: { - rel: 'modulepreload', - href: preload, - nonce, - }, - }) - }), - ) - - return preloadLinks + const result: Array = [] + const seen = new Set() + const manifest = router.ssr?.manifest + + for (const match of state.matches) { + const route = router.looseRoutesById[match.routeId] + if (!route) continue + + const preloads = manifest?.routes[route.id]?.preloads + if (!preloads) continue + + for (const preload of preloads) { + if (!preload) continue + // Deduplicate by href before creating the object + if (seen.has(preload)) continue + seen.add(preload) + result.push({ + tag: 'link', + attrs: { + rel: 'modulepreload', + href: preload, + nonce, + }, + }) + } + } + + return result }, structuralSharing: true as any, }) const styles = useRouterState({ - select: (state) => - ( - state.matches - .map((match) => match.styles!) - .flat(1) - .filter(Boolean) as Array - ).map(({ children, ...attrs }) => ({ - tag: 'style', - attrs: { - ...attrs, - nonce, - }, - children, - })), + select: (state) => { + const result: Array = [] + const seen = new Set() + + for (const match of state.matches) { + const matchStyles = match.styles + if (!matchStyles) continue + + for (const style of matchStyles) { + if (!style) continue + // Deduplicate by children (CSS content) before creating the object + const { children, ...attrs } = style + const key = String(children ?? '') + if (seen.has(key)) continue + seen.add(key) + result.push({ + tag: 'style', + attrs: { + ...attrs, + nonce, + }, + children: children as string | undefined, + }) + } + } + + return result + }, structuralSharing: true as any, }) - const headScripts: Array = useRouterState({ - select: (state) => - ( - state.matches - .map((match) => match.headScripts!) - .flat(1) - .filter(Boolean) as Array - ).map(({ children, ...script }) => ({ - tag: 'script', - attrs: { - ...script, - nonce, - }, - children, - })), + const headScripts = useRouterState({ + select: (state) => { + const result: Array = [] + const seen = new Set() + + for (const match of state.matches) { + const matchScripts = match.headScripts + if (!matchScripts) continue + + for (const script of matchScripts) { + if (!script) continue + // Deduplicate by src (external) or children (inline) before creating the object + const { children, ...attrs } = script + const key = attrs.src ?? String(children ?? '') + if (seen.has(key)) continue + seen.add(key) + result.push({ + tag: 'script', + attrs: { + ...attrs, + nonce, + }, + children: children as string | undefined, + }) + } + } + + return result + }, structuralSharing: true as any, }) - return uniqBy( - [ - ...meta, - ...preloadLinks, - ...links, - ...styles, - ...headScripts, - ] as Array, - (d) => { - return JSON.stringify(d) - }, - ) + return [ + ...(title ? [title] : []), + ...metaTags, + ...ldJsonScripts, + ...preloadLinks, + ...links, + ...styles, + ...headScripts, + ] as Array } -export function uniqBy(arr: Array, fn: (item: T) => string) { +export function uniqBy(arr: Array, fn: (item: T) => string): Array { const seen = new Set() - return arr.filter((item) => { + const result: Array = [] + for (const item of arr) { const key = fn(item) - if (seen.has(key)) { - return false - } + if (seen.has(key)) continue seen.add(key) - return true - }) + result.push(item) + } + return result } From 302591deb0153ebf8e893b441dd81526ed6f3f3f Mon Sep 17 00:00:00 2001 From: Sheraff Date: Mon, 26 Jan 2026 10:35:21 +0100 Subject: [PATCH 2/3] add type constraints to head props --- packages/react-router/src/Matches.tsx | 21 ++++++++++++++++++--- packages/solid-router/src/Matches.tsx | 21 ++++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/react-router/src/Matches.tsx b/packages/react-router/src/Matches.tsx index de8a2ea73ed..0c79cb6da8e 100644 --- a/packages/react-router/src/Matches.tsx +++ b/packages/react-router/src/Matches.tsx @@ -36,9 +36,24 @@ declare module '@tanstack/router-core' { export interface RouteMatchExtensions { meta?: Array links?: Array - scripts?: Array - styles?: Array - headScripts?: Array + scripts?: Array< + | (React.JSX.IntrinsicElements['script'] & { + children?: string | null | boolean | number | undefined + }) + | undefined + > + styles?: Array< + | (React.JSX.IntrinsicElements['style'] & { + children?: string | null | boolean | number | undefined + }) + | undefined + > + headScripts?: Array< + | (React.JSX.IntrinsicElements['script'] & { + children?: string | null | boolean | number | undefined + }) + | undefined + > } } diff --git a/packages/solid-router/src/Matches.tsx b/packages/solid-router/src/Matches.tsx index a39f09a4dbc..1ed5188141e 100644 --- a/packages/solid-router/src/Matches.tsx +++ b/packages/solid-router/src/Matches.tsx @@ -32,9 +32,24 @@ declare module '@tanstack/router-core' { export interface RouteMatchExtensions { meta?: Array links?: Array - scripts?: Array - styles?: Array - headScripts?: Array + scripts?: Array< + | (Solid.JSX.IntrinsicElements['script'] & { + children?: string | null | boolean | number | undefined + }) + | undefined + > + styles?: Array< + | (Solid.JSX.IntrinsicElements['style'] & { + children?: string | null | boolean | number | undefined + }) + | undefined + > + headScripts?: Array< + | (Solid.JSX.IntrinsicElements['script'] & { + children?: string | null | boolean | number | undefined + }) + | undefined + > } } From dadb39d8ee331be27141840e2d1a91d933ae83d0 Mon Sep 17 00:00:00 2001 From: Sheraff Date: Mon, 26 Jan 2026 10:50:56 +0100 Subject: [PATCH 3/3] fix unicity keys --- .../react-router/src/headContentUtils.tsx | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/packages/react-router/src/headContentUtils.tsx b/packages/react-router/src/headContentUtils.tsx index 8d8edbe8846..e0a78ba87e7 100644 --- a/packages/react-router/src/headContentUtils.tsx +++ b/packages/react-router/src/headContentUtils.tsx @@ -64,8 +64,8 @@ export const useTags = () => { // Skip invalid JSON-LD objects } } else { - // Deduplicate by name or property attribute - const key = m.name ?? m.property ?? '' + // Deduplicate + const key = `${m.name ?? m.property}\0${m.content}\0${m.media}` if (key) { if (seenMeta.has(key)) continue seenMeta.add(key) @@ -112,8 +112,8 @@ export const useTags = () => { if (matchLinks) { for (const link of matchLinks) { if (!link) continue - // Deduplicate by rel:href before creating the object - const key = `${link.rel ?? ''}:${link.href ?? ''}` + // Deduplicate + const key = `${link.rel}\0${link.href}\0${link.media}\0${link.type}\0${link.as}` if (seen.has(key)) continue seen.add(key) result.push({ @@ -131,9 +131,10 @@ export const useTags = () => { if (assets) { for (const asset of assets) { if (asset.tag !== 'link') continue - // Deduplicate by rel:href before creating the object const attrs = asset.attrs - const key = `${attrs?.rel ?? ''}:${attrs?.href ?? ''}` + if (!attrs) continue + // Deduplicate + const key = `${attrs.rel}\0${attrs.href}\0${attrs.media}\0${attrs.type}\0${attrs.as}` if (seen.has(key)) continue seen.add(key) result.push({ @@ -198,9 +199,9 @@ export const useTags = () => { for (const style of matchStyles) { if (!style) continue - // Deduplicate by children (CSS content) before creating the object + // Deduplicate const { children, ...attrs } = style - const key = String(children ?? '') + const key = `${attrs.media}\0${children}` if (seen.has(key)) continue seen.add(key) result.push({ @@ -230,9 +231,9 @@ export const useTags = () => { for (const script of matchScripts) { if (!script) continue - // Deduplicate by src (external) or children (inline) before creating the object + // Deduplicate const { children, ...attrs } = script - const key = attrs.src ?? String(children ?? '') + const key = `${attrs.src}\0${attrs.type}\0${children}` if (seen.has(key)) continue seen.add(key) result.push({ @@ -261,15 +262,3 @@ export const useTags = () => { ...headScripts, ] as Array } - -export function uniqBy(arr: Array, fn: (item: T) => string): Array { - const seen = new Set() - const result: Array = [] - for (const item of arr) { - const key = fn(item) - if (seen.has(key)) continue - seen.add(key) - result.push(item) - } - return result -}