@tanstack/router-core 1.171.4 → 1.171.6
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.
- package/dist/cjs/index.cjs +5 -1
- package/dist/cjs/index.d.cts +2 -2
- package/dist/cjs/manifest.cjs +43 -17
- package/dist/cjs/manifest.cjs.map +1 -1
- package/dist/cjs/manifest.d.cts +76 -24
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +2 -2
- package/dist/cjs/scroll-restoration-inline.cjs +1 -1
- package/dist/cjs/scroll-restoration-inline.cjs.map +1 -1
- package/dist/cjs/scroll-restoration-inline.d.cts +1 -4
- package/dist/cjs/scroll-restoration-script/server.cjs +5 -8
- package/dist/cjs/scroll-restoration-script/server.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.cjs +32 -32
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/ssr/createRequestHandler.cjs +2 -1
- package/dist/cjs/ssr/createRequestHandler.cjs.map +1 -1
- package/dist/cjs/ssr/createRequestHandler.d.cts +2 -2
- package/dist/cjs/ssr/ssr-server.cjs +132 -83
- package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
- package/dist/cjs/ssr/ssr-server.d.cts +4 -5
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/manifest.d.ts +76 -24
- package/dist/esm/manifest.js +39 -17
- package/dist/esm/manifest.js.map +1 -1
- package/dist/esm/router.d.ts +2 -2
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration-inline.d.ts +1 -4
- package/dist/esm/scroll-restoration-inline.js +1 -1
- package/dist/esm/scroll-restoration-inline.js.map +1 -1
- package/dist/esm/scroll-restoration-script/server.js +5 -8
- package/dist/esm/scroll-restoration-script/server.js.map +1 -1
- package/dist/esm/scroll-restoration.js +32 -32
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/ssr/createRequestHandler.d.ts +2 -2
- package/dist/esm/ssr/createRequestHandler.js +2 -1
- package/dist/esm/ssr/createRequestHandler.js.map +1 -1
- package/dist/esm/ssr/ssr-server.d.ts +4 -5
- package/dist/esm/ssr/ssr-server.js +133 -84
- package/dist/esm/ssr/ssr-server.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +21 -1
- package/src/manifest.ts +151 -59
- package/src/router.ts +6 -4
- package/src/scroll-restoration-inline.ts +19 -38
- package/src/scroll-restoration-script/server.ts +5 -17
- package/src/scroll-restoration.ts +35 -40
- package/src/ssr/createRequestHandler.ts +6 -5
- package/src/ssr/ssr-server.ts +239 -141
package/dist/cjs/router.d.cts
CHANGED
|
@@ -10,7 +10,7 @@ import { AnyContext, AnyRoute, AnyRouteWithContext, LoaderStaleReloadMode, MakeR
|
|
|
10
10
|
import { FullSearchSchema, RouteById, RoutePaths, RoutesById, RoutesByPath } from './routeInfo.cjs';
|
|
11
11
|
import { AnyRouteMatch, MakeRouteMatchUnion, MatchRouteOptions } from './Matches.cjs';
|
|
12
12
|
import { BuildLocationFn, CommitLocationOptions, NavigateFn } from './RouterProvider.cjs';
|
|
13
|
-
import { Manifest, RouterManagedTag } from './manifest.cjs';
|
|
13
|
+
import { Manifest, ManifestRouteAssets, RouterManagedTag } from './manifest.cjs';
|
|
14
14
|
import { AnySchema } from './validators.cjs';
|
|
15
15
|
import { NavigateOptions, ResolveRelativePath, ToOptions } from './link.cjs';
|
|
16
16
|
import { AnySerializationAdapter, ValidateSerializableInput } from './ssr/serializer/transformer.cjs';
|
|
@@ -522,7 +522,7 @@ export interface ServerSsr {
|
|
|
522
522
|
cleanup: () => void;
|
|
523
523
|
onSerializationFinished: (listener: () => void) => void;
|
|
524
524
|
dehydrate: (opts?: {
|
|
525
|
-
requestAssets?:
|
|
525
|
+
requestAssets?: ManifestRouteAssets;
|
|
526
526
|
}) => Promise<void>;
|
|
527
527
|
takeBufferedScripts: () => RouterManagedTag | undefined;
|
|
528
528
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/scroll-restoration-inline.ts?script-string
|
|
2
|
-
var scroll_restoration_inline_default = "function(
|
|
2
|
+
var scroll_restoration_inline_default = "function(a,f){let l;try{l=JSON.parse(sessionStorage.getItem(a)||\"{}\")}catch{return}const n=l?.[f||history.state?.__TSR_key];let c=!1;for(const t in n){const e=n[t],o=e?.scrollX,s=e?.scrollY;if(Number.isFinite(o)&&Number.isFinite(s)){if(t===\"window\")scrollTo(o,s),c=!0;else if(t)try{const r=document.querySelector(t);r&&(r.scrollLeft=o,r.scrollTop=s)}catch{}}}if(c)return;const i=location.hash.slice(1);if(i){const t=history.state?.__hashScrollIntoViewOptions??!0;if(t){const e=document.getElementById(i);e&&e.scrollIntoView(t)}return}scrollTo(0,0)}";
|
|
3
3
|
//#endregion
|
|
4
4
|
exports.default = scroll_restoration_inline_default;
|
|
5
5
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-restoration-inline.cjs","names":[],"sources":["../../src/scroll-restoration-inline.ts?script-string"],"sourcesContent":["export default function (
|
|
1
|
+
{"version":3,"file":"scroll-restoration-inline.cjs","names":[],"sources":["../../src/scroll-restoration-inline.ts?script-string"],"sourcesContent":["export default function (storageKey: string, key?: string) {\n let byKey\n\n try {\n byKey = JSON.parse(sessionStorage.getItem(storageKey) || '{}')\n } catch {\n return\n }\n\n const elementEntries = byKey?.[key || history.state?.__TSR_key]\n let windowRestored = false\n\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]\n const scrollX = entry?.scrollX\n const scrollY = entry?.scrollY\n\n if (Number.isFinite(scrollX) && Number.isFinite(scrollY)) {\n if (elementSelector === 'window') {\n scrollTo(scrollX, scrollY)\n windowRestored = true\n } else if (elementSelector) {\n try {\n const element = document.querySelector(elementSelector)\n if (element) {\n element.scrollLeft = scrollX\n element.scrollTop = scrollY\n }\n } catch {}\n }\n }\n }\n\n if (windowRestored) return\n\n const hash = location.hash.slice(1)\n\n if (hash) {\n const hashScrollIntoViewOptions =\n history.state?.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions) {\n const el = document.getElementById(hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n\n return\n }\n\n scrollTo(0, 0)\n}\n"],"mappings":";AAAA,IAAA,oCAAe"}
|
|
@@ -3,10 +3,10 @@ const require_utils = require("../utils.cjs");
|
|
|
3
3
|
const require_scroll_restoration = require("../scroll-restoration.cjs");
|
|
4
4
|
const require_scroll_restoration_inline = require("../scroll-restoration-inline.cjs");
|
|
5
5
|
//#region src/scroll-restoration-script/server.ts
|
|
6
|
-
const defaultInlineScrollRestorationScript = `(${require_scroll_restoration_inline.default})(${require_utils.escapeHtml(JSON.stringify(
|
|
7
|
-
function getScrollRestorationScript(
|
|
8
|
-
if (
|
|
9
|
-
return `(${require_scroll_restoration_inline.default})(${require_utils.escapeHtml(JSON.stringify(
|
|
6
|
+
const defaultInlineScrollRestorationScript = `(${require_scroll_restoration_inline.default})(${require_utils.escapeHtml(JSON.stringify(require_scroll_restoration.storageKey))})`;
|
|
7
|
+
function getScrollRestorationScript(key) {
|
|
8
|
+
if (key === void 0) return defaultInlineScrollRestorationScript;
|
|
9
|
+
return `(${require_scroll_restoration_inline.default})(${require_utils.escapeHtml(JSON.stringify(require_scroll_restoration.storageKey))},${require_utils.escapeHtml(JSON.stringify(key))})`;
|
|
10
10
|
}
|
|
11
11
|
function getScrollRestorationScriptForRouter(router) {
|
|
12
12
|
if (typeof router.options.scrollRestoration === "function" && !router.options.scrollRestoration({ location: router.latestLocation })) return null;
|
|
@@ -15,10 +15,7 @@ function getScrollRestorationScriptForRouter(router) {
|
|
|
15
15
|
const location = router.latestLocation;
|
|
16
16
|
const userKey = getKey(location);
|
|
17
17
|
if (userKey === require_scroll_restoration.defaultGetScrollRestorationKey(location)) return defaultInlineScrollRestorationScript;
|
|
18
|
-
return getScrollRestorationScript(
|
|
19
|
-
storageKey: require_scroll_restoration.storageKey,
|
|
20
|
-
key: userKey
|
|
21
|
-
});
|
|
18
|
+
return getScrollRestorationScript(userKey);
|
|
22
19
|
}
|
|
23
20
|
//#endregion
|
|
24
21
|
exports.getScrollRestorationScriptForRouter = getScrollRestorationScriptForRouter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.cjs","names":[],"sources":["../../../src/scroll-restoration-script/server.ts"],"sourcesContent":["import minifiedScrollRestorationScript from '../scroll-restoration-inline?script-string'\nimport {\n defaultGetScrollRestorationKey,\n storageKey,\n} from '../scroll-restoration'\nimport { escapeHtml } from '../utils'\nimport type { AnyRouter } from '../router'\n\
|
|
1
|
+
{"version":3,"file":"server.cjs","names":[],"sources":["../../../src/scroll-restoration-script/server.ts"],"sourcesContent":["import minifiedScrollRestorationScript from '../scroll-restoration-inline?script-string'\nimport {\n defaultGetScrollRestorationKey,\n storageKey,\n} from '../scroll-restoration'\nimport { escapeHtml } from '../utils'\nimport type { AnyRouter } from '../router'\n\nconst defaultInlineScrollRestorationScript = `(${minifiedScrollRestorationScript})(${escapeHtml(\n JSON.stringify(storageKey),\n)})`\n\nfunction getScrollRestorationScript(key?: string) {\n if (key === undefined) {\n return defaultInlineScrollRestorationScript\n }\n\n return `(${minifiedScrollRestorationScript})(${escapeHtml(JSON.stringify(storageKey))},${escapeHtml(JSON.stringify(key))})`\n}\n\nexport function getScrollRestorationScriptForRouter(router: AnyRouter) {\n if (\n typeof router.options.scrollRestoration === 'function' &&\n !router.options.scrollRestoration({ location: router.latestLocation })\n ) {\n return null\n }\n\n const getKey = router.options.getScrollRestorationKey\n if (!getKey) {\n return defaultInlineScrollRestorationScript\n }\n\n const location = router.latestLocation\n const userKey = getKey(location)\n const defaultKey = defaultGetScrollRestorationKey(location)\n\n if (userKey === defaultKey) {\n return defaultInlineScrollRestorationScript\n }\n\n return getScrollRestorationScript(userKey)\n}\n"],"mappings":";;;;;AAQA,MAAM,uCAAuC,IAAI,kCAAA,QAAgC,IAAI,cAAA,WACnF,KAAK,UAAU,2BAAA,WAAW,CAC3B,CAAC;AAEF,SAAS,2BAA2B,KAAc;AAChD,KAAI,QAAQ,KAAA,EACV,QAAO;AAGT,QAAO,IAAI,kCAAA,QAAgC,IAAI,cAAA,WAAW,KAAK,UAAU,2BAAA,WAAW,CAAC,CAAC,GAAG,cAAA,WAAW,KAAK,UAAU,IAAI,CAAC,CAAC;;AAG3H,SAAgB,oCAAoC,QAAmB;AACrE,KACE,OAAO,OAAO,QAAQ,sBAAsB,cAC5C,CAAC,OAAO,QAAQ,kBAAkB,EAAE,UAAU,OAAO,gBAAgB,CAAC,CAEtE,QAAO;CAGT,MAAM,SAAS,OAAO,QAAQ;AAC9B,KAAI,CAAC,OACH,QAAO;CAGT,MAAM,WAAW,OAAO;CACxB,MAAM,UAAU,OAAO,SAAS;AAGhC,KAAI,YAFe,2BAAA,+BAA+B,SAAS,CAGzD,QAAO;AAGT,QAAO,2BAA2B,QAAQ"}
|
|
@@ -142,47 +142,47 @@ function setupScrollRestoration(router, force) {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
-
if (!shouldResetScroll) return;
|
|
146
145
|
ignoreScroll = true;
|
|
147
146
|
try {
|
|
148
147
|
const hash = event.toLocation.hash;
|
|
149
148
|
const hashScrollIntoViewOptions = event.toLocation.state.__hashScrollIntoViewOptions ?? true;
|
|
150
|
-
const action = require_router.locationHistoryActions.get(event.toLocation);
|
|
151
|
-
const skipWindowRestore = hash && hashScrollIntoViewOptions && (action === "PUSH" || action === "REPLACE");
|
|
152
|
-
const elementEntries = router.isScrollRestoring ? scrollRestorationCache[cacheKey] : void 0;
|
|
153
149
|
let windowRestored = false;
|
|
154
|
-
if (
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
150
|
+
if (shouldResetScroll) {
|
|
151
|
+
const action = require_router.locationHistoryActions.get(event.toLocation);
|
|
152
|
+
const skipWindowRestore = hash && hashScrollIntoViewOptions && (action === "PUSH" || action === "REPLACE");
|
|
153
|
+
const elementEntries = router.isScrollRestoring ? scrollRestorationCache[cacheKey] : void 0;
|
|
154
|
+
if (elementEntries) for (const elementSelector in elementEntries) {
|
|
155
|
+
const { scrollX, scrollY } = elementEntries[elementSelector];
|
|
156
|
+
if (elementSelector === windowScrollTarget) {
|
|
157
|
+
if (skipWindowRestore) continue;
|
|
158
|
+
scrollTo({
|
|
159
|
+
top: scrollY,
|
|
160
|
+
left: scrollX,
|
|
161
|
+
behavior
|
|
162
|
+
});
|
|
163
|
+
windowRestored = true;
|
|
164
|
+
} else {
|
|
165
|
+
const element = getElement(elementSelector);
|
|
166
|
+
if (element) {
|
|
167
|
+
element.scrollLeft = scrollX;
|
|
168
|
+
element.scrollTop = scrollY;
|
|
169
|
+
}
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors);
|
|
183
|
-
for (const element of scrollToTopElements) element.scrollTo(scrollOptions);
|
|
172
|
+
if (!windowRestored && !hash) {
|
|
173
|
+
const scrollOptions = {
|
|
174
|
+
top: 0,
|
|
175
|
+
left: 0,
|
|
176
|
+
behavior
|
|
177
|
+
};
|
|
178
|
+
scrollTo(scrollOptions);
|
|
179
|
+
if (scrollToTopSelectors) {
|
|
180
|
+
scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors);
|
|
181
|
+
for (const element of scrollToTopElements) element.scrollTo(scrollOptions);
|
|
182
|
+
}
|
|
184
183
|
}
|
|
185
184
|
}
|
|
185
|
+
if (!windowRestored && hash && hashScrollIntoViewOptions) document.getElementById(hash)?.scrollIntoView(hashScrollIntoViewOptions);
|
|
186
186
|
} finally {
|
|
187
187
|
ignoreScroll = false;
|
|
188
188
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-restoration.cjs","names":[],"sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport { locationHistoryActions } from './router'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\ntype ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\ntype ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n // Accessing sessionStorage itself can throw SecurityError in locked-down\n // contexts, e.g. sandboxed/opaque origins or blocked storage policies.\n return sessionStorage\n } catch {\n return\n }\n}\n\n// SessionStorage key used to store scroll positions across navigations.\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\nconst safeSessionStorage = getSafeSessionStorage()\n\nfunction createScrollRestorationCache() {\n try {\n return JSON.parse(\n safeSessionStorage?.getItem(storageKey) || '{}',\n ) as ScrollRestorationByKey\n } catch {\n // ignore invalid session storage payloads\n return {}\n }\n}\n\nfunction persistScrollRestorationCache() {\n try {\n safeSessionStorage?.setItem(\n storageKey,\n JSON.stringify(scrollRestorationCache),\n )\n } catch {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[ts-router] Could not persist scroll restoration state to sessionStorage.',\n )\n }\n }\n}\n\nconst scrollRestorationCache = /* @__PURE__ */ createScrollRestorationCache()\nconst scrollRestorationIdAttribute = 'data-scroll-restoration-id'\n\n/**\n * The default `getKey` function for `useScrollRestoration`.\n * It returns the `key` from the location state or the `href` of the location.\n *\n * The `location.href` is used as a fallback to support the use case where the location state is not available like the initial render.\n */\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\nfunction getScrollRestorationSelector(element: Element): string {\n const attrId = element.getAttribute(scrollRestorationIdAttribute)\n if (attrId) {\n return `[${scrollRestorationIdAttribute}=\"${attrId}\"]`\n }\n\n let selector = ''\n let el: any = element\n let parent: HTMLElement\n\n while ((parent = el.parentNode)) {\n let index = 1\n let sibling = el\n while ((sibling = sibling.previousElementSibling)) {\n index++\n }\n\n const part = `${el.localName}:nth-child(${index})`\n selector = selector ? `${part} > ${selector}` : part\n el = parent\n }\n\n return selector\n}\n\nexport function getElementScrollRestorationEntry(\n router: AnyRouter,\n options: (\n | {\n id: string\n getElement?: () => Window | Element | undefined | null\n }\n | {\n id?: string\n getElement: () => Window | Element | undefined | null\n }\n ) & {\n getKey?: (location: ParsedLocation) => string\n },\n): ScrollRestorationEntry | undefined {\n const getKey = options.getKey || defaultGetScrollRestorationKey\n const restoreKey = getKey(router.latestLocation)\n const entries = scrollRestorationCache[restoreKey]\n\n if (!entries) {\n return\n }\n\n if (options.id) {\n return entries[`[${scrollRestorationIdAttribute}=\"${options.id}\"]`]\n }\n\n const element = options.getElement?.()\n if (!element) {\n return\n }\n\n return entries[\n element === window\n ? windowScrollTarget\n : getScrollRestorationSelector(element as Element)\n ]\n}\n\nlet ignoreScroll = false\nconst windowScrollTarget = 'window'\ntype ScrollTarget = typeof windowScrollTarget | Element\n\nfunction getElement(selector: string | (() => Element | null | undefined)) {\n try {\n return typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n } catch {}\n return\n}\n\nfunction getScrollToTopElements(\n scrollToTopSelectors: NonNullable<\n AnyRouter['options']['scrollToTopSelectors']\n >,\n): Array<Element> {\n const elements: Array<Element> = []\n\n for (const selector of scrollToTopSelectors) {\n if (selector === windowScrollTarget) {\n continue\n }\n\n const element = getElement(selector)\n if (element) {\n elements.push(element)\n }\n }\n\n return elements\n}\n\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n // Keep hash/top scrolling active even when sessionStorage is unavailable.\n\n if (force ?? router.options.scrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if ((isServer ?? router.isServer) || router.isScrollRestorationSetup) {\n return\n }\n\n router.isScrollRestorationSetup = true\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n const trackedScrollEntries = new Map<ScrollTarget, ScrollRestorationEntry>()\n const setTrackedScrollEntry = (\n target: ScrollTarget,\n scrollX: number,\n scrollY: number,\n ) => {\n const entry =\n trackedScrollEntries.get(target) || ({} as ScrollRestorationEntry)\n entry.scrollX = scrollX\n entry.scrollY = scrollY\n trackedScrollEntries.set(target, entry)\n }\n\n history.scrollRestoration = 'manual'\n\n const onScroll = (event: Event) => {\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n if (event.target === document) {\n setTrackedScrollEntry(windowScrollTarget, scrollX, scrollY)\n } else {\n const target = event.target as Element\n setTrackedScrollEntry(target, target.scrollLeft, target.scrollTop)\n }\n }\n\n // Snapshot the current page's tracked scroll targets before navigation or unload.\n const snapshotCurrentScrollTargets = (restoreKey: string) => {\n if (!router.isScrollRestoring) {\n return\n }\n\n const keyEntry = (scrollRestorationCache[restoreKey] ||=\n {} as ScrollRestorationByElement)\n\n for (const [target, position] of trackedScrollEntries) {\n if (target === windowScrollTarget) {\n keyEntry[windowScrollTarget] = position\n } else if (target.isConnected) {\n keyEntry[getScrollRestorationSelector(target)] = position\n }\n }\n }\n\n document.addEventListener('scroll', onScroll, true)\n router.subscribe('onBeforeLoad', (event) => {\n if (event.fromLocation) {\n snapshotCurrentScrollTargets(getKey(event.fromLocation))\n }\n trackedScrollEntries.clear()\n })\n addEventListener('pagehide', () => {\n snapshotCurrentScrollTargets(\n getKey(\n router.stores.resolvedLocation.get() ?? router.stores.location.get(),\n ),\n )\n persistScrollRestorationCache()\n })\n\n // Restore destination scroll after the new route has rendered.\n router.subscribe('onRendered', (event) => {\n const behavior = router.options.scrollRestorationBehavior\n const scrollToTopSelectors = router.options.scrollToTopSelectors\n const shouldResetScroll = router.resetNextScroll\n let scrollToTopElements: Array<Element> | undefined\n trackedScrollEntries.clear()\n\n if (!shouldResetScroll) {\n router.resetNextScroll = true\n }\n\n if (\n typeof router.options.scrollRestoration === 'function' &&\n !router.options.scrollRestoration({ location: router.latestLocation })\n ) {\n return\n }\n\n const cacheKey = getKey(event.toLocation)\n const fromCacheKey = event.fromLocation && getKey(event.fromLocation)\n\n if (router.isScrollRestoring && fromCacheKey && fromCacheKey !== cacheKey) {\n const fromElementEntries = scrollRestorationCache[fromCacheKey]\n\n if (fromElementEntries) {\n let toElementEntries = scrollRestorationCache[cacheKey]\n\n for (const elementSelector in fromElementEntries) {\n if (elementSelector === windowScrollTarget) {\n if (shouldResetScroll) {\n continue\n }\n } else {\n const element = getElement(elementSelector)\n if (!element) {\n continue\n }\n\n if (shouldResetScroll && scrollToTopSelectors) {\n scrollToTopElements ??=\n getScrollToTopElements(scrollToTopSelectors)\n if (scrollToTopElements.includes(element)) {\n continue\n }\n }\n }\n\n if (!toElementEntries) {\n toElementEntries = scrollRestorationCache[cacheKey] =\n {} as ScrollRestorationByElement\n }\n\n toElementEntries[elementSelector] ??=\n fromElementEntries[elementSelector]!\n }\n }\n }\n\n if (!shouldResetScroll) {\n return\n }\n\n ignoreScroll = true\n\n try {\n const hash = event.toLocation.hash\n const hashScrollIntoViewOptions =\n event.toLocation.state.__hashScrollIntoViewOptions ?? true\n const action = locationHistoryActions.get(event.toLocation)\n const skipWindowRestore =\n hash &&\n hashScrollIntoViewOptions &&\n (action === 'PUSH' || action === 'REPLACE')\n\n const elementEntries = router.isScrollRestoring\n ? scrollRestorationCache[cacheKey]\n : undefined\n let windowRestored = false\n\n if (elementEntries) {\n for (const elementSelector in elementEntries) {\n const { scrollX, scrollY } = elementEntries[elementSelector]!\n\n if (elementSelector === windowScrollTarget) {\n if (skipWindowRestore) {\n continue\n }\n\n scrollTo({\n top: scrollY,\n left: scrollX,\n behavior,\n })\n windowRestored = true\n } else {\n const element = getElement(elementSelector)\n if (element) {\n element.scrollLeft = scrollX\n element.scrollTop = scrollY\n }\n }\n }\n }\n\n if (!windowRestored) {\n if (hash) {\n if (hashScrollIntoViewOptions) {\n document\n .getElementById(hash)\n ?.scrollIntoView(hashScrollIntoViewOptions)\n }\n } else {\n const scrollOptions = {\n top: 0,\n left: 0,\n behavior,\n }\n\n scrollTo(scrollOptions)\n if (scrollToTopSelectors) {\n scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors)\n for (const element of scrollToTopElements) {\n element.scrollTo(scrollOptions)\n }\n }\n }\n }\n } finally {\n ignoreScroll = false\n }\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scroll-restoration.cjs","names":[],"sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { isServer } from '@tanstack/router-core/isServer'\nimport { locationHistoryActions } from './router'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\ntype ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\ntype ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n // Accessing sessionStorage itself can throw SecurityError in locked-down\n // contexts, e.g. sandboxed/opaque origins or blocked storage policies.\n return sessionStorage\n } catch {\n return\n }\n}\n\n// SessionStorage key used to store scroll positions across navigations.\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\nconst safeSessionStorage = getSafeSessionStorage()\n\nfunction createScrollRestorationCache() {\n try {\n return JSON.parse(\n safeSessionStorage?.getItem(storageKey) || '{}',\n ) as ScrollRestorationByKey\n } catch {\n // ignore invalid session storage payloads\n return {}\n }\n}\n\nfunction persistScrollRestorationCache() {\n try {\n safeSessionStorage?.setItem(\n storageKey,\n JSON.stringify(scrollRestorationCache),\n )\n } catch {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[ts-router] Could not persist scroll restoration state to sessionStorage.',\n )\n }\n }\n}\n\nconst scrollRestorationCache = /* @__PURE__ */ createScrollRestorationCache()\nconst scrollRestorationIdAttribute = 'data-scroll-restoration-id'\n\n/**\n * The default `getKey` function for `useScrollRestoration`.\n * It returns the `key` from the location state or the `href` of the location.\n *\n * The `location.href` is used as a fallback to support the use case where the location state is not available like the initial render.\n */\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\nfunction getScrollRestorationSelector(element: Element): string {\n const attrId = element.getAttribute(scrollRestorationIdAttribute)\n if (attrId) {\n return `[${scrollRestorationIdAttribute}=\"${attrId}\"]`\n }\n\n let selector = ''\n let el: any = element\n let parent: HTMLElement\n\n while ((parent = el.parentNode)) {\n let index = 1\n let sibling = el\n while ((sibling = sibling.previousElementSibling)) {\n index++\n }\n\n const part = `${el.localName}:nth-child(${index})`\n selector = selector ? `${part} > ${selector}` : part\n el = parent\n }\n\n return selector\n}\n\nexport function getElementScrollRestorationEntry(\n router: AnyRouter,\n options: (\n | {\n id: string\n getElement?: () => Window | Element | undefined | null\n }\n | {\n id?: string\n getElement: () => Window | Element | undefined | null\n }\n ) & {\n getKey?: (location: ParsedLocation) => string\n },\n): ScrollRestorationEntry | undefined {\n const getKey = options.getKey || defaultGetScrollRestorationKey\n const restoreKey = getKey(router.latestLocation)\n const entries = scrollRestorationCache[restoreKey]\n\n if (!entries) {\n return\n }\n\n if (options.id) {\n return entries[`[${scrollRestorationIdAttribute}=\"${options.id}\"]`]\n }\n\n const element = options.getElement?.()\n if (!element) {\n return\n }\n\n return entries[\n element === window\n ? windowScrollTarget\n : getScrollRestorationSelector(element as Element)\n ]\n}\n\nlet ignoreScroll = false\nconst windowScrollTarget = 'window'\ntype ScrollTarget = typeof windowScrollTarget | Element\n\nfunction getElement(selector: string | (() => Element | null | undefined)) {\n try {\n return typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n } catch {}\n return\n}\n\nfunction getScrollToTopElements(\n scrollToTopSelectors: NonNullable<\n AnyRouter['options']['scrollToTopSelectors']\n >,\n): Array<Element> {\n const elements: Array<Element> = []\n\n for (const selector of scrollToTopSelectors) {\n if (selector === windowScrollTarget) {\n continue\n }\n\n const element = getElement(selector)\n if (element) {\n elements.push(element)\n }\n }\n\n return elements\n}\n\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n // Keep hash/top scrolling active even when sessionStorage is unavailable.\n\n if (force ?? router.options.scrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if ((isServer ?? router.isServer) || router.isScrollRestorationSetup) {\n return\n }\n\n router.isScrollRestorationSetup = true\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n const trackedScrollEntries = new Map<ScrollTarget, ScrollRestorationEntry>()\n const setTrackedScrollEntry = (\n target: ScrollTarget,\n scrollX: number,\n scrollY: number,\n ) => {\n const entry =\n trackedScrollEntries.get(target) || ({} as ScrollRestorationEntry)\n entry.scrollX = scrollX\n entry.scrollY = scrollY\n trackedScrollEntries.set(target, entry)\n }\n\n history.scrollRestoration = 'manual'\n\n const onScroll = (event: Event) => {\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n if (event.target === document) {\n setTrackedScrollEntry(windowScrollTarget, scrollX, scrollY)\n } else {\n const target = event.target as Element\n setTrackedScrollEntry(target, target.scrollLeft, target.scrollTop)\n }\n }\n\n // Snapshot the current page's tracked scroll targets before navigation or unload.\n const snapshotCurrentScrollTargets = (restoreKey: string) => {\n if (!router.isScrollRestoring) {\n return\n }\n\n const keyEntry = (scrollRestorationCache[restoreKey] ||=\n {} as ScrollRestorationByElement)\n\n for (const [target, position] of trackedScrollEntries) {\n if (target === windowScrollTarget) {\n keyEntry[windowScrollTarget] = position\n } else if (target.isConnected) {\n keyEntry[getScrollRestorationSelector(target)] = position\n }\n }\n }\n\n document.addEventListener('scroll', onScroll, true)\n router.subscribe('onBeforeLoad', (event) => {\n if (event.fromLocation) {\n snapshotCurrentScrollTargets(getKey(event.fromLocation))\n }\n trackedScrollEntries.clear()\n })\n addEventListener('pagehide', () => {\n snapshotCurrentScrollTargets(\n getKey(\n router.stores.resolvedLocation.get() ?? router.stores.location.get(),\n ),\n )\n persistScrollRestorationCache()\n })\n\n // Restore destination scroll after the new route has rendered.\n router.subscribe('onRendered', (event) => {\n const behavior = router.options.scrollRestorationBehavior\n const scrollToTopSelectors = router.options.scrollToTopSelectors\n const shouldResetScroll = router.resetNextScroll\n let scrollToTopElements: Array<Element> | undefined\n trackedScrollEntries.clear()\n\n if (!shouldResetScroll) {\n router.resetNextScroll = true\n }\n\n if (\n typeof router.options.scrollRestoration === 'function' &&\n !router.options.scrollRestoration({ location: router.latestLocation })\n ) {\n return\n }\n\n const cacheKey = getKey(event.toLocation)\n const fromCacheKey = event.fromLocation && getKey(event.fromLocation)\n\n if (router.isScrollRestoring && fromCacheKey && fromCacheKey !== cacheKey) {\n const fromElementEntries = scrollRestorationCache[fromCacheKey]\n\n if (fromElementEntries) {\n let toElementEntries = scrollRestorationCache[cacheKey]\n\n for (const elementSelector in fromElementEntries) {\n if (elementSelector === windowScrollTarget) {\n if (shouldResetScroll) {\n continue\n }\n } else {\n const element = getElement(elementSelector)\n if (!element) {\n continue\n }\n\n if (shouldResetScroll && scrollToTopSelectors) {\n scrollToTopElements ??=\n getScrollToTopElements(scrollToTopSelectors)\n if (scrollToTopElements.includes(element)) {\n continue\n }\n }\n }\n\n if (!toElementEntries) {\n toElementEntries = scrollRestorationCache[cacheKey] =\n {} as ScrollRestorationByElement\n }\n\n toElementEntries[elementSelector] ??=\n fromElementEntries[elementSelector]!\n }\n }\n }\n\n ignoreScroll = true\n\n try {\n const hash = event.toLocation.hash\n const hashScrollIntoViewOptions =\n event.toLocation.state.__hashScrollIntoViewOptions ?? true\n let windowRestored = false\n\n if (shouldResetScroll) {\n const action = locationHistoryActions.get(event.toLocation)\n const skipWindowRestore =\n hash &&\n hashScrollIntoViewOptions &&\n (action === 'PUSH' || action === 'REPLACE')\n\n const elementEntries = router.isScrollRestoring\n ? scrollRestorationCache[cacheKey]\n : undefined\n\n if (elementEntries) {\n for (const elementSelector in elementEntries) {\n const { scrollX, scrollY } = elementEntries[elementSelector]!\n\n if (elementSelector === windowScrollTarget) {\n if (skipWindowRestore) {\n continue\n }\n\n scrollTo({\n top: scrollY,\n left: scrollX,\n behavior,\n })\n windowRestored = true\n } else {\n const element = getElement(elementSelector)\n if (element) {\n element.scrollLeft = scrollX\n element.scrollTop = scrollY\n }\n }\n }\n }\n\n if (!windowRestored && !hash) {\n const scrollOptions = {\n top: 0,\n left: 0,\n behavior,\n }\n\n scrollTo(scrollOptions)\n if (scrollToTopSelectors) {\n scrollToTopElements ??= getScrollToTopElements(scrollToTopSelectors)\n for (const element of scrollToTopElements) {\n element.scrollTo(scrollOptions)\n }\n }\n }\n }\n\n if (!windowRestored && hash && hashScrollIntoViewOptions) {\n document.getElementById(hash)?.scrollIntoView(hashScrollIntoViewOptions)\n }\n } finally {\n ignoreScroll = false\n }\n })\n}\n"],"mappings":";;;AAgBA,SAAS,wBAAwB;AAC/B,KAAI;AAGF,SAAO;SACD;AACN;;;AAKJ,MAAa,aAAa;AAC1B,MAAM,qBAAqB,uBAAuB;AAElD,SAAS,+BAA+B;AACtC,KAAI;AACF,SAAO,KAAK,MACV,oBAAoB,QAAA,8BAAmB,IAAI,KAC5C;SACK;AAEN,SAAO,EAAE;;;AAIb,SAAS,gCAAgC;AACvC,KAAI;AACF,sBAAoB,QAClB,YACA,KAAK,UAAU,uBAAuB,CACvC;SACK;AACN,MAAA,QAAA,IAAA,aAA6B,aAC3B,SAAQ,KACN,4EACD;;;AAKP,MAAM,yBAAyC,8CAA8B;AAC7E,MAAM,+BAA+B;;;;;;;AAQrC,MAAa,kCAAkC,aAA6B;AAC1E,QAAO,SAAS,MAAM,aAAc,SAAS;;AAG/C,SAAS,6BAA6B,SAA0B;CAC9D,MAAM,SAAS,QAAQ,aAAa,6BAA6B;AACjE,KAAI,OACF,QAAO,IAAI,6BAA6B,IAAI,OAAO;CAGrD,IAAI,WAAW;CACf,IAAI,KAAU;CACd,IAAI;AAEJ,QAAQ,SAAS,GAAG,YAAa;EAC/B,IAAI,QAAQ;EACZ,IAAI,UAAU;AACd,SAAQ,UAAU,QAAQ,uBACxB;EAGF,MAAM,OAAO,GAAG,GAAG,UAAU,aAAa,MAAM;AAChD,aAAW,WAAW,GAAG,KAAK,KAAK,aAAa;AAChD,OAAK;;AAGP,QAAO;;AAGT,SAAgB,iCACd,QACA,SAYoC;CAGpC,MAAM,UAAU,wBAFD,QAAQ,UAAU,gCACP,OAAO,eAAe;AAGhD,KAAI,CAAC,QACH;AAGF,KAAI,QAAQ,GACV,QAAO,QAAQ,IAAI,6BAA6B,IAAI,QAAQ,GAAG;CAGjE,MAAM,UAAU,QAAQ,cAAc;AACtC,KAAI,CAAC,QACH;AAGF,QAAO,QACL,YAAY,SACR,qBACA,6BAA6B,QAAmB;;AAIxD,IAAI,eAAe;AACnB,MAAM,qBAAqB;AAG3B,SAAS,WAAW,UAAuD;AACzE,KAAI;AACF,SAAO,OAAO,aAAa,aACvB,UAAU,GACV,SAAS,cAAc,SAAS;SAC9B;;AAIV,SAAS,uBACP,sBAGgB;CAChB,MAAM,WAA2B,EAAE;AAEnC,MAAK,MAAM,YAAY,sBAAsB;AAC3C,MAAI,aAAa,mBACf;EAGF,MAAM,UAAU,WAAW,SAAS;AACpC,MAAI,QACF,UAAS,KAAK,QAAQ;;AAI1B,QAAO;;AAGT,SAAgB,uBAAuB,QAAmB,OAAiB;AAGzE,KAAI,SAAS,OAAO,QAAQ,kBAC1B,QAAO,oBAAoB;AAG7B,MAAK,+BAAA,YAAY,OAAO,aAAa,OAAO,yBAC1C;AAGF,QAAO,2BAA2B;AAClC,gBAAe;CAEf,MAAM,SACJ,OAAO,QAAQ,2BAA2B;CAC5C,MAAM,uCAAuB,IAAI,KAA2C;CAC5E,MAAM,yBACJ,QACA,SACA,YACG;EACH,MAAM,QACJ,qBAAqB,IAAI,OAAO,IAAK,EAAE;AACzC,QAAM,UAAU;AAChB,QAAM,UAAU;AAChB,uBAAqB,IAAI,QAAQ,MAAM;;AAGzC,SAAQ,oBAAoB;CAE5B,MAAM,YAAY,UAAiB;AACjC,MAAI,gBAAgB,CAAC,OAAO,kBAC1B;AAGF,MAAI,MAAM,WAAW,SACnB,uBAAsB,oBAAoB,SAAS,QAAQ;OACtD;GACL,MAAM,SAAS,MAAM;AACrB,yBAAsB,QAAQ,OAAO,YAAY,OAAO,UAAU;;;CAKtE,MAAM,gCAAgC,eAAuB;AAC3D,MAAI,CAAC,OAAO,kBACV;EAGF,MAAM,WAAY,uBAAuB,gBACvC,EAAE;AAEJ,OAAK,MAAM,CAAC,QAAQ,aAAa,qBAC/B,KAAI,WAAW,mBACb,UAAS,sBAAsB;WACtB,OAAO,YAChB,UAAS,6BAA6B,OAAO,IAAI;;AAKvD,UAAS,iBAAiB,UAAU,UAAU,KAAK;AACnD,QAAO,UAAU,iBAAiB,UAAU;AAC1C,MAAI,MAAM,aACR,8BAA6B,OAAO,MAAM,aAAa,CAAC;AAE1D,uBAAqB,OAAO;GAC5B;AACF,kBAAiB,kBAAkB;AACjC,+BACE,OACE,OAAO,OAAO,iBAAiB,KAAK,IAAI,OAAO,OAAO,SAAS,KAAK,CACrE,CACF;AACD,iCAA+B;GAC/B;AAGF,QAAO,UAAU,eAAe,UAAU;EACxC,MAAM,WAAW,OAAO,QAAQ;EAChC,MAAM,uBAAuB,OAAO,QAAQ;EAC5C,MAAM,oBAAoB,OAAO;EACjC,IAAI;AACJ,uBAAqB,OAAO;AAE5B,MAAI,CAAC,kBACH,QAAO,kBAAkB;AAG3B,MACE,OAAO,OAAO,QAAQ,sBAAsB,cAC5C,CAAC,OAAO,QAAQ,kBAAkB,EAAE,UAAU,OAAO,gBAAgB,CAAC,CAEtE;EAGF,MAAM,WAAW,OAAO,MAAM,WAAW;EACzC,MAAM,eAAe,MAAM,gBAAgB,OAAO,MAAM,aAAa;AAErE,MAAI,OAAO,qBAAqB,gBAAgB,iBAAiB,UAAU;GACzE,MAAM,qBAAqB,uBAAuB;AAElD,OAAI,oBAAoB;IACtB,IAAI,mBAAmB,uBAAuB;AAE9C,SAAK,MAAM,mBAAmB,oBAAoB;AAChD,SAAI,oBAAoB;UAClB,kBACF;YAEG;MACL,MAAM,UAAU,WAAW,gBAAgB;AAC3C,UAAI,CAAC,QACH;AAGF,UAAI,qBAAqB,sBAAsB;AAC7C,+BACE,uBAAuB,qBAAqB;AAC9C,WAAI,oBAAoB,SAAS,QAAQ,CACvC;;;AAKN,SAAI,CAAC,iBACH,oBAAmB,uBAAuB,YACxC,EAAE;AAGN,sBAAiB,qBACf,mBAAmB;;;;AAK3B,iBAAe;AAEf,MAAI;GACF,MAAM,OAAO,MAAM,WAAW;GAC9B,MAAM,4BACJ,MAAM,WAAW,MAAM,+BAA+B;GACxD,IAAI,iBAAiB;AAErB,OAAI,mBAAmB;IACrB,MAAM,SAAS,eAAA,uBAAuB,IAAI,MAAM,WAAW;IAC3D,MAAM,oBACJ,QACA,8BACC,WAAW,UAAU,WAAW;IAEnC,MAAM,iBAAiB,OAAO,oBAC1B,uBAAuB,YACvB,KAAA;AAEJ,QAAI,eACF,MAAK,MAAM,mBAAmB,gBAAgB;KAC5C,MAAM,EAAE,SAAS,YAAY,eAAe;AAE5C,SAAI,oBAAoB,oBAAoB;AAC1C,UAAI,kBACF;AAGF,eAAS;OACP,KAAK;OACL,MAAM;OACN;OACD,CAAC;AACF,uBAAiB;YACZ;MACL,MAAM,UAAU,WAAW,gBAAgB;AAC3C,UAAI,SAAS;AACX,eAAQ,aAAa;AACrB,eAAQ,YAAY;;;;AAM5B,QAAI,CAAC,kBAAkB,CAAC,MAAM;KAC5B,MAAM,gBAAgB;MACpB,KAAK;MACL,MAAM;MACN;MACD;AAED,cAAS,cAAc;AACvB,SAAI,sBAAsB;AACxB,8BAAwB,uBAAuB,qBAAqB;AACpE,WAAK,MAAM,WAAW,oBACpB,SAAQ,SAAS,cAAc;;;;AAMvC,OAAI,CAAC,kBAAkB,QAAQ,0BAC7B,UAAS,eAAe,KAAK,EAAE,eAAe,0BAA0B;YAElE;AACR,kBAAe;;GAEjB"}
|
|
@@ -33,7 +33,8 @@ function createRequestHandler({ createRouter, request, getRouterManifest }) {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
function getRequestHeaders(opts) {
|
|
36
|
-
const matchHeaders =
|
|
36
|
+
const matchHeaders = [];
|
|
37
|
+
for (const match of opts.router.stores.matches.get()) matchHeaders.push(match.headers);
|
|
37
38
|
const redirect = opts.router.stores.redirect.get();
|
|
38
39
|
if (redirect) matchHeaders.push(redirect.headers);
|
|
39
40
|
return require_headers.mergeHeaders({ "Content-Type": "text/html; charset=UTF-8" }, ...matchHeaders);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRequestHandler.cjs","names":[],"sources":["../../../src/ssr/createRequestHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport { mergeHeaders } from './headers'\nimport {\n attachRouterServerSsrUtils,\n getNormalizedURL,\n getOrigin,\n} from './ssr-server'\nimport type { HandlerCallback } from './handlerCallback'\nimport type { AnyHeaders } from './headers'\nimport type { AnyRouter } from '../router'\nimport type {
|
|
1
|
+
{"version":3,"file":"createRequestHandler.cjs","names":[],"sources":["../../../src/ssr/createRequestHandler.ts"],"sourcesContent":["import { createMemoryHistory } from '@tanstack/history'\nimport { mergeHeaders } from './headers'\nimport {\n attachRouterServerSsrUtils,\n getNormalizedURL,\n getOrigin,\n} from './ssr-server'\nimport type { HandlerCallback } from './handlerCallback'\nimport type { AnyHeaders } from './headers'\nimport type { AnyRouter } from '../router'\nimport type { ServerManifest } from '../manifest'\n\nexport type RequestHandler<TRouter extends AnyRouter> = (\n cb: HandlerCallback<TRouter>,\n) => Promise<Response>\n\nexport function createRequestHandler<TRouter extends AnyRouter>({\n createRouter,\n request,\n getRouterManifest,\n}: {\n createRouter: () => TRouter\n request: Request\n getRouterManifest?: () => ServerManifest | Promise<ServerManifest>\n}): RequestHandler<TRouter> {\n return async (cb) => {\n const router = createRouter()\n // Track whether the callback will handle cleanup\n let cbWillCleanup = false\n\n try {\n attachRouterServerSsrUtils({\n router,\n manifest: await getRouterManifest?.(),\n })\n\n // normalizing and sanitizing the pathname here for server, so we always deal with the same format during SSR.\n const { url } = getNormalizedURL(request.url, 'http://localhost')\n const origin = getOrigin(request)\n const href = url.href.replace(url.origin, '')\n\n // Create a history for the router\n const history = createMemoryHistory({\n initialEntries: [href],\n })\n\n // Update the router with the history and context\n router.update({\n history,\n origin: router.options.origin ?? origin,\n })\n\n await router.load()\n\n await router.serverSsr?.dehydrate()\n\n const responseHeaders = getRequestHeaders({\n router,\n })\n\n // Mark that the callback will handle cleanup\n cbWillCleanup = true\n return cb({\n request,\n router,\n responseHeaders,\n })\n } finally {\n if (!cbWillCleanup) {\n // Clean up router SSR state if the callback won't handle it\n // (e.g., if an error occurred before the callback was invoked).\n // When the callback runs, it handles cleanup (either via transformStreamWithRouter\n // for streaming, or directly in renderRouterToString for non-streaming).\n router.serverSsr?.cleanup()\n }\n }\n }\n}\n\nfunction getRequestHeaders(opts: { router: AnyRouter }): Headers {\n const matchHeaders: Array<AnyHeaders> = []\n for (const match of opts.router.stores.matches.get()) {\n matchHeaders.push(match.headers)\n }\n\n // Handle Redirects\n const redirect = opts.router.stores.redirect.get()\n if (redirect) {\n matchHeaders.push(redirect.headers)\n }\n\n return mergeHeaders(\n {\n 'Content-Type': 'text/html; charset=UTF-8',\n },\n ...matchHeaders,\n )\n}\n"],"mappings":";;;;AAgBA,SAAgB,qBAAgD,EAC9D,cACA,SACA,qBAK0B;AAC1B,QAAO,OAAO,OAAO;EACnB,MAAM,SAAS,cAAc;EAE7B,IAAI,gBAAgB;AAEpB,MAAI;AACF,sBAAA,2BAA2B;IACzB;IACA,UAAU,MAAM,qBAAqB;IACtC,CAAC;GAGF,MAAM,EAAE,QAAQ,mBAAA,iBAAiB,QAAQ,KAAK,mBAAmB;GACjE,MAAM,SAAS,mBAAA,UAAU,QAAQ;GAIjC,MAAM,WAAA,GAAA,kBAAA,qBAA8B,EAClC,gBAAgB,CAJL,IAAI,KAAK,QAAQ,IAAI,QAAQ,GAAG,CAIrB,EACvB,CAAC;AAGF,UAAO,OAAO;IACZ;IACA,QAAQ,OAAO,QAAQ,UAAU;IAClC,CAAC;AAEF,SAAM,OAAO,MAAM;AAEnB,SAAM,OAAO,WAAW,WAAW;GAEnC,MAAM,kBAAkB,kBAAkB,EACxC,QACD,CAAC;AAGF,mBAAgB;AAChB,UAAO,GAAG;IACR;IACA;IACA;IACD,CAAC;YACM;AACR,OAAI,CAAC,cAKH,QAAO,WAAW,SAAS;;;;AAMnC,SAAS,kBAAkB,MAAsC;CAC/D,MAAM,eAAkC,EAAE;AAC1C,MAAK,MAAM,SAAS,KAAK,OAAO,OAAO,QAAQ,KAAK,CAClD,cAAa,KAAK,MAAM,QAAQ;CAIlC,MAAM,WAAW,KAAK,OAAO,OAAO,SAAS,KAAK;AAClD,KAAI,SACF,cAAa,KAAK,SAAS,QAAQ;AAGrC,QAAO,gBAAA,aACL,EACE,gBAAgB,4BACjB,EACD,GAAG,aACJ"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { HandlerCallback } from './handlerCallback.cjs';
|
|
2
2
|
import { AnyRouter } from '../router.cjs';
|
|
3
|
-
import {
|
|
3
|
+
import { ServerManifest } from '../manifest.cjs';
|
|
4
4
|
export type RequestHandler<TRouter extends AnyRouter> = (cb: HandlerCallback<TRouter>) => Promise<Response>;
|
|
5
5
|
export declare function createRequestHandler<TRouter extends AnyRouter>({ createRouter, request, getRouterManifest, }: {
|
|
6
6
|
createRouter: () => TRouter;
|
|
7
7
|
request: Request;
|
|
8
|
-
getRouterManifest?: () =>
|
|
8
|
+
getRouterManifest?: () => ServerManifest | Promise<ServerManifest>;
|
|
9
9
|
}): RequestHandler<TRouter>;
|
|
@@ -96,7 +96,6 @@ var ScriptBuffer = class {
|
|
|
96
96
|
const isProd = process.env.NODE_ENV === "production";
|
|
97
97
|
const MANIFEST_CACHE_SIZE = 100;
|
|
98
98
|
const manifestCaches = /* @__PURE__ */ new WeakMap();
|
|
99
|
-
const inlineCssCaches = /* @__PURE__ */ new WeakMap();
|
|
100
99
|
function getManifestCache(manifest) {
|
|
101
100
|
const cache = manifestCaches.get(manifest);
|
|
102
101
|
if (cache) return cache;
|
|
@@ -104,83 +103,141 @@ function getManifestCache(manifest) {
|
|
|
104
103
|
manifestCaches.set(manifest, newCache);
|
|
105
104
|
return newCache;
|
|
106
105
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
function getInlineCssForPreparedRoutes(manifest, preparedRoutes) {
|
|
107
|
+
if (preparedRoutes.inlineCss !== void 0) return preparedRoutes.inlineCss;
|
|
108
|
+
const styles = manifest.inlineCss?.styles;
|
|
109
|
+
const hrefs = preparedRoutes.inlineCssHrefs;
|
|
110
|
+
if (!styles || !hrefs?.length) return void 0;
|
|
111
|
+
let css = "";
|
|
112
|
+
for (const href of hrefs) css += styles[href];
|
|
113
|
+
preparedRoutes.inlineCss = css;
|
|
114
|
+
return css;
|
|
113
115
|
}
|
|
114
|
-
function
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
const seen = /* @__PURE__ */ new Set();
|
|
118
|
-
const hrefs = [];
|
|
119
|
-
for (const match of matches) {
|
|
120
|
-
const assets = manifest?.routes[match.routeId]?.assets ?? [];
|
|
121
|
-
for (const asset of assets) {
|
|
122
|
-
const href = require_manifest.getStylesheetHref(asset);
|
|
123
|
-
if (!href || seen.has(href) || styles[href] === void 0) continue;
|
|
124
|
-
seen.add(href);
|
|
125
|
-
hrefs.push(href);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return hrefs;
|
|
116
|
+
function getInlineCssAssetForPreparedRoutes(manifest, preparedRoutes) {
|
|
117
|
+
const css = getInlineCssForPreparedRoutes(manifest, preparedRoutes);
|
|
118
|
+
return css === void 0 ? void 0 : require_manifest.createInlineCssStyleAsset(css);
|
|
129
119
|
}
|
|
130
|
-
function
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
120
|
+
function getMatchedRoutesCacheKey(matches) {
|
|
121
|
+
let cacheKey = "";
|
|
122
|
+
for (let i = 0; i < matches.length; i++) cacheKey += (i === 0 ? "" : "\0") + matches[i].routeId;
|
|
123
|
+
return cacheKey;
|
|
124
|
+
}
|
|
125
|
+
function getPreparedMatchedManifestRoutes(manifest, matches, cacheKey) {
|
|
134
126
|
if (isProd) {
|
|
135
|
-
const cached =
|
|
136
|
-
if (cached
|
|
127
|
+
const cached = getManifestCache(manifest).get(cacheKey);
|
|
128
|
+
if (cached) return cached;
|
|
137
129
|
}
|
|
138
|
-
const
|
|
139
|
-
if (isProd)
|
|
140
|
-
return
|
|
130
|
+
const preparedRoutes = prepareMatchedManifestRoutes(manifest, matches);
|
|
131
|
+
if (isProd) getManifestCache(manifest).set(cacheKey, preparedRoutes);
|
|
132
|
+
return preparedRoutes;
|
|
141
133
|
}
|
|
142
|
-
function
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
134
|
+
function prepareMatchedManifestRoutes(manifest, matches) {
|
|
135
|
+
const inlineStyles = manifest.inlineCss?.styles;
|
|
136
|
+
const routes = {};
|
|
137
|
+
if (!inlineStyles) {
|
|
138
|
+
for (const match of matches) {
|
|
139
|
+
const route = manifest.routes[match.routeId];
|
|
140
|
+
if (route) routes[match.routeId] = route;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
routes,
|
|
144
|
+
hasStrippedRoutes: false
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const inlineCssHrefs = [];
|
|
148
|
+
const seenInlineCssHrefs = /* @__PURE__ */ new Set();
|
|
149
|
+
let hasStrippedRoutes = false;
|
|
150
|
+
for (const match of matches) {
|
|
151
|
+
const routeId = match.routeId;
|
|
152
|
+
const route = manifest.routes[routeId];
|
|
153
|
+
if (!route) continue;
|
|
154
|
+
const nextRoute = stripInlinedStylesheetAssetsFromRoute(inlineStyles, route, inlineCssHrefs, seenInlineCssHrefs);
|
|
155
|
+
if (nextRoute !== route) hasStrippedRoutes = true;
|
|
156
|
+
routes[routeId] = nextRoute;
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
routes,
|
|
160
|
+
hasStrippedRoutes,
|
|
161
|
+
...inlineCssHrefs.length ? { inlineCssHrefs } : {}
|
|
162
|
+
};
|
|
146
163
|
}
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const assets = route.assets?.filter((asset) => !require_manifest.isInlinableStylesheet(manifest, asset));
|
|
164
|
+
function stripInlinedStylesheetAssetsFromRoute(inlineStyles, route, inlineCssHrefs, seenInlineCssHrefs) {
|
|
165
|
+
const css = route.css;
|
|
166
|
+
if (!css) return route;
|
|
167
|
+
if (css.length === 0) {
|
|
152
168
|
const nextRoute = { ...route };
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
nextRoutes[routeId] = nextRoute;
|
|
169
|
+
delete nextRoute.css;
|
|
170
|
+
return nextRoute;
|
|
156
171
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
let cssLinks;
|
|
173
|
+
for (let i = 0; i < css.length; i++) {
|
|
174
|
+
const link = css[i];
|
|
175
|
+
const href = require_manifest.getStylesheetHref(link);
|
|
176
|
+
if (inlineStyles[href] === void 0) {
|
|
177
|
+
if (cssLinks) cssLinks.push(link);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (!seenInlineCssHrefs.has(href)) {
|
|
181
|
+
seenInlineCssHrefs.add(href);
|
|
182
|
+
inlineCssHrefs.push(href);
|
|
183
|
+
}
|
|
184
|
+
if (!cssLinks) cssLinks = css.slice(0, i);
|
|
163
185
|
}
|
|
164
|
-
return
|
|
186
|
+
if (!cssLinks) return route;
|
|
187
|
+
if (cssLinks.length > 0) return {
|
|
188
|
+
...route,
|
|
189
|
+
css: cssLinks
|
|
190
|
+
};
|
|
191
|
+
const nextRoute = { ...route };
|
|
192
|
+
delete nextRoute.css;
|
|
193
|
+
return nextRoute;
|
|
194
|
+
}
|
|
195
|
+
function hasRouteAssets(route) {
|
|
196
|
+
return !!route.scripts?.length || !!route.css?.length;
|
|
197
|
+
}
|
|
198
|
+
function hasRequestAssets(assets) {
|
|
199
|
+
return !!assets && (!!assets.preloads?.length || hasRouteAssets(assets));
|
|
200
|
+
}
|
|
201
|
+
function mergeRequestAssetsIntoRootRoute(rootRoute, requestAssets) {
|
|
202
|
+
const preloads = requestAssets?.preloads?.length ? [...requestAssets.preloads, ...rootRoute?.preloads ?? []] : rootRoute?.preloads;
|
|
203
|
+
const scripts = requestAssets?.scripts?.length ? [...requestAssets.scripts, ...rootRoute?.scripts ?? []] : rootRoute?.scripts;
|
|
204
|
+
const cssLinks = requestAssets?.css?.length ? [...requestAssets.css, ...rootRoute?.css ?? []] : rootRoute?.css;
|
|
205
|
+
return {
|
|
206
|
+
...rootRoute ?? {},
|
|
207
|
+
...preloads?.length ? { preloads } : {},
|
|
208
|
+
...scripts?.length ? { scripts } : {},
|
|
209
|
+
...cssLinks?.length ? { css: cssLinks } : {}
|
|
210
|
+
};
|
|
165
211
|
}
|
|
166
|
-
function attachRouterServerSsrUtils({ router, manifest, getRequestAssets
|
|
212
|
+
function attachRouterServerSsrUtils({ router, manifest, getRequestAssets }) {
|
|
167
213
|
router.ssr = { get manifest() {
|
|
168
214
|
if (!manifest) return manifest;
|
|
169
215
|
const requestAssets = getRequestAssets?.();
|
|
170
|
-
const
|
|
171
|
-
|
|
216
|
+
const matches = router.stores.matches.get();
|
|
217
|
+
const hasAssets = hasRequestAssets(requestAssets);
|
|
218
|
+
if (!hasAssets && !manifest.inlineCss) return manifest;
|
|
219
|
+
let inlineCssAsset;
|
|
220
|
+
let routes = manifest.routes;
|
|
221
|
+
if (manifest.inlineCss) {
|
|
222
|
+
const preparedManifest = getPreparedMatchedManifestRoutes(manifest, matches, getMatchedRoutesCacheKey(matches));
|
|
223
|
+
inlineCssAsset = getInlineCssAssetForPreparedRoutes(manifest, preparedManifest);
|
|
224
|
+
if (preparedManifest.hasStrippedRoutes) routes = {
|
|
225
|
+
...manifest.routes,
|
|
226
|
+
...preparedManifest.routes
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (!hasAssets) return {
|
|
230
|
+
...manifest.scriptFormat ? { scriptFormat: manifest.scriptFormat } : {},
|
|
231
|
+
...inlineCssAsset ? { inlineStyle: inlineCssAsset } : {},
|
|
232
|
+
routes
|
|
233
|
+
};
|
|
234
|
+
const rootRoute = routes[require_root.rootRouteId];
|
|
172
235
|
return {
|
|
173
|
-
...manifest,
|
|
236
|
+
...manifest.scriptFormat ? { scriptFormat: manifest.scriptFormat } : {},
|
|
237
|
+
...inlineCssAsset ? { inlineStyle: inlineCssAsset } : {},
|
|
174
238
|
routes: {
|
|
175
|
-
...
|
|
176
|
-
[require_root.rootRouteId]:
|
|
177
|
-
...manifest.routes[require_root.rootRouteId],
|
|
178
|
-
assets: [
|
|
179
|
-
...requestAssets ?? [],
|
|
180
|
-
...inlineCssAsset ? [inlineCssAsset] : [],
|
|
181
|
-
...manifest.routes["__root__"]?.assets ?? []
|
|
182
|
-
]
|
|
183
|
-
}
|
|
239
|
+
...routes,
|
|
240
|
+
[require_root.rootRouteId]: mergeRequestAssetsIntoRootRoute(rootRoute, requestAssets)
|
|
184
241
|
}
|
|
185
242
|
};
|
|
186
243
|
} };
|
|
@@ -211,27 +268,19 @@ function attachRouterServerSsrUtils({ router, manifest, getRequestAssets, includ
|
|
|
211
268
|
const matches = matchesToDehydrate.map(dehydrateMatch);
|
|
212
269
|
let manifestToDehydrate = void 0;
|
|
213
270
|
if (manifest) {
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (currentRouteIds.has(routeId)) nextFilteredRoutes[routeId] = routeManifest;
|
|
224
|
-
else if (includeUnmatchedRouteAssets && routeManifest.assets && routeManifest.assets.length > 0) nextFilteredRoutes[routeId] = { assets: routeManifest.assets };
|
|
225
|
-
}
|
|
226
|
-
filteredRoutes = stripInlinedStylesheetAssets(manifest, nextFilteredRoutes, matchesToDehydrate);
|
|
227
|
-
if (isProd) getManifestCache(manifest).set(manifestCacheKey, filteredRoutes);
|
|
228
|
-
}
|
|
229
|
-
manifestToDehydrate = { routes: { ...filteredRoutes } };
|
|
230
|
-
if (opts?.requestAssets?.length) {
|
|
271
|
+
const cacheKey = getMatchedRoutesCacheKey(matchesToDehydrate);
|
|
272
|
+
const preparedManifest = getPreparedMatchedManifestRoutes(manifest, matchesToDehydrate, cacheKey);
|
|
273
|
+
manifestToDehydrate = {
|
|
274
|
+
...manifest.scriptFormat ? { scriptFormat: manifest.scriptFormat } : {},
|
|
275
|
+
...preparedManifest.inlineCssHrefs ? { inlineStyle: require_manifest.createInlineCssPlaceholderAsset() } : {},
|
|
276
|
+
routes: preparedManifest.routes
|
|
277
|
+
};
|
|
278
|
+
const requestAssets = opts?.requestAssets;
|
|
279
|
+
if (hasRequestAssets(requestAssets)) {
|
|
231
280
|
const existingRoot = manifestToDehydrate.routes[require_root.rootRouteId];
|
|
232
|
-
manifestToDehydrate.routes
|
|
233
|
-
...
|
|
234
|
-
|
|
281
|
+
manifestToDehydrate.routes = {
|
|
282
|
+
...manifestToDehydrate.routes,
|
|
283
|
+
[require_root.rootRouteId]: mergeRequestAssetsIntoRootRoute(existingRoot, requestAssets)
|
|
235
284
|
};
|
|
236
285
|
}
|
|
237
286
|
}
|