@tanstack/router-plugin 1.168.4 → 1.168.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.
Files changed (30) hide show
  1. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs +1 -1
  2. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs.map +1 -1
  3. package/dist/cjs/core/hmr/handle-route-update.cjs +17 -18
  4. package/dist/cjs/core/hmr/handle-route-update.cjs.map +1 -1
  5. package/dist/cjs/core/router-code-splitter-plugin.cjs +2 -7
  6. package/dist/cjs/core/router-code-splitter-plugin.cjs.map +1 -1
  7. package/dist/cjs/core/router-hmr-plugin.cjs +1 -6
  8. package/dist/cjs/core/router-hmr-plugin.cjs.map +1 -1
  9. package/dist/cjs/core/router-hmr-plugin.d.cts +5 -0
  10. package/dist/cjs/core/utils.cjs +6 -0
  11. package/dist/cjs/core/utils.cjs.map +1 -1
  12. package/dist/cjs/core/utils.d.cts +1 -0
  13. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js +1 -1
  14. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js.map +1 -1
  15. package/dist/esm/core/hmr/handle-route-update.js +17 -18
  16. package/dist/esm/core/hmr/handle-route-update.js.map +1 -1
  17. package/dist/esm/core/router-code-splitter-plugin.js +3 -8
  18. package/dist/esm/core/router-code-splitter-plugin.js.map +1 -1
  19. package/dist/esm/core/router-hmr-plugin.d.ts +5 -0
  20. package/dist/esm/core/router-hmr-plugin.js +2 -7
  21. package/dist/esm/core/router-hmr-plugin.js.map +1 -1
  22. package/dist/esm/core/utils.d.ts +1 -0
  23. package/dist/esm/core/utils.js +6 -1
  24. package/dist/esm/core/utils.js.map +1 -1
  25. package/package.json +4 -4
  26. package/src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts +1 -1
  27. package/src/core/hmr/handle-route-update.ts +30 -35
  28. package/src/core/router-code-splitter-plugin.ts +3 -11
  29. package/src/core/router-hmr-plugin.ts +2 -8
  30. package/src/core/utils.ts +6 -0
