@tanstack/solid-router 1.147.1 → 1.149.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/cjs/HeadContent.cjs +5 -196
  2. package/dist/cjs/HeadContent.cjs.map +1 -1
  3. package/dist/cjs/HeadContent.d.cts +1 -4
  4. package/dist/cjs/HeadContent.dev.cjs +36 -0
  5. package/dist/cjs/HeadContent.dev.cjs.map +1 -0
  6. package/dist/cjs/HeadContent.dev.d.cts +10 -0
  7. package/dist/cjs/headContentUtils.cjs +174 -0
  8. package/dist/cjs/headContentUtils.cjs.map +1 -0
  9. package/dist/cjs/headContentUtils.d.cts +7 -0
  10. package/dist/cjs/index.cjs +2 -1
  11. package/dist/cjs/index.cjs.map +1 -1
  12. package/dist/cjs/index.d.cts +2 -1
  13. package/dist/cjs/index.dev.cjs +259 -0
  14. package/dist/cjs/index.dev.cjs.map +1 -0
  15. package/dist/cjs/index.dev.d.cts +2 -0
  16. package/dist/cjs/ssr/RouterServer.cjs +2 -2
  17. package/dist/cjs/ssr/RouterServer.cjs.map +1 -1
  18. package/dist/esm/HeadContent.d.ts +1 -4
  19. package/dist/esm/HeadContent.dev.d.ts +10 -0
  20. package/dist/esm/HeadContent.dev.js +36 -0
  21. package/dist/esm/HeadContent.dev.js.map +1 -0
  22. package/dist/esm/HeadContent.js +6 -181
  23. package/dist/esm/HeadContent.js.map +1 -1
  24. package/dist/esm/headContentUtils.d.ts +7 -0
  25. package/dist/esm/headContentUtils.js +157 -0
  26. package/dist/esm/headContentUtils.js.map +1 -0
  27. package/dist/esm/index.d.ts +2 -1
  28. package/dist/esm/index.dev.d.ts +2 -0
  29. package/dist/esm/index.dev.js +142 -0
  30. package/dist/esm/index.dev.js.map +1 -0
  31. package/dist/esm/index.js +2 -1
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/esm/ssr/RouterServer.js +1 -1
  34. package/dist/esm/ssr/RouterServer.js.map +1 -1
  35. package/dist/source/HeadContent.d.ts +1 -4
  36. package/dist/source/HeadContent.dev.d.ts +10 -0
  37. package/dist/source/HeadContent.dev.jsx +39 -0
  38. package/dist/source/HeadContent.dev.jsx.map +1 -0
  39. package/dist/source/HeadContent.jsx +2 -202
  40. package/dist/source/HeadContent.jsx.map +1 -1
  41. package/dist/source/headContentUtils.d.ts +7 -0
  42. package/dist/source/headContentUtils.jsx +181 -0
  43. package/dist/source/headContentUtils.jsx.map +1 -0
  44. package/dist/source/index.d.ts +2 -1
  45. package/dist/source/index.dev.d.ts +2 -0
  46. package/dist/source/index.dev.jsx +6 -0
  47. package/dist/source/index.dev.jsx.map +1 -0
  48. package/dist/source/index.jsx +2 -1
  49. package/dist/source/index.jsx.map +1 -1
  50. package/dist/source/ssr/RouterServer.jsx +1 -1
  51. package/dist/source/ssr/RouterServer.jsx.map +1 -1
  52. package/package.json +5 -2
  53. package/src/HeadContent.dev.tsx +45 -0
  54. package/src/HeadContent.tsx +2 -235
  55. package/src/headContentUtils.tsx +209 -0
  56. package/src/index.dev.tsx +6 -0
  57. package/src/index.tsx +2 -1
  58. package/src/ssr/RouterServer.tsx +1 -1
