@tanstack/router-plugin 1.168.23 → 1.168.24-pre.0

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.
@@ -12,13 +12,6 @@ function handleRouteUpdate(routeId, newRoute) {
12
12
  generatedRouteOptionKeys.forEach((key) => {
13
13
  if (key in oldRoute.options) generatedRouteOptions[key] = oldRoute.options[key];
14
14
  });
15
- const removedKeys = /* @__PURE__ */ new Set();
16
- Object.keys(oldRoute.options).forEach((key) => {
17
- if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {
18
- removedKeys.add(key);
19
- delete oldRoute.options[key];
20
- }
21
- });
22
15
  const preserveComponentIdentity = "shellComponent" in oldRoute.options === "shellComponent" in newRoute.options;
23
16
  const componentKeys = "__TSR_COMPONENT_TYPES__";
24
17
  if (preserveComponentIdentity) componentKeys.forEach((key) => {
@@ -30,42 +23,11 @@ function handleRouteUpdate(routeId, newRoute) {
30
23
  };
31
24
  oldRoute.options = nextOptions;
32
25
  oldRoute.update(nextOptions);
33
- oldRoute._componentsPromise = void 0;
34
- oldRoute._lazyPromise = void 0;
26
+ router._replaceRouteChunk(oldRoute, newRoute.lazyFn);
35
27
  router.setRoutes(router.buildRouteTree());
36
28
  syncHotRouteExport(oldRoute);
37
29
  router.resolvePathCache.clear();
38
- const filter = (m) => m.routeId === oldRoute.id;
39
- const activeMatch = router.stores.matches.get().find(filter);
40
- const pendingMatch = router.stores.pendingMatches.get().find(filter);
41
- const cachedMatches = router.stores.cachedMatches.get().filter(filter);
42
- if (activeMatch || pendingMatch || cachedMatches.length > 0) {
43
- if (removedKeys.has("loader") || removedKeys.has("beforeLoad")) {
44
- const matchIds = [
45
- activeMatch?.id,
46
- pendingMatch?.id,
47
- ...cachedMatches.map((match) => match.id)
48
- ].filter(Boolean);
49
- router.batch(() => {
50
- for (const matchId of matchIds) {
51
- const store = router.stores.pendingMatchStores.get(matchId) || router.stores.matchStores.get(matchId) || router.stores.cachedMatchStores.get(matchId);
52
- if (store) store.set((prev) => {
53
- const next = { ...prev };
54
- if (removedKeys.has("loader")) next.loaderData = void 0;
55
- if (removedKeys.has("beforeLoad")) {
56
- next.__beforeLoadContext = void 0;
57
- next.context = rebuildMatchContextWithoutBeforeLoad(next);
58
- }
59
- return next;
60
- });
61
- }
62
- });
63
- }
64
- router.invalidate({
65
- filter,
66
- sync: true
67
- });
68
- }
30
+ router._refreshRoute?.();
69
31
  function syncHotRouteExport(liveRoute) {
70
32
  newRoute.options = liveRoute.options;
71
33
  newRoute.parentRoute = liveRoute.parentRoute;
@@ -74,33 +36,6 @@ function handleRouteUpdate(routeId, newRoute) {
74
36
  newRoute._fullPath = liveRoute._fullPath;
75
37
  newRoute._to = liveRoute._to;
76
38
  }
77
- function getStoreMatch(matchId) {
78
- return router.stores.pendingMatchStores.get(matchId)?.get() || router.stores.matchStores.get(matchId)?.get() || router.stores.cachedMatchStores.get(matchId)?.get();
79
- }
80
- function getMatchList(matchId) {
81
- const pendingMatches = router.stores.pendingMatches.get();
82
- if (pendingMatches.some((match) => match.id === matchId)) return pendingMatches;
83
- const activeMatches = router.stores.matches.get();
84
- if (activeMatches.some((match) => match.id === matchId)) return activeMatches;
85
- const cachedMatches = router.stores.cachedMatches.get();
86
- if (cachedMatches.some((match) => match.id === matchId)) return cachedMatches;
87
- return [];
88
- }
89
- function getParentMatch(match) {
90
- const matchList = getMatchList(match.id);
91
- const matchIndex = matchList.findIndex((item) => item.id === match.id);
92
- if (matchIndex <= 0) return;
93
- const parentMatch = matchList[matchIndex - 1];
94
- return getStoreMatch(parentMatch.id) || parentMatch;
95
- }
96
- function rebuildMatchContextWithoutBeforeLoad(match) {
97
- const parentMatch = getParentMatch(match);
98
- const getParentContext = router.getParentContext;
99
- return {
100
- ...(getParentContext ? getParentContext.call(router, parentMatch) : parentMatch?.context ?? router.options.context) ?? {},
101
- ...match.__routeContext ?? {}
102
- };
103
- }
104
39
  }
105
40
  var handleRouteUpdateStr = handleRouteUpdate.toString();
106
41
  function getHandleRouteUpdateCode(stableRouteOptionKeys) {
@@ -1 +1 @@
1
- {"version":3,"file":"handle-route-update.cjs","names":[],"sources":["../../../../src/core/hmr/handle-route-update.ts"],"sourcesContent":["import type {\n AnyRoute,\n AnyRouteMatch,\n AnyRouter,\n RouterWritableStore,\n} from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n options: Record<string, unknown>\n parentRoute: AnyRoute\n _componentsPromise?: Promise<void>\n _lazyPromise?: Promise<void>\n update: (options: Record<string, unknown>) => unknown\n _path: string\n _id: string\n _fullPath: string\n _to: string\n}\n\ntype AnyRouterWithPrivateMaps = AnyRouter & {\n routesById: Record<string, AnyRoute>\n buildRouteTree: () => Parameters<AnyRouter['setRoutes']>[0]\n setRoutes: AnyRouter['setRoutes']\n stores: AnyRouter['stores'] & {\n cachedMatchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n >\n pendingMatchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n >\n matchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n >\n }\n}\n\ntype AnyRouteMatchWithPrivateProps = AnyRouteMatch & {\n __beforeLoadContext?: unknown\n __routeContext?: Record<string, unknown>\n context?: Record<string, unknown>\n}\n\nfunction handleRouteUpdate(\n routeId: string,\n newRoute: AnyRouteWithPrivateProps,\n) {\n const router = window.__TSR_ROUTER__ as AnyRouterWithPrivateMaps\n const oldRoute = router.routesById[routeId] as\n | AnyRouteWithPrivateProps\n | undefined\n\n if (!oldRoute) {\n return\n }\n\n // Generated route-tree options are not present on the freshly imported route\n // module, but they must stay on the live route before rebuilding indexes.\n const generatedRouteOptionKeys = new Set(['id', 'path', 'getParentRoute'])\n const generatedRouteOptions: Record<string, unknown> = {}\n generatedRouteOptionKeys.forEach((key) => {\n if (key in oldRoute.options) {\n generatedRouteOptions[key] = oldRoute.options[key]\n }\n })\n\n const removedKeys = new Set<string>()\n Object.keys(oldRoute.options).forEach((key) => {\n if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {\n removedKeys.add(key)\n delete oldRoute.options[key]\n }\n })\n\n const oldHasShellComponent = 'shellComponent' in oldRoute.options\n const newHasShellComponent = 'shellComponent' in newRoute.options\n const preserveComponentIdentity =\n oldHasShellComponent === newHasShellComponent\n\n // Keys whose identity must remain stable to prevent React from\n // unmounting/remounting the component tree. React Fast Refresh already\n // handles hot-updating the function bodies of these components — our job\n // is only to update non-component route options (loader, head, etc.).\n // For code-split (splittable) routes, the lazyRouteComponent wrapper is\n // already cached in the bundler hot data so its identity is stable.\n // For unsplittable routes (e.g. root routes), the component is a plain\n // function reference that gets recreated on every module re-execution,\n // so we must explicitly preserve the old reference.\n // Preserve component identity so React doesn't remount.\n // React Fast Refresh patches the function bodies in-place.\n const componentKeys = '__TSR_COMPONENT_TYPES__' as unknown as Array<string>\n if (preserveComponentIdentity) {\n componentKeys.forEach((key) => {\n if (key in oldRoute.options && key in newRoute.options) {\n newRoute.options[key] = oldRoute.options[key]\n }\n })\n }\n\n const nextOptions = {\n ...newRoute.options,\n ...generatedRouteOptions,\n }\n\n oldRoute.options = nextOptions\n oldRoute.update(nextOptions)\n oldRoute._componentsPromise = undefined\n oldRoute._lazyPromise = undefined\n\n router.setRoutes(router.buildRouteTree())\n syncHotRouteExport(oldRoute)\n router.resolvePathCache.clear()\n\n const filter = (m: AnyRouteMatch) => m.routeId === oldRoute.id\n const activeMatch = router.stores.matches.get().find(filter)\n const pendingMatch = router.stores.pendingMatches.get().find(filter)\n const cachedMatches = router.stores.cachedMatches.get().filter(filter)\n\n if (activeMatch || pendingMatch || cachedMatches.length > 0) {\n // Clear stale match data for removed route options BEFORE invalidating.\n // Without this, router.invalidate() -> matchRoutes() reuses the existing\n // match from the store (via ...existingMatch spread) and the stale\n // loaderData / __beforeLoadContext survives the reload cycle.\n //\n // We must update the store directly (not via router.updateMatch) because\n // updateMatch wraps in startTransition which may defer the state update,\n // and we need the clear to be visible before invalidate reads the store.\n if (removedKeys.has('loader') || removedKeys.has('beforeLoad')) {\n const matchIds = [\n activeMatch?.id,\n pendingMatch?.id,\n ...cachedMatches.map((match) => match.id),\n ].filter(Boolean) as Array<string>\n router.batch(() => {\n for (const matchId of matchIds) {\n const store =\n router.stores.pendingMatchStores.get(matchId) ||\n router.stores.matchStores.get(matchId) ||\n router.stores.cachedMatchStores.get(matchId)\n if (store) {\n store.set((prev) => {\n const next: AnyRouteMatchWithPrivateProps = { ...prev }\n\n if (removedKeys.has('loader')) {\n next.loaderData = undefined\n }\n if (removedKeys.has('beforeLoad')) {\n next.__beforeLoadContext = undefined\n next.context = rebuildMatchContextWithoutBeforeLoad(next)\n }\n\n return next\n })\n }\n }\n })\n }\n\n router.invalidate({ filter, sync: true })\n }\n\n function syncHotRouteExport(liveRoute: AnyRouteWithPrivateProps) {\n // routeTree.gen.ts mutates the original module export with generated\n // routing state. Mirror that state onto the fresh HMR export too, so\n // aliased route imports keep working after the module is hot-reloaded.\n newRoute.options = liveRoute.options\n newRoute.parentRoute = liveRoute.parentRoute\n newRoute._path = liveRoute._path\n newRoute._id = liveRoute._id\n newRoute._fullPath = liveRoute._fullPath\n newRoute._to = liveRoute._to\n }\n\n function getStoreMatch(matchId: string) {\n return (\n router.stores.pendingMatchStores.get(matchId)?.get() ||\n router.stores.matchStores.get(matchId)?.get() ||\n router.stores.cachedMatchStores.get(matchId)?.get()\n )\n }\n\n function getMatchList(matchId: string) {\n const pendingMatches = router.stores.pendingMatches.get()\n if (pendingMatches.some((match) => match.id === matchId)) {\n return pendingMatches\n }\n\n const activeMatches = router.stores.matches.get()\n if (activeMatches.some((match) => match.id === matchId)) {\n return activeMatches\n }\n\n const cachedMatches = router.stores.cachedMatches.get()\n if (cachedMatches.some((match) => match.id === matchId)) {\n return cachedMatches\n }\n\n return []\n }\n\n function getParentMatch(match: AnyRouteMatch) {\n const matchList = getMatchList(match.id)\n const matchIndex = matchList.findIndex((item) => item.id === match.id)\n\n if (matchIndex <= 0) {\n return undefined\n }\n\n const parentMatch = matchList[matchIndex - 1]!\n return getStoreMatch(parentMatch.id) || parentMatch\n }\n\n function rebuildMatchContextWithoutBeforeLoad(\n match: AnyRouteMatchWithPrivateProps,\n ) {\n const parentMatch = getParentMatch(match)\n const getParentContext = (\n router as unknown as {\n getParentContext?: (\n parentMatch?: AnyRouteMatch,\n ) => Record<string, unknown> | undefined\n }\n ).getParentContext\n const parentContext = getParentContext\n ? getParentContext.call(router, parentMatch)\n : (parentMatch?.context ?? router.options.context)\n\n return {\n ...(parentContext ?? {}),\n ...(match.__routeContext ?? {}),\n }\n }\n}\n\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function getHandleRouteUpdateCode(stableRouteOptionKeys: Array<string>) {\n return handleRouteUpdateStr.replace(\n /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n JSON.stringify(stableRouteOptionKeys),\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"handle-route-update.cjs","names":[],"sources":["../../../../src/core/hmr/handle-route-update.ts"],"sourcesContent":["import type { AnyRoute, AnyRouter } from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n options: Record<string, unknown>\n parentRoute: AnyRoute\n _lazy?: Promise<void> | true\n update: (options: Record<string, unknown>) => unknown\n _path: string\n _id: string\n _fullPath: string\n _to: string\n}\n\ntype AnyRouterWithPrivateState = AnyRouter & {\n routesById: Record<string, AnyRoute>\n buildRouteTree: () => Parameters<AnyRouter['setRoutes']>[0]\n setRoutes: AnyRouter['setRoutes']\n _refreshRoute?: () => Promise<void>\n _replaceRouteChunk: (route: AnyRoute, lazyFn: AnyRoute['lazyFn']) => void\n}\n\nfunction handleRouteUpdate(\n routeId: string,\n newRoute: AnyRouteWithPrivateProps,\n) {\n const router = window.__TSR_ROUTER__ as AnyRouterWithPrivateState\n const oldRoute = router.routesById[routeId] as\n | AnyRouteWithPrivateProps\n | undefined\n\n if (!oldRoute) {\n return\n }\n\n // Generated route-tree options are not present on the freshly imported route\n // module, but they must stay on the live route before rebuilding indexes.\n const generatedRouteOptionKeys = new Set(['id', 'path', 'getParentRoute'])\n const generatedRouteOptions: Record<string, unknown> = {}\n generatedRouteOptionKeys.forEach((key) => {\n if (key in oldRoute.options) {\n generatedRouteOptions[key] = oldRoute.options[key]\n }\n })\n\n const oldHasShellComponent = 'shellComponent' in oldRoute.options\n const newHasShellComponent = 'shellComponent' in newRoute.options\n const preserveComponentIdentity =\n oldHasShellComponent === newHasShellComponent\n\n // Keys whose identity must remain stable to prevent React from\n // unmounting/remounting the component tree. React Fast Refresh already\n // handles hot-updating the function bodies of these components — our job\n // is only to update non-component route options (loader, head, etc.).\n // For code-split (splittable) routes, the lazyRouteComponent wrapper is\n // already cached in the bundler hot data so its identity is stable.\n // For unsplittable routes (e.g. root routes), the component is a plain\n // function reference that gets recreated on every module re-execution,\n // so we must explicitly preserve the old reference.\n // Preserve component identity so React doesn't remount.\n // React Fast Refresh patches the function bodies in-place.\n const componentKeys = '__TSR_COMPONENT_TYPES__' as unknown as Array<string>\n if (preserveComponentIdentity) {\n componentKeys.forEach((key) => {\n if (key in oldRoute.options && key in newRoute.options) {\n newRoute.options[key] = oldRoute.options[key]\n }\n })\n }\n\n const nextOptions = {\n ...newRoute.options,\n ...generatedRouteOptions,\n }\n\n oldRoute.options = nextOptions\n oldRoute.update(nextOptions)\n router._replaceRouteChunk(oldRoute, newRoute.lazyFn)\n\n router.setRoutes(router.buildRouteTree())\n syncHotRouteExport(oldRoute)\n router.resolvePathCache.clear()\n void router._refreshRoute?.()\n\n function syncHotRouteExport(liveRoute: AnyRouteWithPrivateProps) {\n // routeTree.gen.ts mutates the original module export with generated\n // routing state. Mirror that state onto the fresh HMR export too, so\n // aliased route imports keep working after the module is hot-reloaded.\n newRoute.options = liveRoute.options\n newRoute.parentRoute = liveRoute.parentRoute\n newRoute._path = liveRoute._path\n newRoute._id = liveRoute._id\n newRoute._fullPath = liveRoute._fullPath\n newRoute._to = liveRoute._to\n }\n}\n\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function getHandleRouteUpdateCode(stableRouteOptionKeys: Array<string>) {\n return handleRouteUpdateStr.replace(\n /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n JSON.stringify(stableRouteOptionKeys),\n )\n}\n"],"mappings":";AAqBA,SAAS,kBACP,SACA,UACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO,WAAW;CAInC,IAAI,CAAC,UACH;CAKF,MAAM,2BAA2B,IAAI,IAAI;EAAC;EAAM;EAAQ;CAAgB,CAAC;CACzE,MAAM,wBAAiD,CAAC;CACxD,yBAAyB,SAAS,QAAQ;EACxC,IAAI,OAAO,SAAS,SAClB,sBAAsB,OAAO,SAAS,QAAQ;CAElD,CAAC;CAID,MAAM,4BAFuB,oBAAoB,SAAS,YAC7B,oBAAoB,SAAS;CAe1D,MAAM,gBAAgB;CACtB,IAAI,2BACF,cAAc,SAAS,QAAQ;EAC7B,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,SAC7C,SAAS,QAAQ,OAAO,SAAS,QAAQ;CAE7C,CAAC;CAGH,MAAM,cAAc;EAClB,GAAG,SAAS;EACZ,GAAG;CACL;CAEA,SAAS,UAAU;CACnB,SAAS,OAAO,WAAW;CAC3B,OAAO,mBAAmB,UAAU,SAAS,MAAM;CAEnD,OAAO,UAAU,OAAO,eAAe,CAAC;CACxC,mBAAmB,QAAQ;CAC3B,OAAO,iBAAiB,MAAM;CAC9B,OAAY,gBAAgB;CAE5B,SAAS,mBAAmB,WAAqC;EAI/D,SAAS,UAAU,UAAU;EAC7B,SAAS,cAAc,UAAU;EACjC,SAAS,QAAQ,UAAU;EAC3B,SAAS,MAAM,UAAU;EACzB,SAAS,YAAY,UAAU;EAC/B,SAAS,MAAM,UAAU;CAC3B;AACF;AAEA,IAAM,uBAAuB,kBAAkB,SAAS;AAExD,SAAgB,yBAAyB,uBAAsC;CAC7E,OAAO,qBAAqB,QAC1B,mCACA,KAAK,UAAU,qBAAqB,CACtC;AACF"}
@@ -12,13 +12,6 @@ function handleRouteUpdate(routeId, newRoute) {
12
12
  generatedRouteOptionKeys.forEach((key) => {
13
13
  if (key in oldRoute.options) generatedRouteOptions[key] = oldRoute.options[key];
14
14
  });
15
- const removedKeys = /* @__PURE__ */ new Set();
16
- Object.keys(oldRoute.options).forEach((key) => {
17
- if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {
18
- removedKeys.add(key);
19
- delete oldRoute.options[key];
20
- }
21
- });
22
15
  const preserveComponentIdentity = "shellComponent" in oldRoute.options === "shellComponent" in newRoute.options;
23
16
  const componentKeys = "__TSR_COMPONENT_TYPES__";
24
17
  if (preserveComponentIdentity) componentKeys.forEach((key) => {
@@ -30,42 +23,11 @@ function handleRouteUpdate(routeId, newRoute) {
30
23
  };
31
24
  oldRoute.options = nextOptions;
32
25
  oldRoute.update(nextOptions);
33
- oldRoute._componentsPromise = void 0;
34
- oldRoute._lazyPromise = void 0;
26
+ router._replaceRouteChunk(oldRoute, newRoute.lazyFn);
35
27
  router.setRoutes(router.buildRouteTree());
36
28
  syncHotRouteExport(oldRoute);
37
29
  router.resolvePathCache.clear();
38
- const filter = (m) => m.routeId === oldRoute.id;
39
- const activeMatch = router.stores.matches.get().find(filter);
40
- const pendingMatch = router.stores.pendingMatches.get().find(filter);
41
- const cachedMatches = router.stores.cachedMatches.get().filter(filter);
42
- if (activeMatch || pendingMatch || cachedMatches.length > 0) {
43
- if (removedKeys.has("loader") || removedKeys.has("beforeLoad")) {
44
- const matchIds = [
45
- activeMatch?.id,
46
- pendingMatch?.id,
47
- ...cachedMatches.map((match) => match.id)
48
- ].filter(Boolean);
49
- router.batch(() => {
50
- for (const matchId of matchIds) {
51
- const store = router.stores.pendingMatchStores.get(matchId) || router.stores.matchStores.get(matchId) || router.stores.cachedMatchStores.get(matchId);
52
- if (store) store.set((prev) => {
53
- const next = { ...prev };
54
- if (removedKeys.has("loader")) next.loaderData = void 0;
55
- if (removedKeys.has("beforeLoad")) {
56
- next.__beforeLoadContext = void 0;
57
- next.context = rebuildMatchContextWithoutBeforeLoad(next);
58
- }
59
- return next;
60
- });
61
- }
62
- });
63
- }
64
- router.invalidate({
65
- filter,
66
- sync: true
67
- });
68
- }
30
+ router._refreshRoute?.();
69
31
  function syncHotRouteExport(liveRoute) {
70
32
  newRoute.options = liveRoute.options;
71
33
  newRoute.parentRoute = liveRoute.parentRoute;
@@ -74,33 +36,6 @@ function handleRouteUpdate(routeId, newRoute) {
74
36
  newRoute._fullPath = liveRoute._fullPath;
75
37
  newRoute._to = liveRoute._to;
76
38
  }
77
- function getStoreMatch(matchId) {
78
- return router.stores.pendingMatchStores.get(matchId)?.get() || router.stores.matchStores.get(matchId)?.get() || router.stores.cachedMatchStores.get(matchId)?.get();
79
- }
80
- function getMatchList(matchId) {
81
- const pendingMatches = router.stores.pendingMatches.get();
82
- if (pendingMatches.some((match) => match.id === matchId)) return pendingMatches;
83
- const activeMatches = router.stores.matches.get();
84
- if (activeMatches.some((match) => match.id === matchId)) return activeMatches;
85
- const cachedMatches = router.stores.cachedMatches.get();
86
- if (cachedMatches.some((match) => match.id === matchId)) return cachedMatches;
87
- return [];
88
- }
89
- function getParentMatch(match) {
90
- const matchList = getMatchList(match.id);
91
- const matchIndex = matchList.findIndex((item) => item.id === match.id);
92
- if (matchIndex <= 0) return;
93
- const parentMatch = matchList[matchIndex - 1];
94
- return getStoreMatch(parentMatch.id) || parentMatch;
95
- }
96
- function rebuildMatchContextWithoutBeforeLoad(match) {
97
- const parentMatch = getParentMatch(match);
98
- const getParentContext = router.getParentContext;
99
- return {
100
- ...(getParentContext ? getParentContext.call(router, parentMatch) : parentMatch?.context ?? router.options.context) ?? {},
101
- ...match.__routeContext ?? {}
102
- };
103
- }
104
39
  }
105
40
  var handleRouteUpdateStr = handleRouteUpdate.toString();
106
41
  function getHandleRouteUpdateCode(stableRouteOptionKeys) {
@@ -1 +1 @@
1
- {"version":3,"file":"handle-route-update.js","names":[],"sources":["../../../../src/core/hmr/handle-route-update.ts"],"sourcesContent":["import type {\n AnyRoute,\n AnyRouteMatch,\n AnyRouter,\n RouterWritableStore,\n} from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n options: Record<string, unknown>\n parentRoute: AnyRoute\n _componentsPromise?: Promise<void>\n _lazyPromise?: Promise<void>\n update: (options: Record<string, unknown>) => unknown\n _path: string\n _id: string\n _fullPath: string\n _to: string\n}\n\ntype AnyRouterWithPrivateMaps = AnyRouter & {\n routesById: Record<string, AnyRoute>\n buildRouteTree: () => Parameters<AnyRouter['setRoutes']>[0]\n setRoutes: AnyRouter['setRoutes']\n stores: AnyRouter['stores'] & {\n cachedMatchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n >\n pendingMatchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n >\n matchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>\n >\n }\n}\n\ntype AnyRouteMatchWithPrivateProps = AnyRouteMatch & {\n __beforeLoadContext?: unknown\n __routeContext?: Record<string, unknown>\n context?: Record<string, unknown>\n}\n\nfunction handleRouteUpdate(\n routeId: string,\n newRoute: AnyRouteWithPrivateProps,\n) {\n const router = window.__TSR_ROUTER__ as AnyRouterWithPrivateMaps\n const oldRoute = router.routesById[routeId] as\n | AnyRouteWithPrivateProps\n | undefined\n\n if (!oldRoute) {\n return\n }\n\n // Generated route-tree options are not present on the freshly imported route\n // module, but they must stay on the live route before rebuilding indexes.\n const generatedRouteOptionKeys = new Set(['id', 'path', 'getParentRoute'])\n const generatedRouteOptions: Record<string, unknown> = {}\n generatedRouteOptionKeys.forEach((key) => {\n if (key in oldRoute.options) {\n generatedRouteOptions[key] = oldRoute.options[key]\n }\n })\n\n const removedKeys = new Set<string>()\n Object.keys(oldRoute.options).forEach((key) => {\n if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {\n removedKeys.add(key)\n delete oldRoute.options[key]\n }\n })\n\n const oldHasShellComponent = 'shellComponent' in oldRoute.options\n const newHasShellComponent = 'shellComponent' in newRoute.options\n const preserveComponentIdentity =\n oldHasShellComponent === newHasShellComponent\n\n // Keys whose identity must remain stable to prevent React from\n // unmounting/remounting the component tree. React Fast Refresh already\n // handles hot-updating the function bodies of these components — our job\n // is only to update non-component route options (loader, head, etc.).\n // For code-split (splittable) routes, the lazyRouteComponent wrapper is\n // already cached in the bundler hot data so its identity is stable.\n // For unsplittable routes (e.g. root routes), the component is a plain\n // function reference that gets recreated on every module re-execution,\n // so we must explicitly preserve the old reference.\n // Preserve component identity so React doesn't remount.\n // React Fast Refresh patches the function bodies in-place.\n const componentKeys = '__TSR_COMPONENT_TYPES__' as unknown as Array<string>\n if (preserveComponentIdentity) {\n componentKeys.forEach((key) => {\n if (key in oldRoute.options && key in newRoute.options) {\n newRoute.options[key] = oldRoute.options[key]\n }\n })\n }\n\n const nextOptions = {\n ...newRoute.options,\n ...generatedRouteOptions,\n }\n\n oldRoute.options = nextOptions\n oldRoute.update(nextOptions)\n oldRoute._componentsPromise = undefined\n oldRoute._lazyPromise = undefined\n\n router.setRoutes(router.buildRouteTree())\n syncHotRouteExport(oldRoute)\n router.resolvePathCache.clear()\n\n const filter = (m: AnyRouteMatch) => m.routeId === oldRoute.id\n const activeMatch = router.stores.matches.get().find(filter)\n const pendingMatch = router.stores.pendingMatches.get().find(filter)\n const cachedMatches = router.stores.cachedMatches.get().filter(filter)\n\n if (activeMatch || pendingMatch || cachedMatches.length > 0) {\n // Clear stale match data for removed route options BEFORE invalidating.\n // Without this, router.invalidate() -> matchRoutes() reuses the existing\n // match from the store (via ...existingMatch spread) and the stale\n // loaderData / __beforeLoadContext survives the reload cycle.\n //\n // We must update the store directly (not via router.updateMatch) because\n // updateMatch wraps in startTransition which may defer the state update,\n // and we need the clear to be visible before invalidate reads the store.\n if (removedKeys.has('loader') || removedKeys.has('beforeLoad')) {\n const matchIds = [\n activeMatch?.id,\n pendingMatch?.id,\n ...cachedMatches.map((match) => match.id),\n ].filter(Boolean) as Array<string>\n router.batch(() => {\n for (const matchId of matchIds) {\n const store =\n router.stores.pendingMatchStores.get(matchId) ||\n router.stores.matchStores.get(matchId) ||\n router.stores.cachedMatchStores.get(matchId)\n if (store) {\n store.set((prev) => {\n const next: AnyRouteMatchWithPrivateProps = { ...prev }\n\n if (removedKeys.has('loader')) {\n next.loaderData = undefined\n }\n if (removedKeys.has('beforeLoad')) {\n next.__beforeLoadContext = undefined\n next.context = rebuildMatchContextWithoutBeforeLoad(next)\n }\n\n return next\n })\n }\n }\n })\n }\n\n router.invalidate({ filter, sync: true })\n }\n\n function syncHotRouteExport(liveRoute: AnyRouteWithPrivateProps) {\n // routeTree.gen.ts mutates the original module export with generated\n // routing state. Mirror that state onto the fresh HMR export too, so\n // aliased route imports keep working after the module is hot-reloaded.\n newRoute.options = liveRoute.options\n newRoute.parentRoute = liveRoute.parentRoute\n newRoute._path = liveRoute._path\n newRoute._id = liveRoute._id\n newRoute._fullPath = liveRoute._fullPath\n newRoute._to = liveRoute._to\n }\n\n function getStoreMatch(matchId: string) {\n return (\n router.stores.pendingMatchStores.get(matchId)?.get() ||\n router.stores.matchStores.get(matchId)?.get() ||\n router.stores.cachedMatchStores.get(matchId)?.get()\n )\n }\n\n function getMatchList(matchId: string) {\n const pendingMatches = router.stores.pendingMatches.get()\n if (pendingMatches.some((match) => match.id === matchId)) {\n return pendingMatches\n }\n\n const activeMatches = router.stores.matches.get()\n if (activeMatches.some((match) => match.id === matchId)) {\n return activeMatches\n }\n\n const cachedMatches = router.stores.cachedMatches.get()\n if (cachedMatches.some((match) => match.id === matchId)) {\n return cachedMatches\n }\n\n return []\n }\n\n function getParentMatch(match: AnyRouteMatch) {\n const matchList = getMatchList(match.id)\n const matchIndex = matchList.findIndex((item) => item.id === match.id)\n\n if (matchIndex <= 0) {\n return undefined\n }\n\n const parentMatch = matchList[matchIndex - 1]!\n return getStoreMatch(parentMatch.id) || parentMatch\n }\n\n function rebuildMatchContextWithoutBeforeLoad(\n match: AnyRouteMatchWithPrivateProps,\n ) {\n const parentMatch = getParentMatch(match)\n const getParentContext = (\n router as unknown as {\n getParentContext?: (\n parentMatch?: AnyRouteMatch,\n ) => Record<string, unknown> | undefined\n }\n ).getParentContext\n const parentContext = getParentContext\n ? getParentContext.call(router, parentMatch)\n : (parentMatch?.context ?? router.options.context)\n\n return {\n ...(parentContext ?? {}),\n ...(match.__routeContext ?? {}),\n }\n }\n}\n\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function getHandleRouteUpdateCode(stableRouteOptionKeys: Array<string>) {\n return handleRouteUpdateStr.replace(\n /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n JSON.stringify(stableRouteOptionKeys),\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"handle-route-update.js","names":[],"sources":["../../../../src/core/hmr/handle-route-update.ts"],"sourcesContent":["import type { AnyRoute, AnyRouter } from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n options: Record<string, unknown>\n parentRoute: AnyRoute\n _lazy?: Promise<void> | true\n update: (options: Record<string, unknown>) => unknown\n _path: string\n _id: string\n _fullPath: string\n _to: string\n}\n\ntype AnyRouterWithPrivateState = AnyRouter & {\n routesById: Record<string, AnyRoute>\n buildRouteTree: () => Parameters<AnyRouter['setRoutes']>[0]\n setRoutes: AnyRouter['setRoutes']\n _refreshRoute?: () => Promise<void>\n _replaceRouteChunk: (route: AnyRoute, lazyFn: AnyRoute['lazyFn']) => void\n}\n\nfunction handleRouteUpdate(\n routeId: string,\n newRoute: AnyRouteWithPrivateProps,\n) {\n const router = window.__TSR_ROUTER__ as AnyRouterWithPrivateState\n const oldRoute = router.routesById[routeId] as\n | AnyRouteWithPrivateProps\n | undefined\n\n if (!oldRoute) {\n return\n }\n\n // Generated route-tree options are not present on the freshly imported route\n // module, but they must stay on the live route before rebuilding indexes.\n const generatedRouteOptionKeys = new Set(['id', 'path', 'getParentRoute'])\n const generatedRouteOptions: Record<string, unknown> = {}\n generatedRouteOptionKeys.forEach((key) => {\n if (key in oldRoute.options) {\n generatedRouteOptions[key] = oldRoute.options[key]\n }\n })\n\n const oldHasShellComponent = 'shellComponent' in oldRoute.options\n const newHasShellComponent = 'shellComponent' in newRoute.options\n const preserveComponentIdentity =\n oldHasShellComponent === newHasShellComponent\n\n // Keys whose identity must remain stable to prevent React from\n // unmounting/remounting the component tree. React Fast Refresh already\n // handles hot-updating the function bodies of these components — our job\n // is only to update non-component route options (loader, head, etc.).\n // For code-split (splittable) routes, the lazyRouteComponent wrapper is\n // already cached in the bundler hot data so its identity is stable.\n // For unsplittable routes (e.g. root routes), the component is a plain\n // function reference that gets recreated on every module re-execution,\n // so we must explicitly preserve the old reference.\n // Preserve component identity so React doesn't remount.\n // React Fast Refresh patches the function bodies in-place.\n const componentKeys = '__TSR_COMPONENT_TYPES__' as unknown as Array<string>\n if (preserveComponentIdentity) {\n componentKeys.forEach((key) => {\n if (key in oldRoute.options && key in newRoute.options) {\n newRoute.options[key] = oldRoute.options[key]\n }\n })\n }\n\n const nextOptions = {\n ...newRoute.options,\n ...generatedRouteOptions,\n }\n\n oldRoute.options = nextOptions\n oldRoute.update(nextOptions)\n router._replaceRouteChunk(oldRoute, newRoute.lazyFn)\n\n router.setRoutes(router.buildRouteTree())\n syncHotRouteExport(oldRoute)\n router.resolvePathCache.clear()\n void router._refreshRoute?.()\n\n function syncHotRouteExport(liveRoute: AnyRouteWithPrivateProps) {\n // routeTree.gen.ts mutates the original module export with generated\n // routing state. Mirror that state onto the fresh HMR export too, so\n // aliased route imports keep working after the module is hot-reloaded.\n newRoute.options = liveRoute.options\n newRoute.parentRoute = liveRoute.parentRoute\n newRoute._path = liveRoute._path\n newRoute._id = liveRoute._id\n newRoute._fullPath = liveRoute._fullPath\n newRoute._to = liveRoute._to\n }\n}\n\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function getHandleRouteUpdateCode(stableRouteOptionKeys: Array<string>) {\n return handleRouteUpdateStr.replace(\n /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n JSON.stringify(stableRouteOptionKeys),\n )\n}\n"],"mappings":";AAqBA,SAAS,kBACP,SACA,UACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO,WAAW;CAInC,IAAI,CAAC,UACH;CAKF,MAAM,2BAA2B,IAAI,IAAI;EAAC;EAAM;EAAQ;CAAgB,CAAC;CACzE,MAAM,wBAAiD,CAAC;CACxD,yBAAyB,SAAS,QAAQ;EACxC,IAAI,OAAO,SAAS,SAClB,sBAAsB,OAAO,SAAS,QAAQ;CAElD,CAAC;CAID,MAAM,4BAFuB,oBAAoB,SAAS,YAC7B,oBAAoB,SAAS;CAe1D,MAAM,gBAAgB;CACtB,IAAI,2BACF,cAAc,SAAS,QAAQ;EAC7B,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,SAC7C,SAAS,QAAQ,OAAO,SAAS,QAAQ;CAE7C,CAAC;CAGH,MAAM,cAAc;EAClB,GAAG,SAAS;EACZ,GAAG;CACL;CAEA,SAAS,UAAU;CACnB,SAAS,OAAO,WAAW;CAC3B,OAAO,mBAAmB,UAAU,SAAS,MAAM;CAEnD,OAAO,UAAU,OAAO,eAAe,CAAC;CACxC,mBAAmB,QAAQ;CAC3B,OAAO,iBAAiB,MAAM;CAC9B,OAAY,gBAAgB;CAE5B,SAAS,mBAAmB,WAAqC;EAI/D,SAAS,UAAU,UAAU;EAC7B,SAAS,cAAc,UAAU;EACjC,SAAS,QAAQ,UAAU;EAC3B,SAAS,MAAM,UAAU;EACzB,SAAS,YAAY,UAAU;EAC/B,SAAS,MAAM,UAAU;CAC3B;AACF;AAEA,IAAM,uBAAuB,kBAAkB,SAAS;AAExD,SAAgB,yBAAyB,uBAAsC;CAC7E,OAAO,qBAAqB,QAC1B,mCACA,KAAK,UAAU,qBAAqB,CACtC;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-plugin",
3
- "version": "1.168.23",
3
+ "version": "1.168.24-pre.0",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -106,9 +106,9 @@
106
106
  "chokidar": "^5.0.0",
107
107
  "unplugin": "^3.0.0",
108
108
  "zod": "^4.4.3",
109
- "@tanstack/router-core": "1.171.15",
110
- "@tanstack/router-utils": "1.162.2",
111
- "@tanstack/router-generator": "1.167.21"
109
+ "@tanstack/router-core": "1.171.16-pre.0",
110
+ "@tanstack/router-generator": "1.167.22-pre.0",
111
+ "@tanstack/router-utils": "1.162.2"
112
112
  },
113
113
  "devDependencies": {
114
114
  "@types/babel__core": "^7.20.5",
@@ -120,7 +120,7 @@
120
120
  "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0",
121
121
  "vite-plugin-solid": "^2.11.10 || ^3.0.0-0",
122
122
  "webpack": ">=5.92.0",
123
- "@tanstack/react-router": "^1.170.18"
123
+ "@tanstack/react-router": "^1.170.19-pre.0"
124
124
  },
125
125
  "peerDependenciesMeta": {
126
126
  "@rsbuild/core": {
@@ -147,12 +147,12 @@
147
147
  "test:unit:dev": "vitest --watch",
148
148
  "test:eslint": "eslint ./src",
149
149
  "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"",
150
- "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js",
151
150
  "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js",
152
151
  "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js",
153
152
  "test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js",
154
153
  "test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js",
155
- "test:types:ts60": "tsc",
154
+ "test:types:ts60": "tsc6",
155
+ "test:types:ts70": "tsc",
156
156
  "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .",
157
157
  "build": "vite build"
158
158
  }
@@ -1,15 +1,9 @@
1
- import type {
2
- AnyRoute,
3
- AnyRouteMatch,
4
- AnyRouter,
5
- RouterWritableStore,
6
- } from '@tanstack/router-core'
1
+ import type { AnyRoute, AnyRouter } from '@tanstack/router-core'
7
2
 
8
3
  type AnyRouteWithPrivateProps = AnyRoute & {
9
4
  options: Record<string, unknown>
10
5
  parentRoute: AnyRoute
11
- _componentsPromise?: Promise<void>
12
- _lazyPromise?: Promise<void>
6
+ _lazy?: Promise<void> | true
13
7
  update: (options: Record<string, unknown>) => unknown
14
8
  _path: string
15
9
  _id: string
@@ -17,37 +11,19 @@ type AnyRouteWithPrivateProps = AnyRoute & {
17
11
  _to: string
18
12
  }
19
13
 
20
- type AnyRouterWithPrivateMaps = AnyRouter & {
14
+ type AnyRouterWithPrivateState = AnyRouter & {
21
15
  routesById: Record<string, AnyRoute>
22
16
  buildRouteTree: () => Parameters<AnyRouter['setRoutes']>[0]
23
17
  setRoutes: AnyRouter['setRoutes']
24
- stores: AnyRouter['stores'] & {
25
- cachedMatchStores: Map<
26
- string,
27
- Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>
28
- >
29
- pendingMatchStores: Map<
30
- string,
31
- Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>
32
- >
33
- matchStores: Map<
34
- string,
35
- Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>
36
- >
37
- }
38
- }
39
-
40
- type AnyRouteMatchWithPrivateProps = AnyRouteMatch & {
41
- __beforeLoadContext?: unknown
42
- __routeContext?: Record<string, unknown>
43
- context?: Record<string, unknown>
18
+ _refreshRoute?: () => Promise<void>
19
+ _replaceRouteChunk: (route: AnyRoute, lazyFn: AnyRoute['lazyFn']) => void
44
20
  }
45
21
 
46
22
  function handleRouteUpdate(
47
23
  routeId: string,
48
24
  newRoute: AnyRouteWithPrivateProps,
49
25
  ) {
50
- const router = window.__TSR_ROUTER__ as AnyRouterWithPrivateMaps
26
+ const router = window.__TSR_ROUTER__ as AnyRouterWithPrivateState
51
27
  const oldRoute = router.routesById[routeId] as
52
28
  | AnyRouteWithPrivateProps
53
29
  | undefined
@@ -66,14 +42,6 @@ function handleRouteUpdate(
66
42
  }
67
43
  })
68
44
 
69
- const removedKeys = new Set<string>()
70
- Object.keys(oldRoute.options).forEach((key) => {
71
- if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {
72
- removedKeys.add(key)
73
- delete oldRoute.options[key]
74
- }
75
- })
76
-
77
45
  const oldHasShellComponent = 'shellComponent' in oldRoute.options
78
46
  const newHasShellComponent = 'shellComponent' in newRoute.options
79
47
  const preserveComponentIdentity =
@@ -106,60 +74,12 @@ function handleRouteUpdate(
106
74
 
107
75
  oldRoute.options = nextOptions
108
76
  oldRoute.update(nextOptions)
109
- oldRoute._componentsPromise = undefined
110
- oldRoute._lazyPromise = undefined
77
+ router._replaceRouteChunk(oldRoute, newRoute.lazyFn)
111
78
 
112
79
  router.setRoutes(router.buildRouteTree())
113
80
  syncHotRouteExport(oldRoute)
114
81
  router.resolvePathCache.clear()
115
-
116
- const filter = (m: AnyRouteMatch) => m.routeId === oldRoute.id
117
- const activeMatch = router.stores.matches.get().find(filter)
118
- const pendingMatch = router.stores.pendingMatches.get().find(filter)
119
- const cachedMatches = router.stores.cachedMatches.get().filter(filter)
120
-
121
- if (activeMatch || pendingMatch || cachedMatches.length > 0) {
122
- // Clear stale match data for removed route options BEFORE invalidating.
123
- // Without this, router.invalidate() -> matchRoutes() reuses the existing
124
- // match from the store (via ...existingMatch spread) and the stale
125
- // loaderData / __beforeLoadContext survives the reload cycle.
126
- //
127
- // We must update the store directly (not via router.updateMatch) because
128
- // updateMatch wraps in startTransition which may defer the state update,
129
- // and we need the clear to be visible before invalidate reads the store.
130
- if (removedKeys.has('loader') || removedKeys.has('beforeLoad')) {
131
- const matchIds = [
132
- activeMatch?.id,
133
- pendingMatch?.id,
134
- ...cachedMatches.map((match) => match.id),
135
- ].filter(Boolean) as Array<string>
136
- router.batch(() => {
137
- for (const matchId of matchIds) {
138
- const store =
139
- router.stores.pendingMatchStores.get(matchId) ||
140
- router.stores.matchStores.get(matchId) ||
141
- router.stores.cachedMatchStores.get(matchId)
142
- if (store) {
143
- store.set((prev) => {
144
- const next: AnyRouteMatchWithPrivateProps = { ...prev }
145
-
146
- if (removedKeys.has('loader')) {
147
- next.loaderData = undefined
148
- }
149
- if (removedKeys.has('beforeLoad')) {
150
- next.__beforeLoadContext = undefined
151
- next.context = rebuildMatchContextWithoutBeforeLoad(next)
152
- }
153
-
154
- return next
155
- })
156
- }
157
- }
158
- })
159
- }
160
-
161
- router.invalidate({ filter, sync: true })
162
- }
82
+ void router._refreshRoute?.()
163
83
 
164
84
  function syncHotRouteExport(liveRoute: AnyRouteWithPrivateProps) {
165
85
  // routeTree.gen.ts mutates the original module export with generated
@@ -172,66 +92,6 @@ function handleRouteUpdate(
172
92
  newRoute._fullPath = liveRoute._fullPath
173
93
  newRoute._to = liveRoute._to
174
94
  }
175
-
176
- function getStoreMatch(matchId: string) {
177
- return (
178
- router.stores.pendingMatchStores.get(matchId)?.get() ||
179
- router.stores.matchStores.get(matchId)?.get() ||
180
- router.stores.cachedMatchStores.get(matchId)?.get()
181
- )
182
- }
183
-
184
- function getMatchList(matchId: string) {
185
- const pendingMatches = router.stores.pendingMatches.get()
186
- if (pendingMatches.some((match) => match.id === matchId)) {
187
- return pendingMatches
188
- }
189
-
190
- const activeMatches = router.stores.matches.get()
191
- if (activeMatches.some((match) => match.id === matchId)) {
192
- return activeMatches
193
- }
194
-
195
- const cachedMatches = router.stores.cachedMatches.get()
196
- if (cachedMatches.some((match) => match.id === matchId)) {
197
- return cachedMatches
198
- }
199
-
200
- return []
201
- }
202
-
203
- function getParentMatch(match: AnyRouteMatch) {
204
- const matchList = getMatchList(match.id)
205
- const matchIndex = matchList.findIndex((item) => item.id === match.id)
206
-
207
- if (matchIndex <= 0) {
208
- return undefined
209
- }
210
-
211
- const parentMatch = matchList[matchIndex - 1]!
212
- return getStoreMatch(parentMatch.id) || parentMatch
213
- }
214
-
215
- function rebuildMatchContextWithoutBeforeLoad(
216
- match: AnyRouteMatchWithPrivateProps,
217
- ) {
218
- const parentMatch = getParentMatch(match)
219
- const getParentContext = (
220
- router as unknown as {
221
- getParentContext?: (
222
- parentMatch?: AnyRouteMatch,
223
- ) => Record<string, unknown> | undefined
224
- }
225
- ).getParentContext
226
- const parentContext = getParentContext
227
- ? getParentContext.call(router, parentMatch)
228
- : (parentMatch?.context ?? router.options.context)
229
-
230
- return {
231
- ...(parentContext ?? {}),
232
- ...(match.__routeContext ?? {}),
233
- }
234
- }
235
95
  }
236
96
 
237
97
  const handleRouteUpdateStr = handleRouteUpdate.toString()