@@ -8,7 +8,7 @@ _babel_template = require_runtime.__toESM(_babel_template);
8
8
  var buildReactRefreshIgnoredRouteExportsStatements = _babel_template.statements(`
9
9
  const hot = import.meta.hot
10
10
  if (hot && typeof window !== 'undefined') {
11
- ;(hot.data ??= {})
11
+ hot.data ??= {}
12
12
  const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {
13
13
  const ignoredExportsById = new Map()
14
14
  const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports
@@ -1 +1 @@
1
- {"version":3,"file":"react-refresh-ignored-route-exports.cjs","names":[],"sources":["../../../../../src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport * as t from '@babel/types'\nimport { getUniqueProgramIdentifier } from '../../utils'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\n\nconst buildReactRefreshIgnoredRouteExportsStatements = template.statements(\n `\nconst hot = import.meta.hot\nif (hot && typeof window !== 'undefined') {\n ;(hot.data ??= {})\n const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {\n const ignoredExportsById = new Map()\n const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports\n\n window.__getReactRefreshIgnoredExports = (ctx) => {\n const ignoredExports = previousGetIgnoredExports?.(ctx) ?? []\n const moduleIgnored = ignoredExportsById.get(ctx.id) ?? []\n return [...ignoredExports, ...moduleIgnored]\n }\n\n return {\n ignoredExportsById,\n }\n })()\n\n tsrReactRefresh.ignoredExportsById.set(%%moduleId%%, ['Route'])\n}\n`,\n { syntacticPlaceholders: true },\n)\n\n/**\n * A trivial component-shaped export that gives `@vitejs/plugin-react` a valid\n * Fast Refresh boundary. Without at least one non-ignored component export,\n * the module would be invalidated (full page reload) on every update even\n * though our custom route HMR handler already manages the update.\n */\nconst buildRefreshAnchorStatement = template.statement(\n `export function %%anchorName%%() { return null }`,\n { syntacticPlaceholders: true },\n)\n\nexport function createReactRefreshIgnoredRouteExportsPlugin(): ReferenceRouteCompilerPlugin {\n return {\n name: 'react-refresh-ignored-route-exports',\n onAddHmr(ctx) {\n const anchorName = getUniqueProgramIdentifier(\n ctx.programPath,\n 'TSRFastRefreshAnchor',\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildReactRefreshIgnoredRouteExportsStatements({\n moduleId: t.stringLiteral(ctx.opts.id),\n }),\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildRefreshAnchorStatement({ anchorName }),\n )\n\n return { modified: true }\n },\n }\n}\n"],"mappings":";;;;;;;AAKA,IAAM,iDAAiD,gBAAS,WAC9D;;;;;;;;;;;;;;;;;;;;;GAsBA,EAAE,uBAAuB,MAAM,CAChC;;;;;;;AAQD,IAAM,8BAA8B,gBAAS,UAC3C,oDACA,EAAE,uBAAuB,MAAM,CAChC;AAED,SAAgB,8CAA4E;AAC1F,QAAO;EACL,MAAM;EACN,SAAS,KAAK;GACZ,MAAM,aAAa,cAAA,2BACjB,IAAI,aACJ,uBACD;AAED,OAAI,YAAY,cACd,QACA,+CAA+C,EAC7C,UAAU,aAAE,cAAc,IAAI,KAAK,GAAG,EACvC,CAAC,CACH;AAED,OAAI,YAAY,cACd,QACA,4BAA4B,EAAE,YAAY,CAAC,CAC5C;AAED,UAAO,EAAE,UAAU,MAAM;;EAE5B"}
1
+ {"version":3,"file":"react-refresh-ignored-route-exports.cjs","names":[],"sources":["../../../../../src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport * as t from '@babel/types'\nimport { getUniqueProgramIdentifier } from '../../utils'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\n\nconst buildReactRefreshIgnoredRouteExportsStatements = template.statements(\n `\nconst hot = import.meta.hot\nif (hot && typeof window !== 'undefined') {\n hot.data ??= {}\n const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {\n const ignoredExportsById = new Map()\n const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports\n\n window.__getReactRefreshIgnoredExports = (ctx) => {\n const ignoredExports = previousGetIgnoredExports?.(ctx) ?? []\n const moduleIgnored = ignoredExportsById.get(ctx.id) ?? []\n return [...ignoredExports, ...moduleIgnored]\n }\n\n return {\n ignoredExportsById,\n }\n })()\n\n tsrReactRefresh.ignoredExportsById.set(%%moduleId%%, ['Route'])\n}\n`,\n { syntacticPlaceholders: true },\n)\n\n/**\n * A trivial component-shaped export that gives `@vitejs/plugin-react` a valid\n * Fast Refresh boundary. Without at least one non-ignored component export,\n * the module would be invalidated (full page reload) on every update even\n * though our custom route HMR handler already manages the update.\n */\nconst buildRefreshAnchorStatement = template.statement(\n `export function %%anchorName%%() { return null }`,\n { syntacticPlaceholders: true },\n)\n\nexport function createReactRefreshIgnoredRouteExportsPlugin(): ReferenceRouteCompilerPlugin {\n return {\n name: 'react-refresh-ignored-route-exports',\n onAddHmr(ctx) {\n const anchorName = getUniqueProgramIdentifier(\n ctx.programPath,\n 'TSRFastRefreshAnchor',\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildReactRefreshIgnoredRouteExportsStatements({\n moduleId: t.stringLiteral(ctx.opts.id),\n }),\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildRefreshAnchorStatement({ anchorName }),\n )\n\n return { modified: true }\n },\n }\n}\n"],"mappings":";;;;;;;AAKA,IAAM,iDAAiD,gBAAS,WAC9D;;;;;;;;;;;;;;;;;;;;;GAsBA,EAAE,uBAAuB,MAAM,CAChC;;;;;;;AAQD,IAAM,8BAA8B,gBAAS,UAC3C,oDACA,EAAE,uBAAuB,MAAM,CAChC;AAED,SAAgB,8CAA4E;AAC1F,QAAO;EACL,MAAM;EACN,SAAS,KAAK;GACZ,MAAM,aAAa,cAAA,2BACjB,IAAI,aACJ,uBACD;AAED,OAAI,YAAY,cACd,QACA,+CAA+C,EAC7C,UAAU,aAAE,cAAc,IAAI,KAAK,GAAG,EACvC,CAAC,CACH;AAED,OAAI,YAAY,cACd,QACA,4BAA4B,EAAE,YAAY,CAAC,CAC5C;AAED,UAAO,EAAE,UAAU,MAAM;;EAE5B"}
@@ -3,9 +3,18 @@ function handleRouteUpdate(routeId, newRoute) {
3
3
  const router = window.__TSR_ROUTER__;
4
4
  const oldRoute = router.routesById[routeId];
5
5
  if (!oldRoute) return;
6
+ const generatedRouteOptionKeys = new Set([
7
+ "id",
8
+ "path",
9
+ "getParentRoute"
10
+ ]);
11
+ const generatedRouteOptions = {};
12
+ generatedRouteOptionKeys.forEach((key) => {
13
+ if (key in oldRoute.options) generatedRouteOptions[key] = oldRoute.options[key];
14
+ });
6
15
  const removedKeys = /* @__PURE__ */ new Set();
7
16
  Object.keys(oldRoute.options).forEach((key) => {
8
- if (!(key in newRoute.options)) {
17
+ if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {
9
18
  removedKeys.add(key);
10
19
  delete oldRoute.options[key];
11
20
  }
@@ -15,17 +24,16 @@ function handleRouteUpdate(routeId, newRoute) {
15
24
  if (preserveComponentIdentity) componentKeys.forEach((key) => {
16
25
  if (key in oldRoute.options && key in newRoute.options) newRoute.options[key] = oldRoute.options[key];
17
26
  });
18
- oldRoute.options = newRoute.options;
19
- oldRoute.update(newRoute.options);
27
+ const nextOptions = {
28
+ ...newRoute.options,
29
+ ...generatedRouteOptions
30
+ };
31
+ oldRoute.options = nextOptions;
32
+ oldRoute.update(nextOptions);
20
33
  oldRoute._componentsPromise = void 0;
21
34
  oldRoute._lazyPromise = void 0;
22
- router.routesById[oldRoute.id] = oldRoute;
23
- router.routesByPath[oldRoute.fullPath] = oldRoute;
24
- router.processedTree.matchCache.clear();
25
- router.processedTree.flatCache?.clear();
26
- router.processedTree.singleCache.clear();
35
+ router.setRoutes(router.buildRouteTree());
27
36
  router.resolvePathCache.clear();
28
- walkReplaceSegmentTree(oldRoute, router.processedTree.segmentTree);
29
37
  const filter = (m) => m.routeId === oldRoute.id;
30
38
  const activeMatch = router.stores.matches.get().find(filter);
31
39
  const pendingMatch = router.stores.pendingMatches.get().find(filter);
@@ -57,15 +65,6 @@ function handleRouteUpdate(routeId, newRoute) {
57
65
  sync: true
58
66
  });
59
67
  }
60
- function walkReplaceSegmentTree(route, node) {
61
- if (node.route?.id === route.id) node.route = route;
62
- if (node.index) walkReplaceSegmentTree(route, node.index);
63
- node.static?.forEach((child) => walkReplaceSegmentTree(route, child));
64
- node.staticInsensitive?.forEach((child) => walkReplaceSegmentTree(route, child));
65
- node.dynamic?.forEach((child) => walkReplaceSegmentTree(route, child));
66
- node.optional?.forEach((child) => walkReplaceSegmentTree(route, child));
67
- node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child));
68
- }
69
68
  function getStoreMatch(matchId) {
70
69
  return router.stores.pendingMatchStores.get(matchId)?.get() || router.stores.matchStores.get(matchId)?.get() || router.stores.cachedMatchStores.get(matchId)?.get();
71
70
  }
@@ -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 _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 routesByPath: Record<string, AnyRoute>\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 // 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 const removedKeys = new Set<string>()\n Object.keys(oldRoute.options).forEach((key) => {\n if (!(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 // 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 oldRoute.options = newRoute.options\n oldRoute.update(newRoute.options)\n oldRoute._componentsPromise = undefined\n oldRoute._lazyPromise = undefined\n\n router.routesById[oldRoute.id] = oldRoute\n router.routesByPath[oldRoute.fullPath] = oldRoute\n\n router.processedTree.matchCache.clear()\n router.processedTree.flatCache?.clear()\n router.processedTree.singleCache.clear()\n router.resolvePathCache.clear()\n walkReplaceSegmentTree(oldRoute, router.processedTree.segmentTree)\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 walkReplaceSegmentTree(\n route: AnyRouteWithPrivateProps,\n node: AnyRouter['processedTree']['segmentTree'],\n ) {\n if (node.route?.id === route.id) node.route = route\n if (node.index) walkReplaceSegmentTree(route, node.index)\n node.static?.forEach((child) => walkReplaceSegmentTree(route, child))\n node.staticInsensitive?.forEach((child) =>\n walkReplaceSegmentTree(route, child),\n )\n node.dynamic?.forEach((child) => walkReplaceSegmentTree(route, child))\n node.optional?.forEach((child) => walkReplaceSegmentTree(route, child))\n node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child))\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 {\n AnyRoute,\n AnyRouteMatch,\n AnyRouter,\n RouterWritableStore,\n} from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n options: Record<string, unknown>\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 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 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":";AA4CA,SAAS,kBACP,SACA,UACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO,WAAW;AAInC,KAAI,CAAC,SACH;CAKF,MAAM,2BAA2B,IAAI,IAAI;EAAC;EAAM;EAAQ;EAAiB,CAAC;CAC1E,MAAM,wBAAiD,EAAE;AACzD,0BAAyB,SAAS,QAAQ;AACxC,MAAI,OAAO,SAAS,QAClB,uBAAsB,OAAO,SAAS,QAAQ;GAEhD;CAEF,MAAM,8BAAc,IAAI,KAAa;AACrC,QAAO,KAAK,SAAS,QAAQ,CAAC,SAAS,QAAQ;AAC7C,MAAI,CAAC,yBAAyB,IAAI,IAAI,IAAI,EAAE,OAAO,SAAS,UAAU;AACpE,eAAY,IAAI,IAAI;AACpB,UAAO,SAAS,QAAQ;;GAE1B;CAIF,MAAM,4BAFuB,oBAAoB,SAAS,YAC7B,oBAAoB,SAAS;CAe1D,MAAM,gBAAgB;AACtB,KAAI,0BACF,eAAc,SAAS,QAAQ;AAC7B,MAAI,OAAO,SAAS,WAAW,OAAO,SAAS,QAC7C,UAAS,QAAQ,OAAO,SAAS,QAAQ;GAE3C;CAGJ,MAAM,cAAc;EAClB,GAAG,SAAS;EACZ,GAAG;EACJ;AAED,UAAS,UAAU;AACnB,UAAS,OAAO,YAAY;AAC5B,UAAS,qBAAqB,KAAA;AAC9B,UAAS,eAAe,KAAA;AAExB,QAAO,UAAU,OAAO,gBAAgB,CAAC;AACzC,QAAO,iBAAiB,OAAO;CAE/B,MAAM,UAAU,MAAqB,EAAE,YAAY,SAAS;CAC5D,MAAM,cAAc,OAAO,OAAO,QAAQ,KAAK,CAAC,KAAK,OAAO;CAC5D,MAAM,eAAe,OAAO,OAAO,eAAe,KAAK,CAAC,KAAK,OAAO;CACpE,MAAM,gBAAgB,OAAO,OAAO,cAAc,KAAK,CAAC,OAAO,OAAO;AAEtE,KAAI,eAAe,gBAAgB,cAAc,SAAS,GAAG;AAS3D,MAAI,YAAY,IAAI,SAAS,IAAI,YAAY,IAAI,aAAa,EAAE;GAC9D,MAAM,WAAW;IACf,aAAa;IACb,cAAc;IACd,GAAG,cAAc,KAAK,UAAU,MAAM,GAAG;IAC1C,CAAC,OAAO,QAAQ;AACjB,UAAO,YAAY;AACjB,SAAK,MAAM,WAAW,UAAU;KAC9B,MAAM,QACJ,OAAO,OAAO,mBAAmB,IAAI,QAAQ,IAC7C,OAAO,OAAO,YAAY,IAAI,QAAQ,IACtC,OAAO,OAAO,kBAAkB,IAAI,QAAQ;AAC9C,SAAI,MACF,OAAM,KAAK,SAAS;MAClB,MAAM,OAAsC,EAAE,GAAG,MAAM;AAEvD,UAAI,YAAY,IAAI,SAAS,CAC3B,MAAK,aAAa,KAAA;AAEpB,UAAI,YAAY,IAAI,aAAa,EAAE;AACjC,YAAK,sBAAsB,KAAA;AAC3B,YAAK,UAAU,qCAAqC,KAAK;;AAG3D,aAAO;OACP;;KAGN;;AAGJ,SAAO,WAAW;GAAE;GAAQ,MAAM;GAAM,CAAC;;CAG3C,SAAS,cAAc,SAAiB;AACtC,SACE,OAAO,OAAO,mBAAmB,IAAI,QAAQ,EAAE,KAAK,IACpD,OAAO,OAAO,YAAY,IAAI,QAAQ,EAAE,KAAK,IAC7C,OAAO,OAAO,kBAAkB,IAAI,QAAQ,EAAE,KAAK;;CAIvD,SAAS,aAAa,SAAiB;EACrC,MAAM,iBAAiB,OAAO,OAAO,eAAe,KAAK;AACzD,MAAI,eAAe,MAAM,UAAU,MAAM,OAAO,QAAQ,CACtD,QAAO;EAGT,MAAM,gBAAgB,OAAO,OAAO,QAAQ,KAAK;AACjD,MAAI,cAAc,MAAM,UAAU,MAAM,OAAO,QAAQ,CACrD,QAAO;EAGT,MAAM,gBAAgB,OAAO,OAAO,cAAc,KAAK;AACvD,MAAI,cAAc,MAAM,UAAU,MAAM,OAAO,QAAQ,CACrD,QAAO;AAGT,SAAO,EAAE;;CAGX,SAAS,eAAe,OAAsB;EAC5C,MAAM,YAAY,aAAa,MAAM,GAAG;EACxC,MAAM,aAAa,UAAU,WAAW,SAAS,KAAK,OAAO,MAAM,GAAG;AAEtE,MAAI,cAAc,EAChB;EAGF,MAAM,cAAc,UAAU,aAAa;AAC3C,SAAO,cAAc,YAAY,GAAG,IAAI;;CAG1C,SAAS,qCACP,OACA;EACA,MAAM,cAAc,eAAe,MAAM;EACzC,MAAM,mBACJ,OAKA;AAKF,SAAO;GACL,IALoB,mBAClB,iBAAiB,KAAK,QAAQ,YAAY,GACzC,aAAa,WAAW,OAAO,QAAQ,YAGrB,EAAE;GACvB,GAAI,MAAM,kBAAkB,EAAE;GAC/B;;;AAIL,IAAM,uBAAuB,kBAAkB,UAAU;AAEzD,SAAgB,yBAAyB,uBAAsC;AAC7E,QAAO,qBAAqB,QAC1B,mCACA,KAAK,UAAU,sBAAsB,CACtC"}
@@ -135,11 +135,6 @@ function createRouterCodeSplitterPlugin(options = {}, routerPluginContext) {
135
135
  }
136
136
  return result;
137
137
  };
138
- const includedCode = [
139
- "createFileRoute(",
140
- "createRootRoute(",
141
- "createRootRouteWithContext("
142
- ];
143
138
  return [
144
139
  {
145
140
  name: "tanstack-router:code-splitter:compile-reference-file",
@@ -150,12 +145,12 @@ function createRouterCodeSplitterPlugin(options = {}, routerPluginContext) {
150
145
  exclude: [require_constants.tsrSplit, require_constants.tsrShared],
151
146
  include: /\.(m|c)?(j|t)sx?$/
152
147
  },
153
- code: { include: includedCode }
148
+ code: { include: require_utils.routeFactoryCallCodeFilter }
154
149
  },
155
150
  handler(code, id) {
156
151
  const normalizedId = require_utils.normalizePath(id);
157
152
  const generatorFileInfo = routerPluginContext.routesByFile.get(normalizedId);
158
- if (generatorFileInfo && includedCode.some((included) => code.includes(included))) return handleCompilingReferenceFile(code, normalizedId, generatorFileInfo);
153
+ if (generatorFileInfo) return handleCompilingReferenceFile(code, normalizedId, generatorFileInfo);
159
154
  return null;
160
155
  }
161
156
  },
@@ -1 +1 @@
1
- {"version":3,"file":"router-code-splitter-plugin.cjs","names":[],"sources":["../../../src/core/router-code-splitter-plugin.ts"],"sourcesContent":["/**\n * It is important to familiarize yourself with how the code-splitting works in this plugin.\n * https://github.com/TanStack/router/pull/3355\n */\n\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { logDiff } from '@tanstack/router-utils'\nimport { getConfig, splitGroupingsSchema } from './config'\nimport {\n compileCodeSplitReferenceRoute,\n compileCodeSplitSharedRoute,\n compileCodeSplitVirtualRoute,\n computeSharedBindings,\n detectCodeSplitGroupingsFromRoute,\n} from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport {\n defaultCodeSplitGroupings,\n splitRouteIdentNodes,\n tsrShared,\n tsrSplit,\n} from './constants'\nimport { decodeIdentifier } from './code-splitter/path-ids'\nimport { debug, normalizePath } from './utils'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst CODE_SPLITTER_PLUGIN_NAME =\n 'tanstack-router:code-splitter:compile-reference-file'\n\ntype TransformationPluginInfo = {\n pluginNames: Array<string>\n pkg: string\n usage: string\n}\n\n/**\n * JSX transformation plugins grouped by framework.\n * These plugins must come AFTER the TanStack Router plugin in the Vite config.\n */\nconst TRANSFORMATION_PLUGINS_BY_FRAMEWORK: Record<\n string,\n Array<TransformationPluginInfo>\n> = {\n react: [\n {\n // Babel-based React plugin\n pluginNames: ['vite:react-babel', 'vite:react-refresh'],\n pkg: '@vitejs/plugin-react',\n usage: 'react()',\n },\n {\n // SWC-based React plugin\n pluginNames: ['vite:react-swc', 'vite:react-swc:resolve-runtime'],\n pkg: '@vitejs/plugin-react-swc',\n usage: 'reactSwc()',\n },\n {\n // OXC-based React plugin (deprecated but should still be handled)\n pluginNames: ['vite:react-oxc:config', 'vite:react-oxc:refresh-runtime'],\n pkg: '@vitejs/plugin-react-oxc',\n usage: 'reactOxc()',\n },\n ],\n solid: [\n {\n pluginNames: ['solid'],\n pkg: 'vite-plugin-solid',\n usage: 'solid()',\n },\n ],\n}\n\nexport function createRouterCodeSplitterPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config | (() => Config)> | undefined>> {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n function initUserConfig() {\n if (typeof options === 'function') {\n userConfig = options()\n } else {\n userConfig = getConfig(options, ROOT)\n }\n }\n const isProduction = process.env.NODE_ENV === 'production'\n // Map from normalized route file path → set of shared binding names.\n // Populated by the reference compiler, consumed by virtual and shared compilers.\n const sharedBindingsMap = new Map<string, Set<string>>()\n\n const getGlobalCodeSplitGroupings = () => {\n return (\n userConfig.codeSplittingOptions?.defaultBehavior ||\n defaultCodeSplitGroupings\n )\n }\n const getShouldSplitFn = () => {\n return userConfig.codeSplittingOptions?.splitBehavior\n }\n\n const handleCompilingReferenceFile = (\n code: string,\n id: string,\n generatorNodeInfo: GetRoutesByFileMapResultValue,\n ): UnpluginTransformResult => {\n if (debug) console.info('Compiling Route: ', id)\n\n const fromCode = detectCodeSplitGroupingsFromRoute({\n code,\n filename: id,\n })\n\n if (fromCode.groupings !== undefined) {\n const res = splitGroupingsSchema.safeParse(fromCode.groupings)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const userShouldSplitFn = getShouldSplitFn()\n\n const pluginSplitBehavior = userShouldSplitFn?.({\n routeId: generatorNodeInfo.routeId,\n }) as CodeSplitGroupings | undefined\n\n if (pluginSplitBehavior) {\n const res = splitGroupingsSchema.safeParse(pluginSplitBehavior)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings returned when using \\`splitBehavior\\` for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const splitGroupings: CodeSplitGroupings =\n fromCode.groupings ?? pluginSplitBehavior ?? getGlobalCodeSplitGroupings()\n\n // Compute shared bindings before compiling the reference route\n const sharedBindings = computeSharedBindings({\n code,\n filename: id,\n codeSplitGroupings: splitGroupings,\n })\n if (sharedBindings.size > 0) {\n sharedBindingsMap.set(id, sharedBindings)\n } else {\n sharedBindingsMap.delete(id)\n }\n\n const addHmr =\n (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n const compiledReferenceRoute = compileCodeSplitReferenceRoute({\n code,\n codeSplitGroupings: splitGroupings,\n targetFramework: userConfig.target,\n filename: id,\n id,\n deleteNodes: userConfig.codeSplittingOptions?.deleteNodes\n ? new Set(userConfig.codeSplittingOptions.deleteNodes)\n : undefined,\n addHmr,\n hmrStyle,\n hmrRouteId: generatorNodeInfo.routeId,\n sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: userConfig.target,\n addHmr,\n hmrStyle,\n }),\n })\n\n if (compiledReferenceRoute === null) {\n if (debug) {\n console.info(\n `No changes made to route \"${id}\", skipping code-splitting.`,\n )\n }\n return null\n }\n if (debug) {\n logDiff(code, compiledReferenceRoute.code)\n console.log('Output:\\n', compiledReferenceRoute.code + '\\n\\n')\n }\n\n return compiledReferenceRoute\n }\n\n const handleCompilingVirtualFile = (\n code: string,\n id: string,\n ): UnpluginTransformResult => {\n if (debug) console.info('Splitting Route: ', id)\n\n const [_, ...pathnameParts] = id.split('?')\n\n const searchParams = new URLSearchParams(pathnameParts.join('?'))\n const splitValue = searchParams.get(tsrSplit)\n\n if (!splitValue) {\n throw new Error(\n `The split value for the virtual route \"${id}\" was not found.`,\n )\n }\n\n const rawGrouping = decodeIdentifier(splitValue)\n const grouping = [...new Set(rawGrouping)].filter((p) =>\n splitRouteIdentNodes.includes(p as any),\n ) as Array<SplitRouteIdentNodes>\n\n const baseId = id.split('?')[0]!\n const resolvedSharedBindings = sharedBindingsMap.get(baseId)\n\n const result = compileCodeSplitVirtualRoute({\n code,\n filename: id,\n splitTargets: grouping,\n sharedBindings: resolvedSharedBindings,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n }\n\n const includedCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n ]\n return [\n {\n name: 'tanstack-router:code-splitter:compile-reference-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: {\n exclude: [tsrSplit, tsrShared],\n // this is necessary for webpack / rspack to avoid matching .html files\n include: /\\.(m|c)?(j|t)sx?$/,\n },\n code: {\n include: includedCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const generatorFileInfo =\n routerPluginContext.routesByFile.get(normalizedId)\n if (\n generatorFileInfo &&\n includedCode.some((included) => code.includes(included))\n ) {\n return handleCompilingReferenceFile(\n code,\n normalizedId,\n generatorFileInfo,\n )\n }\n\n return null\n },\n },\n\n vite: {\n configResolved(config) {\n ROOT = config.root\n initUserConfig()\n\n // Validate plugin order - router must come before JSX transformation plugins\n const routerPluginIndex = config.plugins.findIndex(\n (p) => p.name === CODE_SPLITTER_PLUGIN_NAME,\n )\n\n if (routerPluginIndex === -1) return\n\n const frameworkPlugins =\n TRANSFORMATION_PLUGINS_BY_FRAMEWORK[userConfig.target]\n if (!frameworkPlugins) return\n\n for (const transformPlugin of frameworkPlugins) {\n const transformPluginIndex = config.plugins.findIndex((p) =>\n transformPlugin.pluginNames.includes(p.name),\n )\n\n if (\n transformPluginIndex !== -1 &&\n transformPluginIndex < routerPluginIndex\n ) {\n throw new Error(\n `Plugin order error: '${transformPlugin.pkg}' is placed before '@tanstack/router-plugin'.\\n\\n` +\n `The TanStack Router plugin must come BEFORE JSX transformation plugins.\\n\\n` +\n `Please update your Vite config:\\n\\n` +\n ` plugins: [\\n` +\n ` tanstackRouter(),\\n` +\n ` ${transformPlugin.usage},\\n` +\n ` ]\\n`,\n )\n }\n }\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n\n rspack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n\n webpack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-virtual-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-split/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n return handleCompilingVirtualFile(code, normalizedId)\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-shared-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-shared/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n const [baseId] = normalizedId.split('?')\n\n if (!baseId) return null\n\n const sharedBindings = sharedBindingsMap.get(baseId)\n if (!sharedBindings || sharedBindings.size === 0) return null\n\n if (debug) console.info('Compiling Shared Module: ', id)\n\n const result = compileCodeSplitSharedRoute({\n code,\n sharedBindings,\n filename: normalizedId,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n ]\n}\n\nexport const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}) => {\n return createRouterCodeSplitterPlugin(options, createRouterPluginContext())\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"router-code-splitter-plugin.cjs","names":[],"sources":["../../../src/core/router-code-splitter-plugin.ts"],"sourcesContent":["/**\n * It is important to familiarize yourself with how the code-splitting works in this plugin.\n * https://github.com/TanStack/router/pull/3355\n */\n\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { logDiff } from '@tanstack/router-utils'\nimport { getConfig, splitGroupingsSchema } from './config'\nimport {\n compileCodeSplitReferenceRoute,\n compileCodeSplitSharedRoute,\n compileCodeSplitVirtualRoute,\n computeSharedBindings,\n detectCodeSplitGroupingsFromRoute,\n} from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport {\n defaultCodeSplitGroupings,\n splitRouteIdentNodes,\n tsrShared,\n tsrSplit,\n} from './constants'\nimport { decodeIdentifier } from './code-splitter/path-ids'\nimport { debug, normalizePath, routeFactoryCallCodeFilter } from './utils'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst CODE_SPLITTER_PLUGIN_NAME =\n 'tanstack-router:code-splitter:compile-reference-file'\n\ntype TransformationPluginInfo = {\n pluginNames: Array<string>\n pkg: string\n usage: string\n}\n\n/**\n * JSX transformation plugins grouped by framework.\n * These plugins must come AFTER the TanStack Router plugin in the Vite config.\n */\nconst TRANSFORMATION_PLUGINS_BY_FRAMEWORK: Record<\n string,\n Array<TransformationPluginInfo>\n> = {\n react: [\n {\n // Babel-based React plugin\n pluginNames: ['vite:react-babel', 'vite:react-refresh'],\n pkg: '@vitejs/plugin-react',\n usage: 'react()',\n },\n {\n // SWC-based React plugin\n pluginNames: ['vite:react-swc', 'vite:react-swc:resolve-runtime'],\n pkg: '@vitejs/plugin-react-swc',\n usage: 'reactSwc()',\n },\n {\n // OXC-based React plugin (deprecated but should still be handled)\n pluginNames: ['vite:react-oxc:config', 'vite:react-oxc:refresh-runtime'],\n pkg: '@vitejs/plugin-react-oxc',\n usage: 'reactOxc()',\n },\n ],\n solid: [\n {\n pluginNames: ['solid'],\n pkg: 'vite-plugin-solid',\n usage: 'solid()',\n },\n ],\n}\n\nexport function createRouterCodeSplitterPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config | (() => Config)> | undefined>> {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n function initUserConfig() {\n if (typeof options === 'function') {\n userConfig = options()\n } else {\n userConfig = getConfig(options, ROOT)\n }\n }\n const isProduction = process.env.NODE_ENV === 'production'\n // Map from normalized route file path → set of shared binding names.\n // Populated by the reference compiler, consumed by virtual and shared compilers.\n const sharedBindingsMap = new Map<string, Set<string>>()\n\n const getGlobalCodeSplitGroupings = () => {\n return (\n userConfig.codeSplittingOptions?.defaultBehavior ||\n defaultCodeSplitGroupings\n )\n }\n const getShouldSplitFn = () => {\n return userConfig.codeSplittingOptions?.splitBehavior\n }\n\n const handleCompilingReferenceFile = (\n code: string,\n id: string,\n generatorNodeInfo: GetRoutesByFileMapResultValue,\n ): UnpluginTransformResult => {\n if (debug) console.info('Compiling Route: ', id)\n\n const fromCode = detectCodeSplitGroupingsFromRoute({\n code,\n filename: id,\n })\n\n if (fromCode.groupings !== undefined) {\n const res = splitGroupingsSchema.safeParse(fromCode.groupings)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const userShouldSplitFn = getShouldSplitFn()\n\n const pluginSplitBehavior = userShouldSplitFn?.({\n routeId: generatorNodeInfo.routeId,\n }) as CodeSplitGroupings | undefined\n\n if (pluginSplitBehavior) {\n const res = splitGroupingsSchema.safeParse(pluginSplitBehavior)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings returned when using \\`splitBehavior\\` for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const splitGroupings: CodeSplitGroupings =\n fromCode.groupings ?? pluginSplitBehavior ?? getGlobalCodeSplitGroupings()\n\n // Compute shared bindings before compiling the reference route\n const sharedBindings = computeSharedBindings({\n code,\n filename: id,\n codeSplitGroupings: splitGroupings,\n })\n if (sharedBindings.size > 0) {\n sharedBindingsMap.set(id, sharedBindings)\n } else {\n sharedBindingsMap.delete(id)\n }\n\n const addHmr =\n (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n const compiledReferenceRoute = compileCodeSplitReferenceRoute({\n code,\n codeSplitGroupings: splitGroupings,\n targetFramework: userConfig.target,\n filename: id,\n id,\n deleteNodes: userConfig.codeSplittingOptions?.deleteNodes\n ? new Set(userConfig.codeSplittingOptions.deleteNodes)\n : undefined,\n addHmr,\n hmrStyle,\n hmrRouteId: generatorNodeInfo.routeId,\n sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: userConfig.target,\n addHmr,\n hmrStyle,\n }),\n })\n\n if (compiledReferenceRoute === null) {\n if (debug) {\n console.info(\n `No changes made to route \"${id}\", skipping code-splitting.`,\n )\n }\n return null\n }\n if (debug) {\n logDiff(code, compiledReferenceRoute.code)\n console.log('Output:\\n', compiledReferenceRoute.code + '\\n\\n')\n }\n\n return compiledReferenceRoute\n }\n\n const handleCompilingVirtualFile = (\n code: string,\n id: string,\n ): UnpluginTransformResult => {\n if (debug) console.info('Splitting Route: ', id)\n\n const [_, ...pathnameParts] = id.split('?')\n\n const searchParams = new URLSearchParams(pathnameParts.join('?'))\n const splitValue = searchParams.get(tsrSplit)\n\n if (!splitValue) {\n throw new Error(\n `The split value for the virtual route \"${id}\" was not found.`,\n )\n }\n\n const rawGrouping = decodeIdentifier(splitValue)\n const grouping = [...new Set(rawGrouping)].filter((p) =>\n splitRouteIdentNodes.includes(p as any),\n ) as Array<SplitRouteIdentNodes>\n\n const baseId = id.split('?')[0]!\n const resolvedSharedBindings = sharedBindingsMap.get(baseId)\n\n const result = compileCodeSplitVirtualRoute({\n code,\n filename: id,\n splitTargets: grouping,\n sharedBindings: resolvedSharedBindings,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n }\n\n return [\n {\n name: 'tanstack-router:code-splitter:compile-reference-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: {\n exclude: [tsrSplit, tsrShared],\n // this is necessary for webpack / rspack to avoid matching .html files\n include: /\\.(m|c)?(j|t)sx?$/,\n },\n code: {\n include: routeFactoryCallCodeFilter,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const generatorFileInfo =\n routerPluginContext.routesByFile.get(normalizedId)\n if (generatorFileInfo) {\n return handleCompilingReferenceFile(\n code,\n normalizedId,\n generatorFileInfo,\n )\n }\n\n return null\n },\n },\n\n vite: {\n configResolved(config) {\n ROOT = config.root\n initUserConfig()\n\n // Validate plugin order - router must come before JSX transformation plugins\n const routerPluginIndex = config.plugins.findIndex(\n (p) => p.name === CODE_SPLITTER_PLUGIN_NAME,\n )\n\n if (routerPluginIndex === -1) return\n\n const frameworkPlugins =\n TRANSFORMATION_PLUGINS_BY_FRAMEWORK[userConfig.target]\n if (!frameworkPlugins) return\n\n for (const transformPlugin of frameworkPlugins) {\n const transformPluginIndex = config.plugins.findIndex((p) =>\n transformPlugin.pluginNames.includes(p.name),\n )\n\n if (\n transformPluginIndex !== -1 &&\n transformPluginIndex < routerPluginIndex\n ) {\n throw new Error(\n `Plugin order error: '${transformPlugin.pkg}' is placed before '@tanstack/router-plugin'.\\n\\n` +\n `The TanStack Router plugin must come BEFORE JSX transformation plugins.\\n\\n` +\n `Please update your Vite config:\\n\\n` +\n ` plugins: [\\n` +\n ` tanstackRouter(),\\n` +\n ` ${transformPlugin.usage},\\n` +\n ` ]\\n`,\n )\n }\n }\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n\n rspack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n\n webpack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-virtual-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-split/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n return handleCompilingVirtualFile(code, normalizedId)\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-shared-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-shared/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n const [baseId] = normalizedId.split('?')\n\n if (!baseId) return null\n\n const sharedBindings = sharedBindingsMap.get(baseId)\n if (!sharedBindings || sharedBindings.size === 0) return null\n\n if (debug) console.info('Compiling Shared Module: ', id)\n\n const result = compileCodeSplitSharedRoute({\n code,\n sharedBindings,\n filename: normalizedId,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n ]\n}\n\nexport const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}) => {\n return createRouterCodeSplitterPlugin(options, createRouterPluginContext())\n}\n"],"mappings":"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"}
@@ -11,11 +11,6 @@ let _tanstack_router_utils = require("@tanstack/router-utils");
11
11
  * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin
12
12
  * handles HMR for code-split routes itself.
13
13
  */
14
- var includeCode = [
15
- "createFileRoute(",
16
- "createRootRoute(",
17
- "createRootRouteWithContext("
18
- ];
19
14
  function createRouterHmrPlugin(options = {}, routerPluginContext) {
20
15
  let ROOT = process.cwd();
21
16
  const resolveUserConfig = () => {
@@ -28,7 +23,7 @@ function createRouterHmrPlugin(options = {}, routerPluginContext) {
28
23
  transform: {
29
24
  filter: {
30
25
  id: /\.(m|c)?(j|t)sx?$/,
31
- code: { include: includeCode }
26
+ code: { include: require_utils.routeFactoryCallCodeFilter }
32
27
  },
33
28
  handler(code, id) {
34
29
  const normalizedId = require_utils.normalizePath(id);
@@ -1 +1 @@
1
- {"version":3,"file":"router-hmr-plugin.cjs","names":[],"sources":["../../../src/core/router-hmr-plugin.ts"],"sourcesContent":["import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'\nimport { compileCodeSplitReferenceRoute } from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport { createRouteHmrStatement } from './hmr'\nimport { debug, normalizePath } from './utils'\nimport { getConfig } from './config'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\n\n/**\n * This plugin adds HMR support for file routes.\n * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin\n * handles HMR for code-split routes itself.\n */\n\nconst includeCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n]\n\nexport function createRouterHmrPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config> | undefined>> {\n let ROOT: string = process.cwd()\n\n const resolveUserConfig = () => {\n return getConfig(typeof options === 'function' ? options() : options, ROOT)\n }\n\n let userConfig = resolveUserConfig()\n\n return {\n name: 'tanstack-router:hmr',\n enforce: 'pre',\n transform: {\n filter: {\n // this is necessary for webpack / rspack to avoid matching .html files\n id: /\\.(m|c)?(j|t)sx?$/,\n code: {\n include: includeCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const routeEntry = routerPluginContext.routesByFile.get(normalizedId)\n if (!routeEntry) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n if (userConfig.target === 'react') {\n const compilerPlugins = getReferenceRouteCompilerPlugins({\n targetFramework: 'react',\n addHmr: true,\n hmrStyle,\n })\n const compiled = compileCodeSplitReferenceRoute({\n code,\n filename: normalizedId,\n id: normalizedId,\n addHmr: true,\n hmrStyle,\n hmrRouteId: routeEntry.routeId,\n codeSplitGroupings: [],\n targetFramework: 'react',\n compilerPlugins,\n })\n\n if (compiled) {\n if (debug) {\n logDiff(code, compiled.code)\n console.log('Output:\\n', compiled.code + '\\n\\n')\n }\n\n return compiled\n }\n }\n\n const ast = parseAst({ code, filename: normalizedId })\n ast.program.body.push(\n ...createRouteHmrStatement([], {\n hmrStyle,\n targetFramework: userConfig.target,\n routeId: routeEntry.routeId,\n }),\n )\n const result = generateFromAst(ast, {\n sourceMaps: true,\n filename: normalizedId,\n sourceFileName: normalizedId,\n })\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n return result\n },\n },\n vite: {\n configResolved(config) {\n ROOT = config.root\n userConfig = resolveUserConfig()\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n }\n}\n\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n return createRouterHmrPlugin(options, createRouterPluginContext())\n}\n"],"mappings":";;;;;;;;;;;;;AAiBA,IAAM,cAAc;CAClB;CACA;CACA;CACD;AAED,SAAgB,sBACd,UAAwD,EAAE,EAC1D,qBAC0D;CAC1D,IAAI,OAAe,QAAQ,KAAK;CAEhC,MAAM,0BAA0B;AAC9B,SAAO,eAAA,UAAU,OAAO,YAAY,aAAa,SAAS,GAAG,SAAS,KAAK;;CAG7E,IAAI,aAAa,mBAAmB;AAEpC,QAAO;EACL,MAAM;EACN,SAAS;EACT,WAAW;GACT,QAAQ;IAEN,IAAI;IACJ,MAAM,EACJ,SAAS,aACV;IACF;GACD,QAAQ,MAAM,IAAI;IAChB,MAAM,eAAe,cAAA,cAAc,GAAG;IACtC,MAAM,aAAa,oBAAoB,aAAa,IAAI,aAAa;AACrE,QAAI,CAAC,WACH,QAAO;AAGT,QAAI,cAAA,MAAO,SAAQ,KAAK,iCAAiC,aAAa;IAEtE,MAAM,WAAW,WAAW,QAAQ,KAAK,SAAS;AAElD,QAAI,WAAW,WAAW,SAAS;KACjC,MAAM,kBAAkB,0BAAA,iCAAiC;MACvD,iBAAiB;MACjB,QAAQ;MACR;MACD,CAAC;KACF,MAAM,WAAW,kBAAA,+BAA+B;MAC9C;MACA,UAAU;MACV,IAAI;MACJ,QAAQ;MACR;MACA,YAAY,WAAW;MACvB,oBAAoB,EAAE;MACtB,iBAAiB;MACjB;MACD,CAAC;AAEF,SAAI,UAAU;AACZ,UAAI,cAAA,OAAO;AACT,QAAA,GAAA,uBAAA,SAAQ,MAAM,SAAS,KAAK;AAC5B,eAAQ,IAAI,aAAa,SAAS,OAAO,OAAO;;AAGlD,aAAO;;;IAIX,MAAM,OAAA,GAAA,uBAAA,UAAe;KAAE;KAAM,UAAU;KAAc,CAAC;AACtD,QAAI,QAAQ,KAAK,KACf,GAAG,uBAAA,wBAAwB,EAAE,EAAE;KAC7B;KACA,iBAAiB,WAAW;KAC5B,SAAS,WAAW;KACrB,CAAC,CACH;IACD,MAAM,UAAA,GAAA,uBAAA,iBAAyB,KAAK;KAClC,YAAY;KACZ,UAAU;KACV,gBAAgB;KACjB,CAAC;AACF,QAAI,cAAA,OAAO;AACT,MAAA,GAAA,uBAAA,SAAQ,MAAM,OAAO,KAAK;AAC1B,aAAQ,IAAI,aAAa,OAAO,OAAO,OAAO;;AAEhD,WAAO;;GAEV;EACD,MAAM;GACJ,eAAe,QAAQ;AACrB,WAAO,OAAO;AACd,iBAAa,mBAAmB;;GAElC,mBAAmB,aAAa;AAC9B,QAAI,WAAW,QAAQ,MAAM,gBAC3B,QAAO,WAAW,OAAO,KAAK,oBAAoB,YAAY;AAEhE,WAAO;;GAEV;EACF"}
1
+ {"version":3,"file":"router-hmr-plugin.cjs","names":[],"sources":["../../../src/core/router-hmr-plugin.ts"],"sourcesContent":["import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'\nimport { compileCodeSplitReferenceRoute } from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport { createRouteHmrStatement } from './hmr'\nimport { debug, normalizePath, routeFactoryCallCodeFilter } from './utils'\nimport { getConfig } from './config'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\n\n/**\n * This plugin adds HMR support for file routes.\n * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin\n * handles HMR for code-split routes itself.\n */\n\nexport function createRouterHmrPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config> | undefined>> {\n let ROOT: string = process.cwd()\n\n const resolveUserConfig = () => {\n return getConfig(typeof options === 'function' ? options() : options, ROOT)\n }\n\n let userConfig = resolveUserConfig()\n\n return {\n name: 'tanstack-router:hmr',\n enforce: 'pre',\n transform: {\n filter: {\n // this is necessary for webpack / rspack to avoid matching .html files\n id: /\\.(m|c)?(j|t)sx?$/,\n code: {\n include: routeFactoryCallCodeFilter,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const routeEntry = routerPluginContext.routesByFile.get(normalizedId)\n if (!routeEntry) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n if (userConfig.target === 'react') {\n const compilerPlugins = getReferenceRouteCompilerPlugins({\n targetFramework: 'react',\n addHmr: true,\n hmrStyle,\n })\n const compiled = compileCodeSplitReferenceRoute({\n code,\n filename: normalizedId,\n id: normalizedId,\n addHmr: true,\n hmrStyle,\n hmrRouteId: routeEntry.routeId,\n codeSplitGroupings: [],\n targetFramework: 'react',\n compilerPlugins,\n })\n\n if (compiled) {\n if (debug) {\n logDiff(code, compiled.code)\n console.log('Output:\\n', compiled.code + '\\n\\n')\n }\n\n return compiled\n }\n }\n\n const ast = parseAst({ code, filename: normalizedId })\n ast.program.body.push(\n ...createRouteHmrStatement([], {\n hmrStyle,\n targetFramework: userConfig.target,\n routeId: routeEntry.routeId,\n }),\n )\n const result = generateFromAst(ast, {\n sourceMaps: true,\n filename: normalizedId,\n sourceFileName: normalizedId,\n })\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n return result\n },\n },\n vite: {\n configResolved(config) {\n ROOT = config.root\n userConfig = resolveUserConfig()\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n }\n}\n\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n return createRouterHmrPlugin(options, createRouterPluginContext())\n}\n"],"mappings":";;;;;;;;;;;;;AAiBA,SAAgB,sBACd,UAAwD,EAAE,EAC1D,qBAC0D;CAC1D,IAAI,OAAe,QAAQ,KAAK;CAEhC,MAAM,0BAA0B;AAC9B,SAAO,eAAA,UAAU,OAAO,YAAY,aAAa,SAAS,GAAG,SAAS,KAAK;;CAG7E,IAAI,aAAa,mBAAmB;AAEpC,QAAO;EACL,MAAM;EACN,SAAS;EACT,WAAW;GACT,QAAQ;IAEN,IAAI;IACJ,MAAM,EACJ,SAAS,cAAA,4BACV;IACF;GACD,QAAQ,MAAM,IAAI;IAChB,MAAM,eAAe,cAAA,cAAc,GAAG;IACtC,MAAM,aAAa,oBAAoB,aAAa,IAAI,aAAa;AACrE,QAAI,CAAC,WACH,QAAO;AAGT,QAAI,cAAA,MAAO,SAAQ,KAAK,iCAAiC,aAAa;IAEtE,MAAM,WAAW,WAAW,QAAQ,KAAK,SAAS;AAElD,QAAI,WAAW,WAAW,SAAS;KACjC,MAAM,kBAAkB,0BAAA,iCAAiC;MACvD,iBAAiB;MACjB,QAAQ;MACR;MACD,CAAC;KACF,MAAM,WAAW,kBAAA,+BAA+B;MAC9C;MACA,UAAU;MACV,IAAI;MACJ,QAAQ;MACR;MACA,YAAY,WAAW;MACvB,oBAAoB,EAAE;MACtB,iBAAiB;MACjB;MACD,CAAC;AAEF,SAAI,UAAU;AACZ,UAAI,cAAA,OAAO;AACT,QAAA,GAAA,uBAAA,SAAQ,MAAM,SAAS,KAAK;AAC5B,eAAQ,IAAI,aAAa,SAAS,OAAO,OAAO;;AAGlD,aAAO;;;IAIX,MAAM,OAAA,GAAA,uBAAA,UAAe;KAAE;KAAM,UAAU;KAAc,CAAC;AACtD,QAAI,QAAQ,KAAK,KACf,GAAG,uBAAA,wBAAwB,EAAE,EAAE;KAC7B;KACA,iBAAiB,WAAW;KAC5B,SAAS,WAAW;KACrB,CAAC,CACH;IACD,MAAM,UAAA,GAAA,uBAAA,iBAAyB,KAAK;KAClC,YAAY;KACZ,UAAU;KACV,gBAAgB;KACjB,CAAC;AACF,QAAI,cAAA,OAAO;AACT,MAAA,GAAA,uBAAA,SAAQ,MAAM,OAAO,KAAK;AAC1B,aAAQ,IAAI,aAAa,OAAO,OAAO,OAAO;;AAEhD,WAAO;;GAEV;EACD,MAAM;GACJ,eAAe,QAAQ;AACrB,WAAO,OAAO;AACd,iBAAa,mBAAmB;;GAElC,mBAAmB,aAAa;AAC9B,QAAI,WAAW,QAAQ,MAAM,gBAC3B,QAAO,WAAW,OAAO,KAAK,oBAAoB,YAAY;AAEhE,WAAO;;GAEV;EACF"}
@@ -1,5 +1,10 @@
1
1
  import { UnpluginFactory } from 'unplugin';
2
2
  import { Config } from './config.cjs';
3
3
  import { RouterPluginContext } from './router-plugin-context.cjs';
4
+ /**
5
+ * This plugin adds HMR support for file routes.
6
+ * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin
7
+ * handles HMR for code-split routes itself.
8
+ */
4
9
  export declare function createRouterHmrPlugin(options: Partial<Config | (() => Config)> | undefined, routerPluginContext: RouterPluginContext): ReturnType<UnpluginFactory<Partial<Config> | undefined>>;
5
10
  export declare const unpluginRouterHmrFactory: UnpluginFactory<Partial<Config> | undefined>;
@@ -13,6 +13,11 @@ var debug = process.env.TSR_VITE_DEBUG && ["true", "router-plugin"].includes(pro
13
13
  function normalizePath(path) {
14
14
  return path.replace(/\\/g, "/");
15
15
  }
16
+ var routeFactoryCallCodeFilter = [
17
+ /\bcreateFileRoute\s*\(/,
18
+ /\bcreateRootRoute\s*\(/,
19
+ /\bcreateRootRouteWithContext\s*(?:<|\()/
20
+ ];
16
21
  function getObjectPropertyKeyName(prop) {
17
22
  if (prop.computed) return;
18
23
  if (_babel_types.isIdentifier(prop.key)) return prop.key.name;
@@ -34,5 +39,6 @@ exports.debug = debug;
34
39
  exports.getObjectPropertyKeyName = getObjectPropertyKeyName;
35
40
  exports.getUniqueProgramIdentifier = getUniqueProgramIdentifier;
36
41
  exports.normalizePath = normalizePath;
42
+ exports.routeFactoryCallCodeFilter = routeFactoryCallCodeFilter;
37
43
 
38
44
  //# sourceMappingURL=utils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","names":[],"sources":["../../../src/core/utils.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport type babel from '@babel/core'\n\nexport const debug =\n process.env.TSR_VITE_DEBUG &&\n ['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG)\n\n/**\n * Normalizes a file path by converting Windows backslashes to forward slashes.\n * This ensures consistent path handling across different bundlers and operating systems.\n *\n * The route generator stores paths with forward slashes, but rspack/webpack on Windows\n * pass native paths with backslashes to transform handlers.\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\nexport function getObjectPropertyKeyName(\n prop: t.ObjectProperty,\n): string | undefined {\n if (prop.computed) {\n return undefined\n }\n\n if (t.isIdentifier(prop.key)) {\n return prop.key.name\n }\n\n if (t.isStringLiteral(prop.key)) {\n return prop.key.value\n }\n\n return undefined\n}\n\nexport function getUniqueProgramIdentifier(\n programPath: babel.NodePath<t.Program>,\n baseName: string,\n): t.Identifier {\n let name = baseName\n let suffix = 2\n\n const programScope = programPath.scope.getProgramParent()\n\n while (\n programScope.hasBinding(name) ||\n programScope.hasGlobal(name) ||\n programScope.hasReference(name)\n ) {\n name = `${baseName}${suffix}`\n suffix++\n }\n\n // Register the name so subsequent calls within the same traversal\n // see it and avoid collisions\n programScope.references[name] = true\n\n return t.identifier(name)\n}\n"],"mappings":";;;;AAGA,IAAa,QACX,QAAQ,IAAI,kBACZ,CAAC,QAAQ,gBAAgB,CAAC,SAAS,QAAQ,IAAI,eAAe;;;;;;;;AAShE,SAAgB,cAAc,MAAsB;AAClD,QAAO,KAAK,QAAQ,OAAO,IAAI;;AAGjC,SAAgB,yBACd,MACoB;AACpB,KAAI,KAAK,SACP;AAGF,KAAI,aAAE,aAAa,KAAK,IAAI,CAC1B,QAAO,KAAK,IAAI;AAGlB,KAAI,aAAE,gBAAgB,KAAK,IAAI,CAC7B,QAAO,KAAK,IAAI;;AAMpB,SAAgB,2BACd,aACA,UACc;CACd,IAAI,OAAO;CACX,IAAI,SAAS;CAEb,MAAM,eAAe,YAAY,MAAM,kBAAkB;AAEzD,QACE,aAAa,WAAW,KAAK,IAC7B,aAAa,UAAU,KAAK,IAC5B,aAAa,aAAa,KAAK,EAC/B;AACA,SAAO,GAAG,WAAW;AACrB;;AAKF,cAAa,WAAW,QAAQ;AAEhC,QAAO,aAAE,WAAW,KAAK"}
1
+ {"version":3,"file":"utils.cjs","names":[],"sources":["../../../src/core/utils.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport type babel from '@babel/core'\n\nexport const debug =\n process.env.TSR_VITE_DEBUG &&\n ['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG)\n\n/**\n * Normalizes a file path by converting Windows backslashes to forward slashes.\n * This ensures consistent path handling across different bundlers and operating systems.\n *\n * The route generator stores paths with forward slashes, but rspack/webpack on Windows\n * pass native paths with backslashes to transform handlers.\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\nexport const routeFactoryCallCodeFilter = [\n /\\bcreateFileRoute\\s*\\(/,\n /\\bcreateRootRoute\\s*\\(/,\n /\\bcreateRootRouteWithContext\\s*(?:<|\\()/,\n]\n\nexport function getObjectPropertyKeyName(\n prop: t.ObjectProperty,\n): string | undefined {\n if (prop.computed) {\n return undefined\n }\n\n if (t.isIdentifier(prop.key)) {\n return prop.key.name\n }\n\n if (t.isStringLiteral(prop.key)) {\n return prop.key.value\n }\n\n return undefined\n}\n\nexport function getUniqueProgramIdentifier(\n programPath: babel.NodePath<t.Program>,\n baseName: string,\n): t.Identifier {\n let name = baseName\n let suffix = 2\n\n const programScope = programPath.scope.getProgramParent()\n\n while (\n programScope.hasBinding(name) ||\n programScope.hasGlobal(name) ||\n programScope.hasReference(name)\n ) {\n name = `${baseName}${suffix}`\n suffix++\n }\n\n // Register the name so subsequent calls within the same traversal\n // see it and avoid collisions\n programScope.references[name] = true\n\n return t.identifier(name)\n}\n"],"mappings":";;;;AAGA,IAAa,QACX,QAAQ,IAAI,kBACZ,CAAC,QAAQ,gBAAgB,CAAC,SAAS,QAAQ,IAAI,eAAe;;;;;;;;AAShE,SAAgB,cAAc,MAAsB;AAClD,QAAO,KAAK,QAAQ,OAAO,IAAI;;AAGjC,IAAa,6BAA6B;CACxC;CACA;CACA;CACD;AAED,SAAgB,yBACd,MACoB;AACpB,KAAI,KAAK,SACP;AAGF,KAAI,aAAE,aAAa,KAAK,IAAI,CAC1B,QAAO,KAAK,IAAI;AAGlB,KAAI,aAAE,gBAAgB,KAAK,IAAI,CAC7B,QAAO,KAAK,IAAI;;AAMpB,SAAgB,2BACd,aACA,UACc;CACd,IAAI,OAAO;CACX,IAAI,SAAS;CAEb,MAAM,eAAe,YAAY,MAAM,kBAAkB;AAEzD,QACE,aAAa,WAAW,KAAK,IAC7B,aAAa,UAAU,KAAK,IAC5B,aAAa,aAAa,KAAK,EAC/B;AACA,SAAO,GAAG,WAAW;AACrB;;AAKF,cAAa,WAAW,QAAQ;AAEhC,QAAO,aAAE,WAAW,KAAK"}
@@ -9,5 +9,6 @@ export declare const debug: boolean | "" | undefined;
9
9
  * pass native paths with backslashes to transform handlers.
10
10
  */
11
11
  export declare function normalizePath(path: string): string;
12
+ export declare const routeFactoryCallCodeFilter: RegExp[];
12
13
  export declare function getObjectPropertyKeyName(prop: t.ObjectProperty): string | undefined;
13
14
  export declare function getUniqueProgramIdentifier(programPath: babel.NodePath<t.Program>, baseName: string): t.Identifier;
@@ -5,7 +5,7 @@ import * as template from "@babel/template";
5
5
  var buildReactRefreshIgnoredRouteExportsStatements = template.statements(`
6
6
  const hot = import.meta.hot
7
7
  if (hot && typeof window !== 'undefined') {
8
- ;(hot.data ??= {})
8
+ hot.data ??= {}
9
9
  const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {
10
10
  const ignoredExportsById = new Map()
11
11
  const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports
@@ -1 +1 @@
1
- {"version":3,"file":"react-refresh-ignored-route-exports.js","names":[],"sources":["../../../../../src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport * as t from '@babel/types'\nimport { getUniqueProgramIdentifier } from '../../utils'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\n\nconst buildReactRefreshIgnoredRouteExportsStatements = template.statements(\n `\nconst hot = import.meta.hot\nif (hot && typeof window !== 'undefined') {\n ;(hot.data ??= {})\n const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {\n const ignoredExportsById = new Map()\n const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports\n\n window.__getReactRefreshIgnoredExports = (ctx) => {\n const ignoredExports = previousGetIgnoredExports?.(ctx) ?? []\n const moduleIgnored = ignoredExportsById.get(ctx.id) ?? []\n return [...ignoredExports, ...moduleIgnored]\n }\n\n return {\n ignoredExportsById,\n }\n })()\n\n tsrReactRefresh.ignoredExportsById.set(%%moduleId%%, ['Route'])\n}\n`,\n { syntacticPlaceholders: true },\n)\n\n/**\n * A trivial component-shaped export that gives `@vitejs/plugin-react` a valid\n * Fast Refresh boundary. Without at least one non-ignored component export,\n * the module would be invalidated (full page reload) on every update even\n * though our custom route HMR handler already manages the update.\n */\nconst buildRefreshAnchorStatement = template.statement(\n `export function %%anchorName%%() { return null }`,\n { syntacticPlaceholders: true },\n)\n\nexport function createReactRefreshIgnoredRouteExportsPlugin(): ReferenceRouteCompilerPlugin {\n return {\n name: 'react-refresh-ignored-route-exports',\n onAddHmr(ctx) {\n const anchorName = getUniqueProgramIdentifier(\n ctx.programPath,\n 'TSRFastRefreshAnchor',\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildReactRefreshIgnoredRouteExportsStatements({\n moduleId: t.stringLiteral(ctx.opts.id),\n }),\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildRefreshAnchorStatement({ anchorName }),\n )\n\n return { modified: true }\n },\n }\n}\n"],"mappings":";;;;AAKA,IAAM,iDAAiD,SAAS,WAC9D;;;;;;;;;;;;;;;;;;;;;GAsBA,EAAE,uBAAuB,MAAM,CAChC;;;;;;;AAQD,IAAM,8BAA8B,SAAS,UAC3C,oDACA,EAAE,uBAAuB,MAAM,CAChC;AAED,SAAgB,8CAA4E;AAC1F,QAAO;EACL,MAAM;EACN,SAAS,KAAK;GACZ,MAAM,aAAa,2BACjB,IAAI,aACJ,uBACD;AAED,OAAI,YAAY,cACd,QACA,+CAA+C,EAC7C,UAAU,EAAE,cAAc,IAAI,KAAK,GAAG,EACvC,CAAC,CACH;AAED,OAAI,YAAY,cACd,QACA,4BAA4B,EAAE,YAAY,CAAC,CAC5C;AAED,UAAO,EAAE,UAAU,MAAM;;EAE5B"}
1
+ {"version":3,"file":"react-refresh-ignored-route-exports.js","names":[],"sources":["../../../../../src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport * as t from '@babel/types'\nimport { getUniqueProgramIdentifier } from '../../utils'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\n\nconst buildReactRefreshIgnoredRouteExportsStatements = template.statements(\n `\nconst hot = import.meta.hot\nif (hot && typeof window !== 'undefined') {\n hot.data ??= {}\n const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {\n const ignoredExportsById = new Map()\n const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports\n\n window.__getReactRefreshIgnoredExports = (ctx) => {\n const ignoredExports = previousGetIgnoredExports?.(ctx) ?? []\n const moduleIgnored = ignoredExportsById.get(ctx.id) ?? []\n return [...ignoredExports, ...moduleIgnored]\n }\n\n return {\n ignoredExportsById,\n }\n })()\n\n tsrReactRefresh.ignoredExportsById.set(%%moduleId%%, ['Route'])\n}\n`,\n { syntacticPlaceholders: true },\n)\n\n/**\n * A trivial component-shaped export that gives `@vitejs/plugin-react` a valid\n * Fast Refresh boundary. Without at least one non-ignored component export,\n * the module would be invalidated (full page reload) on every update even\n * though our custom route HMR handler already manages the update.\n */\nconst buildRefreshAnchorStatement = template.statement(\n `export function %%anchorName%%() { return null }`,\n { syntacticPlaceholders: true },\n)\n\nexport function createReactRefreshIgnoredRouteExportsPlugin(): ReferenceRouteCompilerPlugin {\n return {\n name: 'react-refresh-ignored-route-exports',\n onAddHmr(ctx) {\n const anchorName = getUniqueProgramIdentifier(\n ctx.programPath,\n 'TSRFastRefreshAnchor',\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildReactRefreshIgnoredRouteExportsStatements({\n moduleId: t.stringLiteral(ctx.opts.id),\n }),\n )\n\n ctx.programPath.pushContainer(\n 'body',\n buildRefreshAnchorStatement({ anchorName }),\n )\n\n return { modified: true }\n },\n }\n}\n"],"mappings":";;;;AAKA,IAAM,iDAAiD,SAAS,WAC9D;;;;;;;;;;;;;;;;;;;;;GAsBA,EAAE,uBAAuB,MAAM,CAChC;;;;;;;AAQD,IAAM,8BAA8B,SAAS,UAC3C,oDACA,EAAE,uBAAuB,MAAM,CAChC;AAED,SAAgB,8CAA4E;AAC1F,QAAO;EACL,MAAM;EACN,SAAS,KAAK;GACZ,MAAM,aAAa,2BACjB,IAAI,aACJ,uBACD;AAED,OAAI,YAAY,cACd,QACA,+CAA+C,EAC7C,UAAU,EAAE,cAAc,IAAI,KAAK,GAAG,EACvC,CAAC,CACH;AAED,OAAI,YAAY,cACd,QACA,4BAA4B,EAAE,YAAY,CAAC,CAC5C;AAED,UAAO,EAAE,UAAU,MAAM;;EAE5B"}
@@ -3,9 +3,18 @@ function handleRouteUpdate(routeId, newRoute) {
3
3
  const router = window.__TSR_ROUTER__;
4
4
  const oldRoute = router.routesById[routeId];
5
5
  if (!oldRoute) return;
6
+ const generatedRouteOptionKeys = new Set([
7
+ "id",
8
+ "path",
9
+ "getParentRoute"
10
+ ]);
11
+ const generatedRouteOptions = {};
12
+ generatedRouteOptionKeys.forEach((key) => {
13
+ if (key in oldRoute.options) generatedRouteOptions[key] = oldRoute.options[key];
14
+ });
6
15
  const removedKeys = /* @__PURE__ */ new Set();
7
16
  Object.keys(oldRoute.options).forEach((key) => {
8
- if (!(key in newRoute.options)) {
17
+ if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {
9
18
  removedKeys.add(key);
10
19
  delete oldRoute.options[key];
11
20
  }
@@ -15,17 +24,16 @@ function handleRouteUpdate(routeId, newRoute) {
15
24
  if (preserveComponentIdentity) componentKeys.forEach((key) => {
16
25
  if (key in oldRoute.options && key in newRoute.options) newRoute.options[key] = oldRoute.options[key];
17
26
  });
18
- oldRoute.options = newRoute.options;
19
- oldRoute.update(newRoute.options);
27
+ const nextOptions = {
28
+ ...newRoute.options,
29
+ ...generatedRouteOptions
30
+ };
31
+ oldRoute.options = nextOptions;
32
+ oldRoute.update(nextOptions);
20
33
  oldRoute._componentsPromise = void 0;
21
34
  oldRoute._lazyPromise = void 0;
22
- router.routesById[oldRoute.id] = oldRoute;
23
- router.routesByPath[oldRoute.fullPath] = oldRoute;
24
- router.processedTree.matchCache.clear();
25
- router.processedTree.flatCache?.clear();
26
- router.processedTree.singleCache.clear();
35
+ router.setRoutes(router.buildRouteTree());
27
36
  router.resolvePathCache.clear();
28
- walkReplaceSegmentTree(oldRoute, router.processedTree.segmentTree);
29
37
  const filter = (m) => m.routeId === oldRoute.id;
30
38
  const activeMatch = router.stores.matches.get().find(filter);
31
39
  const pendingMatch = router.stores.pendingMatches.get().find(filter);
@@ -57,15 +65,6 @@ function handleRouteUpdate(routeId, newRoute) {
57
65
  sync: true
58
66
  });
59
67
  }
60
- function walkReplaceSegmentTree(route, node) {
61
- if (node.route?.id === route.id) node.route = route;
62
- if (node.index) walkReplaceSegmentTree(route, node.index);
63
- node.static?.forEach((child) => walkReplaceSegmentTree(route, child));
64
- node.staticInsensitive?.forEach((child) => walkReplaceSegmentTree(route, child));
65
- node.dynamic?.forEach((child) => walkReplaceSegmentTree(route, child));
66
- node.optional?.forEach((child) => walkReplaceSegmentTree(route, child));
67
- node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child));
68
- }
69
68
  function getStoreMatch(matchId) {
70
69
  return router.stores.pendingMatchStores.get(matchId)?.get() || router.stores.matchStores.get(matchId)?.get() || router.stores.cachedMatchStores.get(matchId)?.get();
71
70
  }
@@ -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 _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 routesByPath: Record<string, AnyRoute>\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 // 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 const removedKeys = new Set<string>()\n Object.keys(oldRoute.options).forEach((key) => {\n if (!(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 // 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 oldRoute.options = newRoute.options\n oldRoute.update(newRoute.options)\n oldRoute._componentsPromise = undefined\n oldRoute._lazyPromise = undefined\n\n router.routesById[oldRoute.id] = oldRoute\n router.routesByPath[oldRoute.fullPath] = oldRoute\n\n router.processedTree.matchCache.clear()\n router.processedTree.flatCache?.clear()\n router.processedTree.singleCache.clear()\n router.resolvePathCache.clear()\n walkReplaceSegmentTree(oldRoute, router.processedTree.segmentTree)\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 walkReplaceSegmentTree(\n route: AnyRouteWithPrivateProps,\n node: AnyRouter['processedTree']['segmentTree'],\n ) {\n if (node.route?.id === route.id) node.route = route\n if (node.index) walkReplaceSegmentTree(route, node.index)\n node.static?.forEach((child) => walkReplaceSegmentTree(route, child))\n node.staticInsensitive?.forEach((child) =>\n walkReplaceSegmentTree(route, child),\n )\n node.dynamic?.forEach((child) => walkReplaceSegmentTree(route, child))\n node.optional?.forEach((child) => walkReplaceSegmentTree(route, child))\n node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child))\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 {\n AnyRoute,\n AnyRouteMatch,\n AnyRouter,\n RouterWritableStore,\n} from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n options: Record<string, unknown>\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 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 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,6 +1,6 @@
1
1
  import { getConfig, splitGroupingsSchema } from "./config.js";
2
2
  import { defaultCodeSplitGroupings, splitRouteIdentNodes, tsrShared, tsrSplit } from "./constants.js";
3
- import { debug, normalizePath } from "./utils.js";
3
+ import { debug, normalizePath, routeFactoryCallCodeFilter } from "./utils.js";
4
4
  import { decodeIdentifier } from "./code-splitter/path-ids.js";
5
5
  import { compileCodeSplitReferenceRoute, compileCodeSplitSharedRoute, compileCodeSplitVirtualRoute, computeSharedBindings, detectCodeSplitGroupingsFromRoute } from "./code-splitter/compilers.js";
6
6
  import { getReferenceRouteCompilerPlugins } from "./code-splitter/plugins/framework-plugins.js";
@@ -134,11 +134,6 @@ function createRouterCodeSplitterPlugin(options = {}, routerPluginContext) {
134
134
  }
135
135
  return result;
136
136
  };
137
- const includedCode = [
138
- "createFileRoute(",
139
- "createRootRoute(",
140
- "createRootRouteWithContext("
141
- ];
142
137
  return [
143
138
  {
144
139
  name: "tanstack-router:code-splitter:compile-reference-file",
@@ -149,12 +144,12 @@ function createRouterCodeSplitterPlugin(options = {}, routerPluginContext) {
149
144
  exclude: [tsrSplit, tsrShared],
150
145
  include: /\.(m|c)?(j|t)sx?$/
151
146
  },
152
- code: { include: includedCode }
147
+ code: { include: routeFactoryCallCodeFilter }
153
148
  },
154
149
  handler(code, id) {
155
150
  const normalizedId = normalizePath(id);
156
151
  const generatorFileInfo = routerPluginContext.routesByFile.get(normalizedId);
157
- if (generatorFileInfo && includedCode.some((included) => code.includes(included))) return handleCompilingReferenceFile(code, normalizedId, generatorFileInfo);
152
+ if (generatorFileInfo) return handleCompilingReferenceFile(code, normalizedId, generatorFileInfo);
158
153
  return null;
159
154
  }
160
155
  },
@@ -1 +1 @@
1
- {"version":3,"file":"router-code-splitter-plugin.js","names":[],"sources":["../../../src/core/router-code-splitter-plugin.ts"],"sourcesContent":["/**\n * It is important to familiarize yourself with how the code-splitting works in this plugin.\n * https://github.com/TanStack/router/pull/3355\n */\n\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { logDiff } from '@tanstack/router-utils'\nimport { getConfig, splitGroupingsSchema } from './config'\nimport {\n compileCodeSplitReferenceRoute,\n compileCodeSplitSharedRoute,\n compileCodeSplitVirtualRoute,\n computeSharedBindings,\n detectCodeSplitGroupingsFromRoute,\n} from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport {\n defaultCodeSplitGroupings,\n splitRouteIdentNodes,\n tsrShared,\n tsrSplit,\n} from './constants'\nimport { decodeIdentifier } from './code-splitter/path-ids'\nimport { debug, normalizePath } from './utils'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst CODE_SPLITTER_PLUGIN_NAME =\n 'tanstack-router:code-splitter:compile-reference-file'\n\ntype TransformationPluginInfo = {\n pluginNames: Array<string>\n pkg: string\n usage: string\n}\n\n/**\n * JSX transformation plugins grouped by framework.\n * These plugins must come AFTER the TanStack Router plugin in the Vite config.\n */\nconst TRANSFORMATION_PLUGINS_BY_FRAMEWORK: Record<\n string,\n Array<TransformationPluginInfo>\n> = {\n react: [\n {\n // Babel-based React plugin\n pluginNames: ['vite:react-babel', 'vite:react-refresh'],\n pkg: '@vitejs/plugin-react',\n usage: 'react()',\n },\n {\n // SWC-based React plugin\n pluginNames: ['vite:react-swc', 'vite:react-swc:resolve-runtime'],\n pkg: '@vitejs/plugin-react-swc',\n usage: 'reactSwc()',\n },\n {\n // OXC-based React plugin (deprecated but should still be handled)\n pluginNames: ['vite:react-oxc:config', 'vite:react-oxc:refresh-runtime'],\n pkg: '@vitejs/plugin-react-oxc',\n usage: 'reactOxc()',\n },\n ],\n solid: [\n {\n pluginNames: ['solid'],\n pkg: 'vite-plugin-solid',\n usage: 'solid()',\n },\n ],\n}\n\nexport function createRouterCodeSplitterPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config | (() => Config)> | undefined>> {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n function initUserConfig() {\n if (typeof options === 'function') {\n userConfig = options()\n } else {\n userConfig = getConfig(options, ROOT)\n }\n }\n const isProduction = process.env.NODE_ENV === 'production'\n // Map from normalized route file path → set of shared binding names.\n // Populated by the reference compiler, consumed by virtual and shared compilers.\n const sharedBindingsMap = new Map<string, Set<string>>()\n\n const getGlobalCodeSplitGroupings = () => {\n return (\n userConfig.codeSplittingOptions?.defaultBehavior ||\n defaultCodeSplitGroupings\n )\n }\n const getShouldSplitFn = () => {\n return userConfig.codeSplittingOptions?.splitBehavior\n }\n\n const handleCompilingReferenceFile = (\n code: string,\n id: string,\n generatorNodeInfo: GetRoutesByFileMapResultValue,\n ): UnpluginTransformResult => {\n if (debug) console.info('Compiling Route: ', id)\n\n const fromCode = detectCodeSplitGroupingsFromRoute({\n code,\n filename: id,\n })\n\n if (fromCode.groupings !== undefined) {\n const res = splitGroupingsSchema.safeParse(fromCode.groupings)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const userShouldSplitFn = getShouldSplitFn()\n\n const pluginSplitBehavior = userShouldSplitFn?.({\n routeId: generatorNodeInfo.routeId,\n }) as CodeSplitGroupings | undefined\n\n if (pluginSplitBehavior) {\n const res = splitGroupingsSchema.safeParse(pluginSplitBehavior)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings returned when using \\`splitBehavior\\` for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const splitGroupings: CodeSplitGroupings =\n fromCode.groupings ?? pluginSplitBehavior ?? getGlobalCodeSplitGroupings()\n\n // Compute shared bindings before compiling the reference route\n const sharedBindings = computeSharedBindings({\n code,\n filename: id,\n codeSplitGroupings: splitGroupings,\n })\n if (sharedBindings.size > 0) {\n sharedBindingsMap.set(id, sharedBindings)\n } else {\n sharedBindingsMap.delete(id)\n }\n\n const addHmr =\n (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n const compiledReferenceRoute = compileCodeSplitReferenceRoute({\n code,\n codeSplitGroupings: splitGroupings,\n targetFramework: userConfig.target,\n filename: id,\n id,\n deleteNodes: userConfig.codeSplittingOptions?.deleteNodes\n ? new Set(userConfig.codeSplittingOptions.deleteNodes)\n : undefined,\n addHmr,\n hmrStyle,\n hmrRouteId: generatorNodeInfo.routeId,\n sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: userConfig.target,\n addHmr,\n hmrStyle,\n }),\n })\n\n if (compiledReferenceRoute === null) {\n if (debug) {\n console.info(\n `No changes made to route \"${id}\", skipping code-splitting.`,\n )\n }\n return null\n }\n if (debug) {\n logDiff(code, compiledReferenceRoute.code)\n console.log('Output:\\n', compiledReferenceRoute.code + '\\n\\n')\n }\n\n return compiledReferenceRoute\n }\n\n const handleCompilingVirtualFile = (\n code: string,\n id: string,\n ): UnpluginTransformResult => {\n if (debug) console.info('Splitting Route: ', id)\n\n const [_, ...pathnameParts] = id.split('?')\n\n const searchParams = new URLSearchParams(pathnameParts.join('?'))\n const splitValue = searchParams.get(tsrSplit)\n\n if (!splitValue) {\n throw new Error(\n `The split value for the virtual route \"${id}\" was not found.`,\n )\n }\n\n const rawGrouping = decodeIdentifier(splitValue)\n const grouping = [...new Set(rawGrouping)].filter((p) =>\n splitRouteIdentNodes.includes(p as any),\n ) as Array<SplitRouteIdentNodes>\n\n const baseId = id.split('?')[0]!\n const resolvedSharedBindings = sharedBindingsMap.get(baseId)\n\n const result = compileCodeSplitVirtualRoute({\n code,\n filename: id,\n splitTargets: grouping,\n sharedBindings: resolvedSharedBindings,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n }\n\n const includedCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n ]\n return [\n {\n name: 'tanstack-router:code-splitter:compile-reference-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: {\n exclude: [tsrSplit, tsrShared],\n // this is necessary for webpack / rspack to avoid matching .html files\n include: /\\.(m|c)?(j|t)sx?$/,\n },\n code: {\n include: includedCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const generatorFileInfo =\n routerPluginContext.routesByFile.get(normalizedId)\n if (\n generatorFileInfo &&\n includedCode.some((included) => code.includes(included))\n ) {\n return handleCompilingReferenceFile(\n code,\n normalizedId,\n generatorFileInfo,\n )\n }\n\n return null\n },\n },\n\n vite: {\n configResolved(config) {\n ROOT = config.root\n initUserConfig()\n\n // Validate plugin order - router must come before JSX transformation plugins\n const routerPluginIndex = config.plugins.findIndex(\n (p) => p.name === CODE_SPLITTER_PLUGIN_NAME,\n )\n\n if (routerPluginIndex === -1) return\n\n const frameworkPlugins =\n TRANSFORMATION_PLUGINS_BY_FRAMEWORK[userConfig.target]\n if (!frameworkPlugins) return\n\n for (const transformPlugin of frameworkPlugins) {\n const transformPluginIndex = config.plugins.findIndex((p) =>\n transformPlugin.pluginNames.includes(p.name),\n )\n\n if (\n transformPluginIndex !== -1 &&\n transformPluginIndex < routerPluginIndex\n ) {\n throw new Error(\n `Plugin order error: '${transformPlugin.pkg}' is placed before '@tanstack/router-plugin'.\\n\\n` +\n `The TanStack Router plugin must come BEFORE JSX transformation plugins.\\n\\n` +\n `Please update your Vite config:\\n\\n` +\n ` plugins: [\\n` +\n ` tanstackRouter(),\\n` +\n ` ${transformPlugin.usage},\\n` +\n ` ]\\n`,\n )\n }\n }\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n\n rspack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n\n webpack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-virtual-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-split/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n return handleCompilingVirtualFile(code, normalizedId)\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-shared-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-shared/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n const [baseId] = normalizedId.split('?')\n\n if (!baseId) return null\n\n const sharedBindings = sharedBindingsMap.get(baseId)\n if (!sharedBindings || sharedBindings.size === 0) return null\n\n if (debug) console.info('Compiling Shared Module: ', id)\n\n const result = compileCodeSplitSharedRoute({\n code,\n sharedBindings,\n filename: normalizedId,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n ]\n}\n\nexport const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}) => {\n return createRouterCodeSplitterPlugin(options, createRouterPluginContext())\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"router-code-splitter-plugin.js","names":[],"sources":["../../../src/core/router-code-splitter-plugin.ts"],"sourcesContent":["/**\n * It is important to familiarize yourself with how the code-splitting works in this plugin.\n * https://github.com/TanStack/router/pull/3355\n */\n\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { logDiff } from '@tanstack/router-utils'\nimport { getConfig, splitGroupingsSchema } from './config'\nimport {\n compileCodeSplitReferenceRoute,\n compileCodeSplitSharedRoute,\n compileCodeSplitVirtualRoute,\n computeSharedBindings,\n detectCodeSplitGroupingsFromRoute,\n} from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport {\n defaultCodeSplitGroupings,\n splitRouteIdentNodes,\n tsrShared,\n tsrSplit,\n} from './constants'\nimport { decodeIdentifier } from './code-splitter/path-ids'\nimport { debug, normalizePath, routeFactoryCallCodeFilter } from './utils'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst CODE_SPLITTER_PLUGIN_NAME =\n 'tanstack-router:code-splitter:compile-reference-file'\n\ntype TransformationPluginInfo = {\n pluginNames: Array<string>\n pkg: string\n usage: string\n}\n\n/**\n * JSX transformation plugins grouped by framework.\n * These plugins must come AFTER the TanStack Router plugin in the Vite config.\n */\nconst TRANSFORMATION_PLUGINS_BY_FRAMEWORK: Record<\n string,\n Array<TransformationPluginInfo>\n> = {\n react: [\n {\n // Babel-based React plugin\n pluginNames: ['vite:react-babel', 'vite:react-refresh'],\n pkg: '@vitejs/plugin-react',\n usage: 'react()',\n },\n {\n // SWC-based React plugin\n pluginNames: ['vite:react-swc', 'vite:react-swc:resolve-runtime'],\n pkg: '@vitejs/plugin-react-swc',\n usage: 'reactSwc()',\n },\n {\n // OXC-based React plugin (deprecated but should still be handled)\n pluginNames: ['vite:react-oxc:config', 'vite:react-oxc:refresh-runtime'],\n pkg: '@vitejs/plugin-react-oxc',\n usage: 'reactOxc()',\n },\n ],\n solid: [\n {\n pluginNames: ['solid'],\n pkg: 'vite-plugin-solid',\n usage: 'solid()',\n },\n ],\n}\n\nexport function createRouterCodeSplitterPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config | (() => Config)> | undefined>> {\n let ROOT: string = process.cwd()\n let userConfig: Config\n\n function initUserConfig() {\n if (typeof options === 'function') {\n userConfig = options()\n } else {\n userConfig = getConfig(options, ROOT)\n }\n }\n const isProduction = process.env.NODE_ENV === 'production'\n // Map from normalized route file path → set of shared binding names.\n // Populated by the reference compiler, consumed by virtual and shared compilers.\n const sharedBindingsMap = new Map<string, Set<string>>()\n\n const getGlobalCodeSplitGroupings = () => {\n return (\n userConfig.codeSplittingOptions?.defaultBehavior ||\n defaultCodeSplitGroupings\n )\n }\n const getShouldSplitFn = () => {\n return userConfig.codeSplittingOptions?.splitBehavior\n }\n\n const handleCompilingReferenceFile = (\n code: string,\n id: string,\n generatorNodeInfo: GetRoutesByFileMapResultValue,\n ): UnpluginTransformResult => {\n if (debug) console.info('Compiling Route: ', id)\n\n const fromCode = detectCodeSplitGroupingsFromRoute({\n code,\n filename: id,\n })\n\n if (fromCode.groupings !== undefined) {\n const res = splitGroupingsSchema.safeParse(fromCode.groupings)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const userShouldSplitFn = getShouldSplitFn()\n\n const pluginSplitBehavior = userShouldSplitFn?.({\n routeId: generatorNodeInfo.routeId,\n }) as CodeSplitGroupings | undefined\n\n if (pluginSplitBehavior) {\n const res = splitGroupingsSchema.safeParse(pluginSplitBehavior)\n if (!res.success) {\n const message = res.error.errors.map((e) => e.message).join('. ')\n throw new Error(\n `The groupings returned when using \\`splitBehavior\\` for the route \"${id}\" are invalid.\\n${message}`,\n )\n }\n }\n\n const splitGroupings: CodeSplitGroupings =\n fromCode.groupings ?? pluginSplitBehavior ?? getGlobalCodeSplitGroupings()\n\n // Compute shared bindings before compiling the reference route\n const sharedBindings = computeSharedBindings({\n code,\n filename: id,\n codeSplitGroupings: splitGroupings,\n })\n if (sharedBindings.size > 0) {\n sharedBindingsMap.set(id, sharedBindings)\n } else {\n sharedBindingsMap.delete(id)\n }\n\n const addHmr =\n (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n const compiledReferenceRoute = compileCodeSplitReferenceRoute({\n code,\n codeSplitGroupings: splitGroupings,\n targetFramework: userConfig.target,\n filename: id,\n id,\n deleteNodes: userConfig.codeSplittingOptions?.deleteNodes\n ? new Set(userConfig.codeSplittingOptions.deleteNodes)\n : undefined,\n addHmr,\n hmrStyle,\n hmrRouteId: generatorNodeInfo.routeId,\n sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: userConfig.target,\n addHmr,\n hmrStyle,\n }),\n })\n\n if (compiledReferenceRoute === null) {\n if (debug) {\n console.info(\n `No changes made to route \"${id}\", skipping code-splitting.`,\n )\n }\n return null\n }\n if (debug) {\n logDiff(code, compiledReferenceRoute.code)\n console.log('Output:\\n', compiledReferenceRoute.code + '\\n\\n')\n }\n\n return compiledReferenceRoute\n }\n\n const handleCompilingVirtualFile = (\n code: string,\n id: string,\n ): UnpluginTransformResult => {\n if (debug) console.info('Splitting Route: ', id)\n\n const [_, ...pathnameParts] = id.split('?')\n\n const searchParams = new URLSearchParams(pathnameParts.join('?'))\n const splitValue = searchParams.get(tsrSplit)\n\n if (!splitValue) {\n throw new Error(\n `The split value for the virtual route \"${id}\" was not found.`,\n )\n }\n\n const rawGrouping = decodeIdentifier(splitValue)\n const grouping = [...new Set(rawGrouping)].filter((p) =>\n splitRouteIdentNodes.includes(p as any),\n ) as Array<SplitRouteIdentNodes>\n\n const baseId = id.split('?')[0]!\n const resolvedSharedBindings = sharedBindingsMap.get(baseId)\n\n const result = compileCodeSplitVirtualRoute({\n code,\n filename: id,\n splitTargets: grouping,\n sharedBindings: resolvedSharedBindings,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n }\n\n return [\n {\n name: 'tanstack-router:code-splitter:compile-reference-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: {\n exclude: [tsrSplit, tsrShared],\n // this is necessary for webpack / rspack to avoid matching .html files\n include: /\\.(m|c)?(j|t)sx?$/,\n },\n code: {\n include: routeFactoryCallCodeFilter,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const generatorFileInfo =\n routerPluginContext.routesByFile.get(normalizedId)\n if (generatorFileInfo) {\n return handleCompilingReferenceFile(\n code,\n normalizedId,\n generatorFileInfo,\n )\n }\n\n return null\n },\n },\n\n vite: {\n configResolved(config) {\n ROOT = config.root\n initUserConfig()\n\n // Validate plugin order - router must come before JSX transformation plugins\n const routerPluginIndex = config.plugins.findIndex(\n (p) => p.name === CODE_SPLITTER_PLUGIN_NAME,\n )\n\n if (routerPluginIndex === -1) return\n\n const frameworkPlugins =\n TRANSFORMATION_PLUGINS_BY_FRAMEWORK[userConfig.target]\n if (!frameworkPlugins) return\n\n for (const transformPlugin of frameworkPlugins) {\n const transformPluginIndex = config.plugins.findIndex((p) =>\n transformPlugin.pluginNames.includes(p.name),\n )\n\n if (\n transformPluginIndex !== -1 &&\n transformPluginIndex < routerPluginIndex\n ) {\n throw new Error(\n `Plugin order error: '${transformPlugin.pkg}' is placed before '@tanstack/router-plugin'.\\n\\n` +\n `The TanStack Router plugin must come BEFORE JSX transformation plugins.\\n\\n` +\n `Please update your Vite config:\\n\\n` +\n ` plugins: [\\n` +\n ` tanstackRouter(),\\n` +\n ` ${transformPlugin.usage},\\n` +\n ` ]\\n`,\n )\n }\n }\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n\n rspack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n\n webpack() {\n ROOT = process.cwd()\n initUserConfig()\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-virtual-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-split/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n return handleCompilingVirtualFile(code, normalizedId)\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n {\n name: 'tanstack-router:code-splitter:compile-shared-file',\n enforce: 'pre',\n\n transform: {\n filter: {\n id: /tsr-shared/,\n },\n handler(code, id) {\n const url = pathToFileURL(id)\n url.searchParams.delete('v')\n const normalizedId = normalizePath(fileURLToPath(url))\n const [baseId] = normalizedId.split('?')\n\n if (!baseId) return null\n\n const sharedBindings = sharedBindingsMap.get(baseId)\n if (!sharedBindings || sharedBindings.size === 0) return null\n\n if (debug) console.info('Compiling Shared Module: ', id)\n\n const result = compileCodeSplitSharedRoute({\n code,\n sharedBindings,\n filename: normalizedId,\n })\n\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n\n return result\n },\n },\n\n vite: {\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n },\n ]\n}\n\nexport const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}) => {\n return createRouterCodeSplitterPlugin(options, createRouterPluginContext())\n}\n"],"mappings":"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"}
@@ -1,5 +1,10 @@
1
1
  import { UnpluginFactory } from 'unplugin';
2
2
  import { Config } from './config.js';
3
3
  import { RouterPluginContext } from './router-plugin-context.js';
4
+ /**
5
+ * This plugin adds HMR support for file routes.
6
+ * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin
7
+ * handles HMR for code-split routes itself.
8
+ */
4
9
  export declare function createRouterHmrPlugin(options: Partial<Config | (() => Config)> | undefined, routerPluginContext: RouterPluginContext): ReturnType<UnpluginFactory<Partial<Config> | undefined>>;
5
10
  export declare const unpluginRouterHmrFactory: UnpluginFactory<Partial<Config> | undefined>;
@@ -1,6 +1,6 @@
1
1
  import { getConfig } from "./config.js";
2
2
  import { createRouteHmrStatement } from "./hmr/select-adapter.js";
3
- import { debug, normalizePath } from "./utils.js";
3
+ import { debug, normalizePath, routeFactoryCallCodeFilter } from "./utils.js";
4
4
  import { compileCodeSplitReferenceRoute } from "./code-splitter/compilers.js";
5
5
  import { getReferenceRouteCompilerPlugins } from "./code-splitter/plugins/framework-plugins.js";
6
6
  import { generateFromAst, logDiff, parseAst } from "@tanstack/router-utils";
@@ -10,11 +10,6 @@ import { generateFromAst, logDiff, parseAst } from "@tanstack/router-utils";
10
10
  * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin
11
11
  * handles HMR for code-split routes itself.
12
12
  */
13
- var includeCode = [
14
- "createFileRoute(",
15
- "createRootRoute(",
16
- "createRootRouteWithContext("
17
- ];
18
13
  function createRouterHmrPlugin(options = {}, routerPluginContext) {
19
14
  let ROOT = process.cwd();
20
15
  const resolveUserConfig = () => {
@@ -27,7 +22,7 @@ function createRouterHmrPlugin(options = {}, routerPluginContext) {
27
22
  transform: {
28
23
  filter: {
29
24
  id: /\.(m|c)?(j|t)sx?$/,
30
- code: { include: includeCode }
25
+ code: { include: routeFactoryCallCodeFilter }
31
26
  },
32
27
  handler(code, id) {
33
28
  const normalizedId = normalizePath(id);
@@ -1 +1 @@
1
- {"version":3,"file":"router-hmr-plugin.js","names":[],"sources":["../../../src/core/router-hmr-plugin.ts"],"sourcesContent":["import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'\nimport { compileCodeSplitReferenceRoute } from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport { createRouteHmrStatement } from './hmr'\nimport { debug, normalizePath } from './utils'\nimport { getConfig } from './config'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\n\n/**\n * This plugin adds HMR support for file routes.\n * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin\n * handles HMR for code-split routes itself.\n */\n\nconst includeCode = [\n 'createFileRoute(',\n 'createRootRoute(',\n 'createRootRouteWithContext(',\n]\n\nexport function createRouterHmrPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config> | undefined>> {\n let ROOT: string = process.cwd()\n\n const resolveUserConfig = () => {\n return getConfig(typeof options === 'function' ? options() : options, ROOT)\n }\n\n let userConfig = resolveUserConfig()\n\n return {\n name: 'tanstack-router:hmr',\n enforce: 'pre',\n transform: {\n filter: {\n // this is necessary for webpack / rspack to avoid matching .html files\n id: /\\.(m|c)?(j|t)sx?$/,\n code: {\n include: includeCode,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const routeEntry = routerPluginContext.routesByFile.get(normalizedId)\n if (!routeEntry) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n if (userConfig.target === 'react') {\n const compilerPlugins = getReferenceRouteCompilerPlugins({\n targetFramework: 'react',\n addHmr: true,\n hmrStyle,\n })\n const compiled = compileCodeSplitReferenceRoute({\n code,\n filename: normalizedId,\n id: normalizedId,\n addHmr: true,\n hmrStyle,\n hmrRouteId: routeEntry.routeId,\n codeSplitGroupings: [],\n targetFramework: 'react',\n compilerPlugins,\n })\n\n if (compiled) {\n if (debug) {\n logDiff(code, compiled.code)\n console.log('Output:\\n', compiled.code + '\\n\\n')\n }\n\n return compiled\n }\n }\n\n const ast = parseAst({ code, filename: normalizedId })\n ast.program.body.push(\n ...createRouteHmrStatement([], {\n hmrStyle,\n targetFramework: userConfig.target,\n routeId: routeEntry.routeId,\n }),\n )\n const result = generateFromAst(ast, {\n sourceMaps: true,\n filename: normalizedId,\n sourceFileName: normalizedId,\n })\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n return result\n },\n },\n vite: {\n configResolved(config) {\n ROOT = config.root\n userConfig = resolveUserConfig()\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n }\n}\n\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n return createRouterHmrPlugin(options, createRouterPluginContext())\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,IAAM,cAAc;CAClB;CACA;CACA;CACD;AAED,SAAgB,sBACd,UAAwD,EAAE,EAC1D,qBAC0D;CAC1D,IAAI,OAAe,QAAQ,KAAK;CAEhC,MAAM,0BAA0B;AAC9B,SAAO,UAAU,OAAO,YAAY,aAAa,SAAS,GAAG,SAAS,KAAK;;CAG7E,IAAI,aAAa,mBAAmB;AAEpC,QAAO;EACL,MAAM;EACN,SAAS;EACT,WAAW;GACT,QAAQ;IAEN,IAAI;IACJ,MAAM,EACJ,SAAS,aACV;IACF;GACD,QAAQ,MAAM,IAAI;IAChB,MAAM,eAAe,cAAc,GAAG;IACtC,MAAM,aAAa,oBAAoB,aAAa,IAAI,aAAa;AACrE,QAAI,CAAC,WACH,QAAO;AAGT,QAAI,MAAO,SAAQ,KAAK,iCAAiC,aAAa;IAEtE,MAAM,WAAW,WAAW,QAAQ,KAAK,SAAS;AAElD,QAAI,WAAW,WAAW,SAAS;KACjC,MAAM,kBAAkB,iCAAiC;MACvD,iBAAiB;MACjB,QAAQ;MACR;MACD,CAAC;KACF,MAAM,WAAW,+BAA+B;MAC9C;MACA,UAAU;MACV,IAAI;MACJ,QAAQ;MACR;MACA,YAAY,WAAW;MACvB,oBAAoB,EAAE;MACtB,iBAAiB;MACjB;MACD,CAAC;AAEF,SAAI,UAAU;AACZ,UAAI,OAAO;AACT,eAAQ,MAAM,SAAS,KAAK;AAC5B,eAAQ,IAAI,aAAa,SAAS,OAAO,OAAO;;AAGlD,aAAO;;;IAIX,MAAM,MAAM,SAAS;KAAE;KAAM,UAAU;KAAc,CAAC;AACtD,QAAI,QAAQ,KAAK,KACf,GAAG,wBAAwB,EAAE,EAAE;KAC7B;KACA,iBAAiB,WAAW;KAC5B,SAAS,WAAW;KACrB,CAAC,CACH;IACD,MAAM,SAAS,gBAAgB,KAAK;KAClC,YAAY;KACZ,UAAU;KACV,gBAAgB;KACjB,CAAC;AACF,QAAI,OAAO;AACT,aAAQ,MAAM,OAAO,KAAK;AAC1B,aAAQ,IAAI,aAAa,OAAO,OAAO,OAAO;;AAEhD,WAAO;;GAEV;EACD,MAAM;GACJ,eAAe,QAAQ;AACrB,WAAO,OAAO;AACd,iBAAa,mBAAmB;;GAElC,mBAAmB,aAAa;AAC9B,QAAI,WAAW,QAAQ,MAAM,gBAC3B,QAAO,WAAW,OAAO,KAAK,oBAAoB,YAAY;AAEhE,WAAO;;GAEV;EACF"}
1
+ {"version":3,"file":"router-hmr-plugin.js","names":[],"sources":["../../../src/core/router-hmr-plugin.ts"],"sourcesContent":["import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'\nimport { compileCodeSplitReferenceRoute } from './code-splitter/compilers'\nimport { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'\nimport { createRouteHmrStatement } from './hmr'\nimport { debug, normalizePath, routeFactoryCallCodeFilter } from './utils'\nimport { getConfig } from './config'\nimport { createRouterPluginContext } from './router-plugin-context'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\nimport type { RouterPluginContext } from './router-plugin-context'\n\n/**\n * This plugin adds HMR support for file routes.\n * It is only added to the composed plugin in dev when autoCodeSplitting is disabled, since the code splitting plugin\n * handles HMR for code-split routes itself.\n */\n\nexport function createRouterHmrPlugin(\n options: Partial<Config | (() => Config)> | undefined = {},\n routerPluginContext: RouterPluginContext,\n): ReturnType<UnpluginFactory<Partial<Config> | undefined>> {\n let ROOT: string = process.cwd()\n\n const resolveUserConfig = () => {\n return getConfig(typeof options === 'function' ? options() : options, ROOT)\n }\n\n let userConfig = resolveUserConfig()\n\n return {\n name: 'tanstack-router:hmr',\n enforce: 'pre',\n transform: {\n filter: {\n // this is necessary for webpack / rspack to avoid matching .html files\n id: /\\.(m|c)?(j|t)sx?$/,\n code: {\n include: routeFactoryCallCodeFilter,\n },\n },\n handler(code, id) {\n const normalizedId = normalizePath(id)\n const routeEntry = routerPluginContext.routesByFile.get(normalizedId)\n if (!routeEntry) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'\n\n if (userConfig.target === 'react') {\n const compilerPlugins = getReferenceRouteCompilerPlugins({\n targetFramework: 'react',\n addHmr: true,\n hmrStyle,\n })\n const compiled = compileCodeSplitReferenceRoute({\n code,\n filename: normalizedId,\n id: normalizedId,\n addHmr: true,\n hmrStyle,\n hmrRouteId: routeEntry.routeId,\n codeSplitGroupings: [],\n targetFramework: 'react',\n compilerPlugins,\n })\n\n if (compiled) {\n if (debug) {\n logDiff(code, compiled.code)\n console.log('Output:\\n', compiled.code + '\\n\\n')\n }\n\n return compiled\n }\n }\n\n const ast = parseAst({ code, filename: normalizedId })\n ast.program.body.push(\n ...createRouteHmrStatement([], {\n hmrStyle,\n targetFramework: userConfig.target,\n routeId: routeEntry.routeId,\n }),\n )\n const result = generateFromAst(ast, {\n sourceMaps: true,\n filename: normalizedId,\n sourceFileName: normalizedId,\n })\n if (debug) {\n logDiff(code, result.code)\n console.log('Output:\\n', result.code + '\\n\\n')\n }\n return result\n },\n },\n vite: {\n configResolved(config) {\n ROOT = config.root\n userConfig = resolveUserConfig()\n },\n applyToEnvironment(environment) {\n if (userConfig.plugin?.vite?.environmentName) {\n return userConfig.plugin.vite.environmentName === environment.name\n }\n return true\n },\n },\n }\n}\n\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n return createRouterHmrPlugin(options, createRouterPluginContext())\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,SAAgB,sBACd,UAAwD,EAAE,EAC1D,qBAC0D;CAC1D,IAAI,OAAe,QAAQ,KAAK;CAEhC,MAAM,0BAA0B;AAC9B,SAAO,UAAU,OAAO,YAAY,aAAa,SAAS,GAAG,SAAS,KAAK;;CAG7E,IAAI,aAAa,mBAAmB;AAEpC,QAAO;EACL,MAAM;EACN,SAAS;EACT,WAAW;GACT,QAAQ;IAEN,IAAI;IACJ,MAAM,EACJ,SAAS,4BACV;IACF;GACD,QAAQ,MAAM,IAAI;IAChB,MAAM,eAAe,cAAc,GAAG;IACtC,MAAM,aAAa,oBAAoB,aAAa,IAAI,aAAa;AACrE,QAAI,CAAC,WACH,QAAO;AAGT,QAAI,MAAO,SAAQ,KAAK,iCAAiC,aAAa;IAEtE,MAAM,WAAW,WAAW,QAAQ,KAAK,SAAS;AAElD,QAAI,WAAW,WAAW,SAAS;KACjC,MAAM,kBAAkB,iCAAiC;MACvD,iBAAiB;MACjB,QAAQ;MACR;MACD,CAAC;KACF,MAAM,WAAW,+BAA+B;MAC9C;MACA,UAAU;MACV,IAAI;MACJ,QAAQ;MACR;MACA,YAAY,WAAW;MACvB,oBAAoB,EAAE;MACtB,iBAAiB;MACjB;MACD,CAAC;AAEF,SAAI,UAAU;AACZ,UAAI,OAAO;AACT,eAAQ,MAAM,SAAS,KAAK;AAC5B,eAAQ,IAAI,aAAa,SAAS,OAAO,OAAO;;AAGlD,aAAO;;;IAIX,MAAM,MAAM,SAAS;KAAE;KAAM,UAAU;KAAc,CAAC;AACtD,QAAI,QAAQ,KAAK,KACf,GAAG,wBAAwB,EAAE,EAAE;KAC7B;KACA,iBAAiB,WAAW;KAC5B,SAAS,WAAW;KACrB,CAAC,CACH;IACD,MAAM,SAAS,gBAAgB,KAAK;KAClC,YAAY;KACZ,UAAU;KACV,gBAAgB;KACjB,CAAC;AACF,QAAI,OAAO;AACT,aAAQ,MAAM,OAAO,KAAK;AAC1B,aAAQ,IAAI,aAAa,OAAO,OAAO,OAAO;;AAEhD,WAAO;;GAEV;EACD,MAAM;GACJ,eAAe,QAAQ;AACrB,WAAO,OAAO;AACd,iBAAa,mBAAmB;;GAElC,mBAAmB,aAAa;AAC9B,QAAI,WAAW,QAAQ,MAAM,gBAC3B,QAAO,WAAW,OAAO,KAAK,oBAAoB,YAAY;AAEhE,WAAO;;GAEV;EACF"}
@@ -9,5 +9,6 @@ export declare const debug: boolean | "" | undefined;
9
9
  * pass native paths with backslashes to transform handlers.
10
10
  */
11
11
  export declare function normalizePath(path: string): string;
12
+ export declare const routeFactoryCallCodeFilter: RegExp[];
12
13
  export declare function getObjectPropertyKeyName(prop: t.ObjectProperty): string | undefined;
13
14
  export declare function getUniqueProgramIdentifier(programPath: babel.NodePath<t.Program>, baseName: string): t.Identifier;
@@ -11,6 +11,11 @@ var debug = process.env.TSR_VITE_DEBUG && ["true", "router-plugin"].includes(pro
11
11
  function normalizePath(path) {
12
12
  return path.replace(/\\/g, "/");
13
13
  }
14
+ var routeFactoryCallCodeFilter = [
15
+ /\bcreateFileRoute\s*\(/,
16
+ /\bcreateRootRoute\s*\(/,
17
+ /\bcreateRootRouteWithContext\s*(?:<|\()/
18
+ ];
14
19
  function getObjectPropertyKeyName(prop) {
15
20
  if (prop.computed) return;
16
21
  if (t.isIdentifier(prop.key)) return prop.key.name;
@@ -28,6 +33,6 @@ function getUniqueProgramIdentifier(programPath, baseName) {
28
33
  return t.identifier(name);
29
34
  }
30
35
  //#endregion
31
- export { debug, getObjectPropertyKeyName, getUniqueProgramIdentifier, normalizePath };
36
+ export { debug, getObjectPropertyKeyName, getUniqueProgramIdentifier, normalizePath, routeFactoryCallCodeFilter };
32
37
 
33
38
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../src/core/utils.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport type babel from '@babel/core'\n\nexport const debug =\n process.env.TSR_VITE_DEBUG &&\n ['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG)\n\n/**\n * Normalizes a file path by converting Windows backslashes to forward slashes.\n * This ensures consistent path handling across different bundlers and operating systems.\n *\n * The route generator stores paths with forward slashes, but rspack/webpack on Windows\n * pass native paths with backslashes to transform handlers.\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\nexport function getObjectPropertyKeyName(\n prop: t.ObjectProperty,\n): string | undefined {\n if (prop.computed) {\n return undefined\n }\n\n if (t.isIdentifier(prop.key)) {\n return prop.key.name\n }\n\n if (t.isStringLiteral(prop.key)) {\n return prop.key.value\n }\n\n return undefined\n}\n\nexport function getUniqueProgramIdentifier(\n programPath: babel.NodePath<t.Program>,\n baseName: string,\n): t.Identifier {\n let name = baseName\n let suffix = 2\n\n const programScope = programPath.scope.getProgramParent()\n\n while (\n programScope.hasBinding(name) ||\n programScope.hasGlobal(name) ||\n programScope.hasReference(name)\n ) {\n name = `${baseName}${suffix}`\n suffix++\n }\n\n // Register the name so subsequent calls within the same traversal\n // see it and avoid collisions\n programScope.references[name] = true\n\n return t.identifier(name)\n}\n"],"mappings":";;AAGA,IAAa,QACX,QAAQ,IAAI,kBACZ,CAAC,QAAQ,gBAAgB,CAAC,SAAS,QAAQ,IAAI,eAAe;;;;;;;;AAShE,SAAgB,cAAc,MAAsB;AAClD,QAAO,KAAK,QAAQ,OAAO,IAAI;;AAGjC,SAAgB,yBACd,MACoB;AACpB,KAAI,KAAK,SACP;AAGF,KAAI,EAAE,aAAa,KAAK,IAAI,CAC1B,QAAO,KAAK,IAAI;AAGlB,KAAI,EAAE,gBAAgB,KAAK,IAAI,CAC7B,QAAO,KAAK,IAAI;;AAMpB,SAAgB,2BACd,aACA,UACc;CACd,IAAI,OAAO;CACX,IAAI,SAAS;CAEb,MAAM,eAAe,YAAY,MAAM,kBAAkB;AAEzD,QACE,aAAa,WAAW,KAAK,IAC7B,aAAa,UAAU,KAAK,IAC5B,aAAa,aAAa,KAAK,EAC/B;AACA,SAAO,GAAG,WAAW;AACrB;;AAKF,cAAa,WAAW,QAAQ;AAEhC,QAAO,EAAE,WAAW,KAAK"}
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../../src/core/utils.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport type babel from '@babel/core'\n\nexport const debug =\n process.env.TSR_VITE_DEBUG &&\n ['true', 'router-plugin'].includes(process.env.TSR_VITE_DEBUG)\n\n/**\n * Normalizes a file path by converting Windows backslashes to forward slashes.\n * This ensures consistent path handling across different bundlers and operating systems.\n *\n * The route generator stores paths with forward slashes, but rspack/webpack on Windows\n * pass native paths with backslashes to transform handlers.\n */\nexport function normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\nexport const routeFactoryCallCodeFilter = [\n /\\bcreateFileRoute\\s*\\(/,\n /\\bcreateRootRoute\\s*\\(/,\n /\\bcreateRootRouteWithContext\\s*(?:<|\\()/,\n]\n\nexport function getObjectPropertyKeyName(\n prop: t.ObjectProperty,\n): string | undefined {\n if (prop.computed) {\n return undefined\n }\n\n if (t.isIdentifier(prop.key)) {\n return prop.key.name\n }\n\n if (t.isStringLiteral(prop.key)) {\n return prop.key.value\n }\n\n return undefined\n}\n\nexport function getUniqueProgramIdentifier(\n programPath: babel.NodePath<t.Program>,\n baseName: string,\n): t.Identifier {\n let name = baseName\n let suffix = 2\n\n const programScope = programPath.scope.getProgramParent()\n\n while (\n programScope.hasBinding(name) ||\n programScope.hasGlobal(name) ||\n programScope.hasReference(name)\n ) {\n name = `${baseName}${suffix}`\n suffix++\n }\n\n // Register the name so subsequent calls within the same traversal\n // see it and avoid collisions\n programScope.references[name] = true\n\n return t.identifier(name)\n}\n"],"mappings":";;AAGA,IAAa,QACX,QAAQ,IAAI,kBACZ,CAAC,QAAQ,gBAAgB,CAAC,SAAS,QAAQ,IAAI,eAAe;;;;;;;;AAShE,SAAgB,cAAc,MAAsB;AAClD,QAAO,KAAK,QAAQ,OAAO,IAAI;;AAGjC,IAAa,6BAA6B;CACxC;CACA;CACA;CACD;AAED,SAAgB,yBACd,MACoB;AACpB,KAAI,KAAK,SACP;AAGF,KAAI,EAAE,aAAa,KAAK,IAAI,CAC1B,QAAO,KAAK,IAAI;AAGlB,KAAI,EAAE,gBAAgB,KAAK,IAAI,CAC7B,QAAO,KAAK,IAAI;;AAMpB,SAAgB,2BACd,aACA,UACc;CACd,IAAI,OAAO;CACX,IAAI,SAAS;CAEb,MAAM,eAAe,YAAY,MAAM,kBAAkB;AAEzD,QACE,aAAa,WAAW,KAAK,IAC7B,aAAa,UAAU,KAAK,IAC5B,aAAa,aAAa,KAAK,EAC/B;AACA,SAAO,GAAG,WAAW;AACrB;;AAKF,cAAa,WAAW,QAAQ;AAEhC,QAAO,EAAE,WAAW,KAAK"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-plugin",
3
- "version": "1.168.4",
3
+ "version": "1.168.6",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -109,8 +109,8 @@
109
109
  "chokidar": "^3.6.0",
110
110
  "unplugin": "^3.0.0",
111
111
  "zod": "^3.24.2",
112
- "@tanstack/router-core": "1.171.1",
113
- "@tanstack/router-generator": "1.167.4",
112
+ "@tanstack/router-core": "1.171.2",
113
+ "@tanstack/router-generator": "1.167.5",
114
114
  "@tanstack/router-utils": "1.162.0",
115
115
  "@tanstack/virtual-file-routes": "1.162.0"
116
116
  },
@@ -125,7 +125,7 @@
125
125
  "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0",
126
126
  "vite-plugin-solid": "^2.11.10 || ^3.0.0-0",
127
127
  "webpack": ">=5.92.0",
128
- "@tanstack/react-router": "^1.170.3"
128
+ "@tanstack/react-router": "^1.170.4"
129
129
  },
130
130
  "peerDependenciesMeta": {
131
131
  "@rsbuild/core": {
@@ -7,7 +7,7 @@ const buildReactRefreshIgnoredRouteExportsStatements = template.statements(
7
7
  `
8
8
  const hot = import.meta.hot
9
9
  if (hot && typeof window !== 'undefined') {
10
- ;(hot.data ??= {})
10
+ hot.data ??= {}
11
11
  const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {
12
12
  const ignoredExportsById = new Map()
13
13
  const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports
@@ -18,7 +18,8 @@ type AnyRouteWithPrivateProps = AnyRoute & {
18
18
 
19
19
  type AnyRouterWithPrivateMaps = AnyRouter & {
20
20
  routesById: Record<string, AnyRoute>
21
- routesByPath: Record<string, AnyRoute>
21
+ buildRouteTree: () => Parameters<AnyRouter['setRoutes']>[0]
22
+ setRoutes: AnyRouter['setRoutes']
22
23
  stores: AnyRouter['stores'] & {
23
24
  cachedMatchStores: Map<
24
25
  string,
@@ -54,18 +55,19 @@ function handleRouteUpdate(
54
55
  return
55
56
  }
56
57
 
57
- // Keys whose identity must remain stable to prevent React from
58
- // unmounting/remounting the component tree. React Fast Refresh already
59
- // handles hot-updating the function bodies of these components — our job
60
- // is only to update non-component route options (loader, head, etc.).
61
- // For code-split (splittable) routes, the lazyRouteComponent wrapper is
62
- // already cached in the bundler hot data so its identity is stable.
63
- // For unsplittable routes (e.g. root routes), the component is a plain
64
- // function reference that gets recreated on every module re-execution,
65
- // so we must explicitly preserve the old reference.
58
+ // Generated route-tree options are not present on the freshly imported route
59
+ // module, but they must stay on the live route before rebuilding indexes.
60
+ const generatedRouteOptionKeys = new Set(['id', 'path', 'getParentRoute'])
61
+ const generatedRouteOptions: Record<string, unknown> = {}
62
+ generatedRouteOptionKeys.forEach((key) => {
63
+ if (key in oldRoute.options) {
64
+ generatedRouteOptions[key] = oldRoute.options[key]
65
+ }
66
+ })
67
+
66
68
  const removedKeys = new Set<string>()
67
69
  Object.keys(oldRoute.options).forEach((key) => {
68
- if (!(key in newRoute.options)) {
70
+ if (!generatedRouteOptionKeys.has(key) && !(key in newRoute.options)) {
69
71
  removedKeys.add(key)
70
72
  delete oldRoute.options[key]
71
73
  }
@@ -76,6 +78,15 @@ function handleRouteUpdate(
76
78
  const preserveComponentIdentity =
77
79
  oldHasShellComponent === newHasShellComponent
78
80
 
81
+ // Keys whose identity must remain stable to prevent React from
82
+ // unmounting/remounting the component tree. React Fast Refresh already
83
+ // handles hot-updating the function bodies of these components — our job
84
+ // is only to update non-component route options (loader, head, etc.).
85
+ // For code-split (splittable) routes, the lazyRouteComponent wrapper is
86
+ // already cached in the bundler hot data so its identity is stable.
87
+ // For unsplittable routes (e.g. root routes), the component is a plain
88
+ // function reference that gets recreated on every module re-execution,
89
+ // so we must explicitly preserve the old reference.
79
90
  // Preserve component identity so React doesn't remount.
80
91
  // React Fast Refresh patches the function bodies in-place.
81
92
  const componentKeys = '__TSR_COMPONENT_TYPES__' as unknown as Array<string>
@@ -87,19 +98,18 @@ function handleRouteUpdate(
87
98
  })
88
99
  }
89
100
 
90
- oldRoute.options = newRoute.options
91
- oldRoute.update(newRoute.options)
101
+ const nextOptions = {
102
+ ...newRoute.options,
103
+ ...generatedRouteOptions,
104
+ }
105
+
106
+ oldRoute.options = nextOptions
107
+ oldRoute.update(nextOptions)
92
108
  oldRoute._componentsPromise = undefined
93
109
  oldRoute._lazyPromise = undefined
94
110
 
95
- router.routesById[oldRoute.id] = oldRoute
96
- router.routesByPath[oldRoute.fullPath] = oldRoute
97
-
98
- router.processedTree.matchCache.clear()
99
- router.processedTree.flatCache?.clear()
100
- router.processedTree.singleCache.clear()
111
+ router.setRoutes(router.buildRouteTree())
101
112
  router.resolvePathCache.clear()
102
- walkReplaceSegmentTree(oldRoute, router.processedTree.segmentTree)
103
113
 
104
114
  const filter = (m: AnyRouteMatch) => m.routeId === oldRoute.id
105
115
  const activeMatch = router.stores.matches.get().find(filter)
@@ -149,21 +159,6 @@ function handleRouteUpdate(
149
159
  router.invalidate({ filter, sync: true })
150
160
  }
151
161
 
152
- function walkReplaceSegmentTree(
153
- route: AnyRouteWithPrivateProps,
154
- node: AnyRouter['processedTree']['segmentTree'],
155
- ) {
156
- if (node.route?.id === route.id) node.route = route
157
- if (node.index) walkReplaceSegmentTree(route, node.index)
158
- node.static?.forEach((child) => walkReplaceSegmentTree(route, child))
159
- node.staticInsensitive?.forEach((child) =>
160
- walkReplaceSegmentTree(route, child),
161
- )
162
- node.dynamic?.forEach((child) => walkReplaceSegmentTree(route, child))
163
- node.optional?.forEach((child) => walkReplaceSegmentTree(route, child))
164
- node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child))
165
- }
166
-
167
162
  function getStoreMatch(matchId: string) {
168
163
  return (
169
164
  router.stores.pendingMatchStores.get(matchId)?.get() ||
@@ -21,7 +21,7 @@ import {
21
21
  tsrSplit,
22
22
  } from './constants'
23
23
  import { decodeIdentifier } from './code-splitter/path-ids'
24
- import { debug, normalizePath } from './utils'
24
+ import { debug, normalizePath, routeFactoryCallCodeFilter } from './utils'
25
25
  import { createRouterPluginContext } from './router-plugin-context'
26
26
  import type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'
27
27
  import type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'
@@ -240,11 +240,6 @@ export function createRouterCodeSplitterPlugin(
240
240
  return result
241
241
  }
242
242
 
243
- const includedCode = [
244
- 'createFileRoute(',
245
- 'createRootRoute(',
246
- 'createRootRouteWithContext(',
247
- ]
248
243
  return [
249
244
  {
250
245
  name: 'tanstack-router:code-splitter:compile-reference-file',
@@ -258,17 +253,14 @@ export function createRouterCodeSplitterPlugin(
258
253
  include: /\.(m|c)?(j|t)sx?$/,
259
254
  },
260
255
  code: {
261
- include: includedCode,
256
+ include: routeFactoryCallCodeFilter,
262
257
  },
263
258
  },
264
259
  handler(code, id) {
265
260
  const normalizedId = normalizePath(id)
266
261
  const generatorFileInfo =
267
262
  routerPluginContext.routesByFile.get(normalizedId)
268
- if (
269
- generatorFileInfo &&
270
- includedCode.some((included) => code.includes(included))
271
- ) {
263
+ if (generatorFileInfo) {
272
264
  return handleCompilingReferenceFile(
273
265
  code,
274
266
  normalizedId,
@@ -2,7 +2,7 @@ import { generateFromAst, logDiff, parseAst } from '@tanstack/router-utils'
2
2
  import { compileCodeSplitReferenceRoute } from './code-splitter/compilers'
3
3
  import { getReferenceRouteCompilerPlugins } from './code-splitter/plugins/framework-plugins'
4
4
  import { createRouteHmrStatement } from './hmr'
5
- import { debug, normalizePath } from './utils'
5
+ import { debug, normalizePath, routeFactoryCallCodeFilter } from './utils'
6
6
  import { getConfig } from './config'
7
7
  import { createRouterPluginContext } from './router-plugin-context'
8
8
  import type { UnpluginFactory } from 'unplugin'
@@ -15,12 +15,6 @@ import type { RouterPluginContext } from './router-plugin-context'
15
15
  * handles HMR for code-split routes itself.
16
16
  */
17
17
 
18
- const includeCode = [
19
- 'createFileRoute(',
20
- 'createRootRoute(',
21
- 'createRootRouteWithContext(',
22
- ]
23
-
24
18
  export function createRouterHmrPlugin(
25
19
  options: Partial<Config | (() => Config)> | undefined = {},
26
20
  routerPluginContext: RouterPluginContext,
@@ -41,7 +35,7 @@ export function createRouterHmrPlugin(
41
35
  // this is necessary for webpack / rspack to avoid matching .html files
42
36
  id: /\.(m|c)?(j|t)sx?$/,
43
37
  code: {
44
- include: includeCode,
38
+ include: routeFactoryCallCodeFilter,
45
39
  },
46
40
  },
47
41
  handler(code, id) {
package/src/core/utils.ts CHANGED
@@ -16,6 +16,12 @@ export function normalizePath(path: string): string {
16
16
  return path.replace(/\\/g, '/')
17
17
  }
18
18
 
19
+ export const routeFactoryCallCodeFilter = [
20
+ /\bcreateFileRoute\s*\(/,
21
+ /\bcreateRootRoute\s*\(/,
22
+ /\bcreateRootRouteWithContext\s*(?:<|\()/,
23
+ ]
24
+
19
25
  export function getObjectPropertyKeyName(
20
26
  prop: t.ObjectProperty,
21
27
  ): string | undefined {