@@ -0,0 +1,157 @@
1
+ import * as Solid from "solid-js";
2
+ import { escapeHtml } from "@tanstack/router-core";
3
+ import { useRouter } from "./useRouter.js";
4
+ import { useRouterState } from "./useRouterState.js";
5
+ const useTags = () => {
6
+ const router = useRouter();
7
+ const nonce = router.options.ssr?.nonce;
8
+ const routeMeta = useRouterState({
9
+ select: (state) => {
10
+ return state.matches.map((match) => match.meta).filter(Boolean);
11
+ }
12
+ });
13
+ const meta = Solid.createMemo(() => {
14
+ const resultMeta = [];
15
+ const metaByAttribute = {};
16
+ let title;
17
+ const routeMetasArray = routeMeta();
18
+ for (let i = routeMetasArray.length - 1; i >= 0; i--) {
19
+ const metas = routeMetasArray[i];
20
+ for (let j = metas.length - 1; j >= 0; j--) {
21
+ const m = metas[j];
22
+ if (!m) continue;
23
+ if (m.title) {
24
+ if (!title) {
25
+ title = {
26
+ tag: "title",
27
+ children: m.title
28
+ };
29
+ }
30
+ } else if ("script:ld+json" in m) {
31
+ try {
32
+ const json = JSON.stringify(m["script:ld+json"]);
33
+ resultMeta.push({
34
+ tag: "script",
35
+ attrs: {
36
+ type: "application/ld+json"
37
+ },
38
+ children: escapeHtml(json)
39
+ });
40
+ } catch {
41
+ }
42
+ } else {
43
+ const attribute = m.name ?? m.property;
44
+ if (attribute) {
45
+ if (metaByAttribute[attribute]) {
46
+ continue;
47
+ } else {
48
+ metaByAttribute[attribute] = true;
49
+ }
50
+ }
51
+ resultMeta.push({
52
+ tag: "meta",
53
+ attrs: {
54
+ ...m,
55
+ nonce
56
+ }
57
+ });
58
+ }
59
+ }
60
+ }
61
+ if (title) {
62
+ resultMeta.push(title);
63
+ }
64
+ if (router.options.ssr?.nonce) {
65
+ resultMeta.push({
66
+ tag: "meta",
67
+ attrs: {
68
+ property: "csp-nonce",
69
+ content: router.options.ssr.nonce
70
+ }
71
+ });
72
+ }
73
+ resultMeta.reverse();
74
+ return resultMeta;
75
+ });
76
+ const links = useRouterState({
77
+ select: (state) => {
78
+ const constructed = state.matches.map((match) => match.links).filter(Boolean).flat(1).map((link) => ({
79
+ tag: "link",
80
+ attrs: {
81
+ ...link,
82
+ nonce
83
+ }
84
+ }));
85
+ const manifest = router.ssr?.manifest;
86
+ const assets = state.matches.map((match) => manifest?.routes[match.routeId]?.assets ?? []).filter(Boolean).flat(1).filter((asset) => asset.tag === "link").map((asset) => ({
87
+ tag: "link",
88
+ attrs: {
89
+ ...asset.attrs,
90
+ nonce
91
+ }
92
+ }));
93
+ return [...constructed, ...assets];
94
+ }
95
+ });
96
+ const preloadLinks = useRouterState({
97
+ select: (state) => {
98
+ const preloadLinks2 = [];
99
+ state.matches.map((match) => router.looseRoutesById[match.routeId]).forEach((route) => router.ssr?.manifest?.routes[route.id]?.preloads?.filter(Boolean).forEach((preload) => {
100
+ preloadLinks2.push({
101
+ tag: "link",
102
+ attrs: {
103
+ rel: "modulepreload",
104
+ href: preload,
105
+ nonce
106
+ }
107
+ });
108
+ }));
109
+ return preloadLinks2;
110
+ }
111
+ });
112
+ const styles = useRouterState({
113
+ select: (state) => state.matches.map((match) => match.styles).flat(1).filter(Boolean).map(({
114
+ children,
115
+ ...style
116
+ }) => ({
117
+ tag: "style",
118
+ attrs: {
119
+ ...style,
120
+ nonce
121
+ },
122
+ children
123
+ }))
124
+ });
125
+ const headScripts = useRouterState({
126
+ select: (state) => state.matches.map((match) => match.headScripts).flat(1).filter(Boolean).map(({
127
+ children,
128
+ ...script
129
+ }) => ({
130
+ tag: "script",
131
+ attrs: {
132
+ ...script,
133
+ nonce
134
+ },
135
+ children
136
+ }))
137
+ });
138
+ return () => uniqBy([...meta(), ...preloadLinks(), ...links(), ...styles(), ...headScripts()], (d) => {
139
+ return JSON.stringify(d);
140
+ });
141
+ };
142
+ function uniqBy(arr, fn) {
143
+ const seen = /* @__PURE__ */ new Set();
144
+ return arr.filter((item) => {
145
+ const key = fn(item);
146
+ if (seen.has(key)) {
147
+ return false;
148
+ }
149
+ seen.add(key);
150
+ return true;
151
+ });
152
+ }
153
+ export {
154
+ uniqBy,
155
+ useTags
156
+ };
157
+ //# sourceMappingURL=headContentUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headContentUtils.js","sources":["../../src/headContentUtils.tsx"],"sourcesContent":["import * as Solid from 'solid-js'\nimport { escapeHtml } from '@tanstack/router-core'\nimport { useRouter } from './useRouter'\nimport { useRouterState } from './useRouterState'\nimport type { RouterManagedTag } 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 = () => {\n const router = useRouter()\n const nonce = router.options.ssr?.nonce\n const routeMeta = useRouterState({\n select: (state) => {\n return state.matches.map((match) => match.meta!).filter(Boolean)\n },\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 = useRouterState({\n select: (state) => {\n const constructed = state.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 = state.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: { ...asset.attrs, nonce },\n }) satisfies RouterManagedTag,\n )\n\n return [...constructed, ...assets]\n },\n })\n\n const preloadLinks = useRouterState({\n select: (state) => {\n const preloadLinks: Array<RouterManagedTag> = []\n\n state.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 preloadLinks.push({\n tag: 'link',\n attrs: {\n rel: 'modulepreload',\n href: preload,\n nonce,\n },\n })\n }),\n )\n\n return preloadLinks\n },\n })\n\n const styles = useRouterState({\n select: (state) =>\n (\n state.matches\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 = useRouterState({\n select: (state) =>\n (\n state.matches\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 () =>\n uniqBy(\n [\n ...meta(),\n ...preloadLinks(),\n ...links(),\n ...styles(),\n ...headScripts(),\n ] as Array<RouterManagedTag>,\n (d) => {\n return JSON.stringify(d)\n },\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"],"names":["useTags","router","useRouter","nonce","options","ssr","routeMeta","useRouterState","select","state","matches","map","match","meta","filter","Boolean","Solid","createMemo","resultMeta","metaByAttribute","title","routeMetasArray","i","length","metas","j","m","tag","children","json","JSON","stringify","push","attrs","type","escapeHtml","attribute","name","property","content","reverse","links","constructed","flat","link","manifest","assets","routes","routeId","asset","preloadLinks","looseRoutesById","forEach","route","id","preloads","preload","rel","href","styles","style","headScripts","script","uniqBy","d","arr","fn","seen","Set","item","key","has","add"],"mappings":"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"}
@@ -45,7 +45,8 @@ export type { ValidateLinkOptions, ValidateUseSearchOptions, ValidateUseParamsOp
45
45
  export type { ValidateFromPath, ValidateToPath, ValidateSearch, ValidateParams, InferFrom, InferTo, InferMaskTo, InferMaskFrom, ValidateNavigateOptions, ValidateNavigateOptionsArray, ValidateRedirectOptions, ValidateRedirectOptionsArray, ValidateId, InferStrict, InferShouldThrow, InferSelected, ValidateUseSearchResult, ValidateUseParamsResult, } from '@tanstack/router-core';
46
46
  export { ScriptOnce } from './ScriptOnce.js';
47
47
  export { Asset } from './Asset.js';
48
- export { HeadContent, useTags } from './HeadContent.js';
48
+ export { HeadContent } from './HeadContent.js';
49
+ export { useTags } from './headContentUtils.js';
49
50
  export { Scripts } from './Scripts.js';
50
51
  export { composeRewrites } from '@tanstack/router-core';
51
52
  export type { LocationRewrite, LocationRewriteFunction, } from '@tanstack/router-core';
@@ -0,0 +1,2 @@
1
+ export * from './index.js';
2
+ export { HeadContent } from './HeadContent.dev';
@@ -0,0 +1,142 @@
1
+ import { PathParamError, SearchParamError, TSR_DEFERRED_PROMISE, cleanPath, componentTypes, composeRewrites, createControlledPromise, createSerializationAdapter, deepEqual, defaultParseSearch, defaultSerializeError, defaultStringifySearch, defer, functionalUpdate, getInitialRouterState, interpolatePath, isMatch, isNotFound, isPlainArray, isPlainObject, isRedirect, joinPaths, lazyFn, notFound, parseSearchWith, redirect, replaceEqualDeep, resolvePath, retainSearchParams, rootRouteId, stringifySearchWith, stripSearchParams, trimPath, trimPathLeft, trimPathRight } from "@tanstack/router-core";
2
+ import { createBrowserHistory, createHashHistory, createHistory, createMemoryHistory } from "@tanstack/history";
3
+ import { Await, useAwaited } from "./awaited.js";
4
+ import { CatchBoundary, ErrorComponent } from "./CatchBoundary.js";
5
+ import { ClientOnly, useHydrated } from "./ClientOnly.js";
6
+ import { FileRoute, FileRouteLoader, LazyRoute, createFileRoute, createLazyFileRoute, createLazyRoute } from "./fileRoute.js";
7
+ import { lazyRouteComponent } from "./lazyRouteComponent.js";
8
+ import { Link, createLink, linkOptions, useLinkProps } from "./link.js";
9
+ import { MatchRoute, Matches, useChildMatches, useMatchRoute, useMatches, useParentMatches } from "./Matches.js";
10
+ import { matchContext } from "./matchContext.js";
11
+ import { Match, Outlet } from "./Match.js";
12
+ import { useMatch } from "./useMatch.js";
13
+ import { useLoaderDeps } from "./useLoaderDeps.js";
14
+ import { useLoaderData } from "./useLoaderData.js";
15
+ import { NotFoundRoute, RootRoute, Route, RouteApi, createRootRoute, createRootRouteWithContext, createRoute, createRouteMask, getRouteApi, rootRouteWithContext } from "./route.js";
16
+ import { Router, createRouter } from "./router.js";
17
+ import { RouterContextProvider, RouterProvider } from "./RouterProvider.js";
18
+ import { ScrollRestoration, useElementScrollRestoration } from "./ScrollRestoration.js";
19
+ import { Block, useBlocker } from "./useBlocker.js";
20
+ import { Navigate, useNavigate } from "./useNavigate.js";
21
+ import { useParams } from "./useParams.js";
22
+ import { useSearch } from "./useSearch.js";
23
+ import { getRouterContext } from "./routerContext.js";
24
+ import { useRouteContext } from "./useRouteContext.js";
25
+ import { useRouter } from "./useRouter.js";
26
+ import { useRouterState } from "./useRouterState.js";
27
+ import { useLocation } from "./useLocation.js";
28
+ import { useCanGoBack } from "./useCanGoBack.js";
29
+ import { useLayoutEffect } from "./utils.js";
30
+ import { CatchNotFound, DefaultGlobalNotFound } from "./not-found.js";
31
+ import { ScriptOnce } from "./ScriptOnce.js";
32
+ import { Asset } from "./Asset.js";
33
+ import { useTags } from "./headContentUtils.js";
34
+ import { Scripts } from "./Scripts.js";
35
+ import { HeadContent } from "./HeadContent.dev.js";
36
+ export {
37
+ Asset,
38
+ Await,
39
+ Block,
40
+ CatchBoundary,
41
+ CatchNotFound,
42
+ ClientOnly,
43
+ DefaultGlobalNotFound,
44
+ ErrorComponent,
45
+ FileRoute,
46
+ FileRouteLoader,
47
+ HeadContent,
48
+ LazyRoute,
49
+ Link,
50
+ Match,
51
+ MatchRoute,
52
+ Matches,
53
+ Navigate,
54
+ NotFoundRoute,
55
+ Outlet,
56
+ PathParamError,
57
+ RootRoute,
58
+ Route,
59
+ RouteApi,
60
+ Router,
61
+ RouterContextProvider,
62
+ RouterProvider,
63
+ ScriptOnce,
64
+ Scripts,
65
+ ScrollRestoration,
66
+ SearchParamError,
67
+ TSR_DEFERRED_PROMISE,
68
+ cleanPath,
69
+ componentTypes,
70
+ composeRewrites,
71
+ createBrowserHistory,
72
+ createControlledPromise,
73
+ createFileRoute,
74
+ createHashHistory,
75
+ createHistory,
76
+ createLazyFileRoute,
77
+ createLazyRoute,
78
+ createLink,
79
+ createMemoryHistory,
80
+ createRootRoute,
81
+ createRootRouteWithContext,
82
+ createRoute,
83
+ createRouteMask,
84
+ createRouter,
85
+ createSerializationAdapter,
86
+ deepEqual,
87
+ defaultParseSearch,
88
+ defaultSerializeError,
89
+ defaultStringifySearch,
90
+ defer,
91
+ functionalUpdate,
92
+ getInitialRouterState,
93
+ getRouteApi,
94
+ getRouterContext,
95
+ interpolatePath,
96
+ isMatch,
97
+ isNotFound,
98
+ isPlainArray,
99
+ isPlainObject,
100
+ isRedirect,
101
+ joinPaths,
102
+ lazyFn,
103
+ lazyRouteComponent,
104
+ linkOptions,
105
+ matchContext,
106
+ notFound,
107
+ parseSearchWith,
108
+ redirect,
109
+ replaceEqualDeep,
110
+ resolvePath,
111
+ retainSearchParams,
112
+ rootRouteId,
113
+ rootRouteWithContext,
114
+ stringifySearchWith,
115
+ stripSearchParams,
116
+ trimPath,
117
+ trimPathLeft,
118
+ trimPathRight,
119
+ useAwaited,
120
+ useBlocker,
121
+ useCanGoBack,
122
+ useChildMatches,
123
+ useElementScrollRestoration,
124
+ useHydrated,
125
+ useLayoutEffect,
126
+ useLinkProps,
127
+ useLoaderData,
128
+ useLoaderDeps,
129
+ useLocation,
130
+ useMatch,
131
+ useMatchRoute,
132
+ useMatches,
133
+ useNavigate,
134
+ useParams,
135
+ useParentMatches,
136
+ useRouteContext,
137
+ useRouter,
138
+ useRouterState,
139
+ useSearch,
140
+ useTags
141
+ };
142
+ //# sourceMappingURL=index.dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.dev.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/esm/index.js CHANGED
@@ -30,7 +30,8 @@ import { useLayoutEffect } from "./utils.js";
30
30
  import { CatchNotFound, DefaultGlobalNotFound } from "./not-found.js";
31
31
  import { ScriptOnce } from "./ScriptOnce.js";
32
32
  import { Asset } from "./Asset.js";
33
- import { HeadContent, useTags } from "./HeadContent.js";
33
+ import { HeadContent } from "./HeadContent.js";
34
+ import { useTags } from "./headContentUtils.js";
34
35
  import { Scripts } from "./Scripts.js";
35
36
  export {
36
37
  Asset,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,7 +1,7 @@
1
1
  import { createComponent, NoHydration, ssr, template, insert, Hydration, useAssets } from "solid-js/web";
2
2
  import { MetaProvider } from "@solidjs/meta";
3
3
  import { Asset } from "../Asset.js";
4
- import { useTags } from "../HeadContent.js";
4
+ import { useTags } from "../headContentUtils.js";
5
5
  import { RouterProvider } from "../RouterProvider.js";
6
6
  import { Scripts } from "../Scripts.js";
7
7
  var _tmpl$ = /* @__PURE__ */ template(`<html><head></head><body>`);
@@ -1 +1 @@
1
- {"version":3,"file":"RouterServer.js","sources":["../../../src/ssr/RouterServer.tsx"],"sourcesContent":["import {\n Hydration,\n HydrationScript,\n NoHydration,\n ssr,\n useAssets,\n} from 'solid-js/web'\nimport { MetaProvider } from '@solidjs/meta'\nimport { Asset } from '../Asset'\nimport { useTags } from '../HeadContent'\nimport { RouterProvider } from '../RouterProvider'\nimport { Scripts } from '../Scripts'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nexport function ServerHeadContent() {\n const tags = useTags()\n useAssets(() => {\n return (\n <MetaProvider>\n {tags().map((tag) => (\n <Asset {...tag} />\n ))}\n </MetaProvider>\n )\n })\n return null\n}\n\nconst docType = ssr('<!DOCTYPE html>')\n\nexport function RouterServer<TRouter extends AnyRouter>(props: {\n router: TRouter\n}) {\n return (\n <NoHydration>\n {docType as any}\n <html>\n <head>\n <HydrationScript />\n </head>\n <body>\n <Hydration>\n <RouterProvider\n router={props.router}\n InnerWrap={(props) => (\n <NoHydration>\n <MetaProvider>\n <ServerHeadContent />\n <Hydration>{props.children}</Hydration>\n <Scripts />\n </MetaProvider>\n </NoHydration>\n )}\n />\n </Hydration>\n </body>\n </html>\n </NoHydration>\n )\n}\n"],"names":["ServerHeadContent","tags","useTags","useAssets","_$createComponent","MetaProvider","children","map","tag","Asset","docType","ssr","RouterServer","props","NoHydration","_el$","_tmpl$","_el$3","firstChild","_$insert","Hydration","RouterProvider","router","InnerWrap","Scripts"],"mappings":";;;;;;;AAcO,SAASA,oBAAoB;AAClC,QAAMC,OAAOC,QAAAA;AACbC,YAAU,MAAM;AACd,WAAAC,gBACGC,cAAY;AAAA,MAAA,IAAAC,WAAA;AAAA,eACVL,OAAOM,IAAKC,SAAGJ,gBACbK,OAAUD,GAAG,CACf;AAAA,MAAC;AAAA,IAAA,CAAA;AAAA,EAGR,CAAC;AACD,SAAO;AACT;AAEA,MAAME,UAAUC,IAAI,iBAAiB;AAE9B,SAASC,aAAwCC,OAErD;AACD,SAAAT,gBACGU,aAAW;AAAA,IAAA,IAAAR,WAAA;AAAA,aAAA,CACTI,UAAc,MAAA;AAAA,YAAAK,OAAAC,OAAAA,GAAAC,QAAAF,KAAAG;AAAAC,eAAAF,OAAAb,gBAMVgB,WAAS;AAAA,UAAA,IAAAd,WAAA;AAAA,mBAAAF,gBACPiB,gBAAc;AAAA,cAAA,IACbC,SAAM;AAAA,uBAAET,MAAMS;AAAAA,cAAM;AAAA,cACpBC,WAAYV,CAAAA,WAAKT,gBACdU,aAAW;AAAA,gBAAA,IAAAR,WAAA;AAAA,yBAAAF,gBACTC,cAAY;AAAA,oBAAA,IAAAC,WAAA;AAAA,6BAAA,CAAAF,gBACVJ,mBAAiB,CAAA,CAAA,GAAAI,gBACjBgB,WAAS;AAAA,wBAAA,IAAAd,WAAA;AAAA,iCAAEO,OAAMP;AAAAA,wBAAQ;AAAA,sBAAA,CAAA,GAAAF,gBACzBoB,SAAO,CAAA,CAAA,CAAA;AAAA,oBAAA;AAAA,kBAAA,CAAA;AAAA,gBAAA;AAAA,cAAA,CAAA;AAAA,YAAA,CAGb;AAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,eAAAT;AAAAA,MAAA,IAAA;AAAA,IAAA;AAAA,EAAA,CAAA;AAOf;"}
1
+ {"version":3,"file":"RouterServer.js","sources":["../../../src/ssr/RouterServer.tsx"],"sourcesContent":["import {\n Hydration,\n HydrationScript,\n NoHydration,\n ssr,\n useAssets,\n} from 'solid-js/web'\nimport { MetaProvider } from '@solidjs/meta'\nimport { Asset } from '../Asset'\nimport { useTags } from '../headContentUtils'\nimport { RouterProvider } from '../RouterProvider'\nimport { Scripts } from '../Scripts'\nimport type { AnyRouter } from '@tanstack/router-core'\n\nexport function ServerHeadContent() {\n const tags = useTags()\n useAssets(() => {\n return (\n <MetaProvider>\n {tags().map((tag) => (\n <Asset {...tag} />\n ))}\n </MetaProvider>\n )\n })\n return null\n}\n\nconst docType = ssr('<!DOCTYPE html>')\n\nexport function RouterServer<TRouter extends AnyRouter>(props: {\n router: TRouter\n}) {\n return (\n <NoHydration>\n {docType as any}\n <html>\n <head>\n <HydrationScript />\n </head>\n <body>\n <Hydration>\n <RouterProvider\n router={props.router}\n InnerWrap={(props) => (\n <NoHydration>\n <MetaProvider>\n <ServerHeadContent />\n <Hydration>{props.children}</Hydration>\n <Scripts />\n </MetaProvider>\n </NoHydration>\n )}\n />\n </Hydration>\n </body>\n </html>\n </NoHydration>\n )\n}\n"],"names":["ServerHeadContent","tags","useTags","useAssets","_$createComponent","MetaProvider","children","map","tag","Asset","docType","ssr","RouterServer","props","NoHydration","_el$","_tmpl$","_el$3","firstChild","_$insert","Hydration","RouterProvider","router","InnerWrap","Scripts"],"mappings":";;;;;;;AAcO,SAASA,oBAAoB;AAClC,QAAMC,OAAOC,QAAAA;AACbC,YAAU,MAAM;AACd,WAAAC,gBACGC,cAAY;AAAA,MAAA,IAAAC,WAAA;AAAA,eACVL,OAAOM,IAAKC,SAAGJ,gBACbK,OAAUD,GAAG,CACf;AAAA,MAAC;AAAA,IAAA,CAAA;AAAA,EAGR,CAAC;AACD,SAAO;AACT;AAEA,MAAME,UAAUC,IAAI,iBAAiB;AAE9B,SAASC,aAAwCC,OAErD;AACD,SAAAT,gBACGU,aAAW;AAAA,IAAA,IAAAR,WAAA;AAAA,aAAA,CACTI,UAAc,MAAA;AAAA,YAAAK,OAAAC,OAAAA,GAAAC,QAAAF,KAAAG;AAAAC,eAAAF,OAAAb,gBAMVgB,WAAS;AAAA,UAAA,IAAAd,WAAA;AAAA,mBAAAF,gBACPiB,gBAAc;AAAA,cAAA,IACbC,SAAM;AAAA,uBAAET,MAAMS;AAAAA,cAAM;AAAA,cACpBC,WAAYV,CAAAA,WAAKT,gBACdU,aAAW;AAAA,gBAAA,IAAAR,WAAA;AAAA,yBAAAF,gBACTC,cAAY;AAAA,oBAAA,IAAAC,WAAA;AAAA,6BAAA,CAAAF,gBACVJ,mBAAiB,CAAA,CAAA,GAAAI,gBACjBgB,WAAS;AAAA,wBAAA,IAAAd,WAAA;AAAA,iCAAEO,OAAMP;AAAAA,wBAAQ;AAAA,sBAAA,CAAA,GAAAF,gBACzBoB,SAAO,CAAA,CAAA,CAAA;AAAA,oBAAA;AAAA,kBAAA,CAAA;AAAA,gBAAA;AAAA,cAAA,CAAA;AAAA,YAAA,CAGb;AAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,eAAAT;AAAAA,MAAA,IAAA;AAAA,IAAA;AAAA,EAAA,CAAA;AAOf;"}
@@ -1,10 +1,7 @@
1
- import * as Solid from 'solid-js';
2
- import type { RouterManagedTag } from '@tanstack/router-core';
3
- export declare const useTags: () => () => RouterManagedTag[];
4
1
  /**
5
2
  * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
6
3
  * When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`
7
4
  * to ensure it's part of the reactive tree and updates correctly during client-side navigation.
8
5
  * The component uses portals internally to render content into the `<head>` element.
9
6
  */
10
- export declare function HeadContent(): Solid.JSX.Element;
7
+ export declare function HeadContent(): import("solid-js").JSX.Element;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
3
+ * When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`
4
+ * to ensure it's part of the reactive tree and updates correctly during client-side navigation.
5
+ * The component uses portals internally to render content into the `<head>` element.
6
+ *
7
+ * Development version: filters out dev styles link after hydration and
8
+ * includes a fallback cleanup effect for hydration mismatch cases.
9
+ */
10
+ export declare function HeadContent(): import("solid-js").JSX.Element;
@@ -0,0 +1,39 @@
1
+ import { MetaProvider } from '@solidjs/meta';
2
+ import { For, createEffect, createMemo } from 'solid-js';
3
+ import { Asset } from './Asset';
4
+ import { useHydrated } from './ClientOnly';
5
+ import { useTags } from './headContentUtils';
6
+ const DEV_STYLES_ATTR = 'data-tanstack-router-dev-styles';
7
+ /**
8
+ * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
9
+ * When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`
10
+ * to ensure it's part of the reactive tree and updates correctly during client-side navigation.
11
+ * The component uses portals internally to render content into the `<head>` element.
12
+ *
13
+ * Development version: filters out dev styles link after hydration and
14
+ * includes a fallback cleanup effect for hydration mismatch cases.
15
+ */
16
+ export function HeadContent() {
17
+ const tags = useTags();
18
+ const hydrated = useHydrated();
19
+ // Fallback cleanup for hydration mismatch cases
20
+ // Runs when hydration completes to remove any orphaned dev styles links from DOM
21
+ createEffect(() => {
22
+ if (hydrated()) {
23
+ document
24
+ .querySelectorAll(`link[${DEV_STYLES_ATTR}]`)
25
+ .forEach((el) => el.remove());
26
+ }
27
+ });
28
+ // Filter out dev styles after hydration
29
+ const filteredTags = createMemo(() => {
30
+ if (hydrated()) {
31
+ return tags().filter((tag) => !tag.attrs?.[DEV_STYLES_ATTR]);
32
+ }
33
+ return tags();
34
+ });
35
+ return (<MetaProvider>
36
+ <For each={filteredTags()}>{(tag) => <Asset {...tag}/>}</For>
37
+ </MetaProvider>);
38
+ }
39
+ //# sourceMappingURL=HeadContent.dev.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeadContent.dev.jsx","sourceRoot":"","sources":["../../src/HeadContent.dev.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAE5C,MAAM,eAAe,GAAG,iCAAiC,CAAA;AAEzD;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAE9B,gDAAgD;IAChD,iFAAiF;IACjF,YAAY,CAAC,GAAG,EAAE;QAChB,IAAI,QAAQ,EAAE,EAAE,CAAC;YACf,QAAQ;iBACL,gBAAgB,CAAC,QAAQ,eAAe,GAAG,CAAC;iBAC5C,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAA;QACjC,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,wCAAwC;IACxC,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;QACnC,IAAI,QAAQ,EAAE,EAAE,CAAC;YACf,OAAO,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,eAAe,CAAC,CAAC,CAAA;QAC9D,CAAC;QACD,OAAO,IAAI,EAAE,CAAA;IACf,CAAC,CAAC,CAAA;IAEF,OAAO,CACL,CAAC,YAAY,CACX;MAAA,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAG,CAAC,EAAE,GAAG,CAC/D;IAAA,EAAE,YAAY,CAAC,CAChB,CAAA;AACH,CAAC"}
@@ -1,193 +1,7 @@
1
- import * as Solid from 'solid-js';
2
1
  import { MetaProvider } from '@solidjs/meta';
3
- import { For, Show, onMount } from 'solid-js';
4
- import { buildDevStylesUrl, escapeHtml } from '@tanstack/router-core';
2
+ import { For } from 'solid-js';
5
3
  import { Asset } from './Asset';
6
- import { useRouter } from './useRouter';
7
- import { useRouterState } from './useRouterState';
8
- export const useTags = () => {
9
- const router = useRouter();
10
- const nonce = router.options.ssr?.nonce;
11
- const routeMeta = useRouterState({
12
- select: (state) => {
13
- return state.matches.map((match) => match.meta).filter(Boolean);
14
- },
15
- });
16
- const meta = Solid.createMemo(() => {
17
- const resultMeta = [];
18
- const metaByAttribute = {};
19
- let title;
20
- const routeMetasArray = routeMeta();
21
- for (let i = routeMetasArray.length - 1; i >= 0; i--) {
22
- const metas = routeMetasArray[i];
23
- for (let j = metas.length - 1; j >= 0; j--) {
24
- const m = metas[j];
25
- if (!m)
26
- continue;
27
- if (m.title) {
28
- if (!title) {
29
- title = {
30
- tag: 'title',
31
- children: m.title,
32
- };
33
- }
34
- }
35
- else if ('script:ld+json' in m) {
36
- // Handle JSON-LD structured data
37
- // Content is HTML-escaped to prevent XSS when injected via innerHTML
38
- try {
39
- const json = JSON.stringify(m['script:ld+json']);
40
- resultMeta.push({
41
- tag: 'script',
42
- attrs: {
43
- type: 'application/ld+json',
44
- },
45
- children: escapeHtml(json),
46
- });
47
- }
48
- catch {
49
- // Skip invalid JSON-LD objects
50
- }
51
- }
52
- else {
53
- const attribute = m.name ?? m.property;
54
- if (attribute) {
55
- if (metaByAttribute[attribute]) {
56
- continue;
57
- }
58
- else {
59
- metaByAttribute[attribute] = true;
60
- }
61
- }
62
- resultMeta.push({
63
- tag: 'meta',
64
- attrs: {
65
- ...m,
66
- nonce,
67
- },
68
- });
69
- }
70
- }
71
- }
72
- if (title) {
73
- resultMeta.push(title);
74
- }
75
- if (router.options.ssr?.nonce) {
76
- resultMeta.push({
77
- tag: 'meta',
78
- attrs: {
79
- property: 'csp-nonce',
80
- content: router.options.ssr.nonce,
81
- },
82
- });
83
- }
84
- resultMeta.reverse();
85
- return resultMeta;
86
- });
87
- const links = useRouterState({
88
- select: (state) => {
89
- const constructed = state.matches
90
- .map((match) => match.links)
91
- .filter(Boolean)
92
- .flat(1)
93
- .map((link) => ({
94
- tag: 'link',
95
- attrs: {
96
- ...link,
97
- nonce,
98
- },
99
- }));
100
- const manifest = router.ssr?.manifest;
101
- // These are the assets extracted from the ViteManifest
102
- // using the `startManifestPlugin`
103
- const assets = state.matches
104
- .map((match) => manifest?.routes[match.routeId]?.assets ?? [])
105
- .filter(Boolean)
106
- .flat(1)
107
- .filter((asset) => asset.tag === 'link')
108
- .map((asset) => ({
109
- tag: 'link',
110
- attrs: { ...asset.attrs, nonce },
111
- }));
112
- return [...constructed, ...assets];
113
- },
114
- });
115
- const preloadLinks = useRouterState({
116
- select: (state) => {
117
- const preloadLinks = [];
118
- state.matches
119
- .map((match) => router.looseRoutesById[match.routeId])
120
- .forEach((route) => router.ssr?.manifest?.routes[route.id]?.preloads
121
- ?.filter(Boolean)
122
- .forEach((preload) => {
123
- preloadLinks.push({
124
- tag: 'link',
125
- attrs: {
126
- rel: 'modulepreload',
127
- href: preload,
128
- nonce,
129
- },
130
- });
131
- }));
132
- return preloadLinks;
133
- },
134
- });
135
- const styles = useRouterState({
136
- select: (state) => state.matches
137
- .map((match) => match.styles)
138
- .flat(1)
139
- .filter(Boolean).map(({ children, ...style }) => ({
140
- tag: 'style',
141
- attrs: {
142
- ...style,
143
- nonce,
144
- },
145
- children,
146
- })),
147
- });
148
- const headScripts = useRouterState({
149
- select: (state) => state.matches
150
- .map((match) => match.headScripts)
151
- .flat(1)
152
- .filter(Boolean).map(({ children, ...script }) => ({
153
- tag: 'script',
154
- attrs: {
155
- ...script,
156
- nonce,
157
- },
158
- children,
159
- })),
160
- });
161
- return () => uniqBy([
162
- ...meta(),
163
- ...preloadLinks(),
164
- ...links(),
165
- ...styles(),
166
- ...headScripts(),
167
- ], (d) => {
168
- return JSON.stringify(d);
169
- });
170
- };
171
- /**
172
- * Renders a stylesheet link for dev mode CSS collection.
173
- * On the server, renders the full link with route-scoped CSS URL.
174
- * On the client, renders the same link to avoid hydration mismatch,
175
- * then removes it after hydration since Vite's HMR handles CSS updates.
176
- */
177
- function DevStylesLink() {
178
- const router = useRouter();
179
- const routeIds = useRouterState({
180
- select: (state) => state.matches.map((match) => match.routeId),
181
- });
182
- onMount(() => {
183
- // After hydration, remove the SSR-rendered dev styles link
184
- document
185
- .querySelectorAll('[data-tanstack-start-dev-styles]')
186
- .forEach((el) => el.remove());
187
- });
188
- const href = () => buildDevStylesUrl(router.basepath, routeIds());
189
- return <link rel="stylesheet" href={href()} data-tanstack-start-dev-styles/>;
190
- }
4
+ import { useTags } from './headContentUtils';
191
5
  /**
192
6
  * @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
193
7
  * When using full document hydration (hydrating from `<html>`), this component should be rendered in the `<body>`
@@ -197,21 +11,7 @@ function DevStylesLink() {
197
11
  export function HeadContent() {
198
12
  const tags = useTags();
199
13
  return (<MetaProvider>
200
- <Show when={process.env.NODE_ENV !== 'production'}>
201
- <DevStylesLink />
202
- </Show>
203
14
  <For each={tags()}>{(tag) => <Asset {...tag}/>}</For>
204
15
  </MetaProvider>);
205
16
  }
206
- function uniqBy(arr, fn) {
207
- const seen = new Set();
208
- return arr.filter((item) => {
209
- const key = fn(item);
210
- if (seen.has(key)) {
211
- return false;
212
- }
213
- seen.add(key);
214
- return true;
215
- });
216
- }
217
17
  //# sourceMappingURL=HeadContent.jsx.map