@tanstack/router-plugin 1.167.22 → 1.167.24

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 (114) hide show
  1. package/dist/cjs/core/code-splitter/compilers.cjs +8 -4
  2. package/dist/cjs/core/code-splitter/compilers.cjs.map +1 -1
  3. package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs +8 -5
  4. package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs.map +1 -1
  5. package/dist/cjs/core/code-splitter/plugins/framework-plugins.d.cts +2 -2
  6. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs +5 -9
  7. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs.map +1 -1
  8. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.d.cts +1 -3
  9. package/dist/cjs/core/code-splitter/plugins/react-stable-hmr-split-route-components.cjs +6 -4
  10. package/dist/cjs/core/code-splitter/plugins/react-stable-hmr-split-route-components.cjs.map +1 -1
  11. package/dist/cjs/core/code-splitter/plugins/react-stable-hmr-split-route-components.d.cts +3 -2
  12. package/dist/cjs/core/code-splitter/plugins.d.cts +3 -2
  13. package/dist/cjs/core/config.cjs +1 -1
  14. package/dist/cjs/core/config.cjs.map +1 -1
  15. package/dist/cjs/core/config.d.cts +26 -18
  16. package/dist/cjs/core/{route-hmr-statement.cjs → hmr/handle-route-update.cjs} +39 -25
  17. package/dist/cjs/core/hmr/handle-route-update.cjs.map +1 -0
  18. package/dist/cjs/core/hmr/handle-route-update.d.cts +1 -0
  19. package/dist/cjs/core/hmr/index.d.cts +5 -0
  20. package/dist/cjs/core/hmr/select-adapter.cjs +20 -0
  21. package/dist/cjs/core/hmr/select-adapter.cjs.map +1 -0
  22. package/dist/cjs/core/hmr/select-adapter.d.cts +13 -0
  23. package/dist/cjs/core/hmr/vite-adapter.cjs +36 -0
  24. package/dist/cjs/core/hmr/vite-adapter.cjs.map +1 -0
  25. package/dist/cjs/core/hmr/vite-adapter.d.cts +12 -0
  26. package/dist/cjs/core/hmr/webpack-adapter.cjs +64 -0
  27. package/dist/cjs/core/hmr/webpack-adapter.cjs.map +1 -0
  28. package/dist/cjs/core/hmr/webpack-adapter.d.cts +20 -0
  29. package/dist/cjs/core/router-code-splitter-plugin.cjs +5 -5
  30. package/dist/cjs/core/router-code-splitter-plugin.cjs.map +1 -1
  31. package/dist/cjs/core/router-composed-plugin.cjs +30 -2
  32. package/dist/cjs/core/router-composed-plugin.cjs.map +1 -1
  33. package/dist/cjs/core/router-composed-plugin.d.cts +1 -1
  34. package/dist/cjs/core/router-hmr-plugin.cjs +17 -11
  35. package/dist/cjs/core/router-hmr-plugin.cjs.map +1 -1
  36. package/dist/cjs/esbuild.d.cts +14 -14
  37. package/dist/cjs/rspack.cjs +22 -3
  38. package/dist/cjs/rspack.cjs.map +1 -1
  39. package/dist/cjs/rspack.d.cts +3 -3
  40. package/dist/cjs/vite.d.cts +14 -14
  41. package/dist/cjs/webpack.cjs +19 -3
  42. package/dist/cjs/webpack.cjs.map +1 -1
  43. package/dist/cjs/webpack.d.cts +3 -3
  44. package/dist/esm/core/code-splitter/compilers.js +7 -3
  45. package/dist/esm/core/code-splitter/compilers.js.map +1 -1
  46. package/dist/esm/core/code-splitter/plugins/framework-plugins.d.ts +2 -2
  47. package/dist/esm/core/code-splitter/plugins/framework-plugins.js +8 -5
  48. package/dist/esm/core/code-splitter/plugins/framework-plugins.js.map +1 -1
  49. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.d.ts +1 -3
  50. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js +4 -8
  51. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js.map +1 -1
  52. package/dist/esm/core/code-splitter/plugins/react-stable-hmr-split-route-components.d.ts +3 -2
  53. package/dist/esm/core/code-splitter/plugins/react-stable-hmr-split-route-components.js +5 -3
  54. package/dist/esm/core/code-splitter/plugins/react-stable-hmr-split-route-components.js.map +1 -1
  55. package/dist/esm/core/code-splitter/plugins.d.ts +3 -2
  56. package/dist/esm/core/config.d.ts +26 -18
  57. package/dist/esm/core/config.js +1 -1
  58. package/dist/esm/core/config.js.map +1 -1
  59. package/dist/esm/core/hmr/handle-route-update.d.ts +1 -0
  60. package/dist/esm/core/{route-hmr-statement.js → hmr/handle-route-update.js} +39 -23
  61. package/dist/esm/core/hmr/handle-route-update.js.map +1 -0
  62. package/dist/esm/core/hmr/index.d.ts +5 -0
  63. package/dist/esm/core/hmr/select-adapter.d.ts +13 -0
  64. package/dist/esm/core/hmr/select-adapter.js +20 -0
  65. package/dist/esm/core/hmr/select-adapter.js.map +1 -0
  66. package/dist/esm/core/hmr/vite-adapter.d.ts +12 -0
  67. package/dist/esm/core/hmr/vite-adapter.js +34 -0
  68. package/dist/esm/core/hmr/vite-adapter.js.map +1 -0
  69. package/dist/esm/core/hmr/webpack-adapter.d.ts +20 -0
  70. package/dist/esm/core/hmr/webpack-adapter.js +62 -0
  71. package/dist/esm/core/hmr/webpack-adapter.js.map +1 -0
  72. package/dist/esm/core/router-code-splitter-plugin.js +5 -5
  73. package/dist/esm/core/router-code-splitter-plugin.js.map +1 -1
  74. package/dist/esm/core/router-composed-plugin.d.ts +1 -1
  75. package/dist/esm/core/router-composed-plugin.js +30 -2
  76. package/dist/esm/core/router-composed-plugin.js.map +1 -1
  77. package/dist/esm/core/router-hmr-plugin.js +17 -11
  78. package/dist/esm/core/router-hmr-plugin.js.map +1 -1
  79. package/dist/esm/esbuild.d.ts +14 -14
  80. package/dist/esm/rspack.d.ts +3 -3
  81. package/dist/esm/rspack.js +22 -3
  82. package/dist/esm/rspack.js.map +1 -1
  83. package/dist/esm/vite.d.ts +14 -14
  84. package/dist/esm/webpack.d.ts +3 -3
  85. package/dist/esm/webpack.js +19 -3
  86. package/dist/esm/webpack.js.map +1 -1
  87. package/package.json +6 -6
  88. package/src/core/code-splitter/compilers.ts +4 -2
  89. package/src/core/code-splitter/plugins/framework-plugins.ts +7 -8
  90. package/src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts +2 -8
  91. package/src/core/code-splitter/plugins/react-stable-hmr-split-route-components.ts +10 -6
  92. package/src/core/code-splitter/plugins.ts +3 -2
  93. package/src/core/config.ts +11 -2
  94. package/src/core/{route-hmr-statement.ts → hmr/handle-route-update.ts} +85 -39
  95. package/src/core/hmr/index.ts +5 -0
  96. package/src/core/hmr/select-adapter.ts +32 -0
  97. package/src/core/hmr/vite-adapter.ts +47 -0
  98. package/src/core/hmr/webpack-adapter.ts +110 -0
  99. package/src/core/router-code-splitter-plugin.ts +5 -7
  100. package/src/core/router-composed-plugin.ts +60 -5
  101. package/src/core/router-hmr-plugin.ts +12 -9
  102. package/src/rspack.ts +37 -9
  103. package/src/webpack.ts +22 -9
  104. package/dist/cjs/core/hmr-hot-expression.cjs +0 -27
  105. package/dist/cjs/core/hmr-hot-expression.cjs.map +0 -1
  106. package/dist/cjs/core/hmr-hot-expression.d.cts +0 -6
  107. package/dist/cjs/core/route-hmr-statement.cjs.map +0 -1
  108. package/dist/cjs/core/route-hmr-statement.d.cts +0 -4
  109. package/dist/esm/core/hmr-hot-expression.d.ts +0 -6
  110. package/dist/esm/core/hmr-hot-expression.js +0 -23
  111. package/dist/esm/core/hmr-hot-expression.js.map +0 -1
  112. package/dist/esm/core/route-hmr-statement.d.ts +0 -4
  113. package/dist/esm/core/route-hmr-statement.js.map +0 -1
  114. package/src/core/hmr-hot-expression.ts +0 -31
@@ -1,10 +1,9 @@
1
1
  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
- import { createRouteHmrStatement } from './route-hmr-statement'
4
+ import { createRouteHmrStatement } from './hmr'
5
5
  import { debug, normalizePath } from './utils'
6
6
  import { getConfig } from './config'
7
- import { resolveHmrHotExpression } from './hmr-hot-expression'
8
7
  import type { UnpluginFactory } from 'unplugin'
9
8
  import type { Config } from './config'
10
9
 
@@ -38,28 +37,28 @@ export const unpluginRouterHmrFactory: UnpluginFactory<
38
37
  },
39
38
  handler(code, id) {
40
39
  const normalizedId = normalizePath(id)
41
- if (!globalThis.TSR_ROUTES_BY_ID_MAP?.has(normalizedId)) {
40
+ const routeEntry = globalThis.TSR_ROUTES_BY_ID_MAP?.get(normalizedId)
41
+ if (!routeEntry) {
42
42
  return null
43
43
  }
44
44
 
45
45
  if (debug) console.info('Adding HMR handling to route ', normalizedId)
46
46
 
47
- const hmrHotExpression = resolveHmrHotExpression(
48
- userConfig.plugin?.hmr?.hotExpression,
49
- )
47
+ const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'
50
48
 
51
49
  if (userConfig.target === 'react') {
52
50
  const compilerPlugins = getReferenceRouteCompilerPlugins({
53
51
  targetFramework: 'react',
54
52
  addHmr: true,
55
- hmrHotExpression,
53
+ hmrStyle,
56
54
  })
57
55
  const compiled = compileCodeSplitReferenceRoute({
58
56
  code,
59
57
  filename: normalizedId,
60
58
  id: normalizedId,
61
59
  addHmr: true,
62
- hmrHotExpression,
60
+ hmrStyle,
61
+ hmrRouteId: routeEntry.routeId,
63
62
  codeSplitGroupings: [],
64
63
  targetFramework: 'react',
65
64
  compilerPlugins,
@@ -77,7 +76,11 @@ export const unpluginRouterHmrFactory: UnpluginFactory<
77
76
 
78
77
  const ast = parseAst({ code })
79
78
  ast.program.body.push(
80
- createRouteHmrStatement([], { hotExpression: hmrHotExpression }),
79
+ ...createRouteHmrStatement([], {
80
+ hmrStyle,
81
+ targetFramework: userConfig.target,
82
+ routeId: routeEntry.routeId,
83
+ }),
81
84
  )
82
85
  const result = generateFromAst(ast, {
83
86
  sourceMaps: true,
package/src/rspack.ts CHANGED
@@ -1,12 +1,42 @@
1
1
  import { createRspackPlugin } from 'unplugin'
2
2
 
3
3
  import { configSchema } from './core/config'
4
- import { withHmrHotExpression } from './core/hmr-hot-expression'
5
4
  import { unpluginRouterCodeSplitterFactory } from './core/router-code-splitter-plugin'
6
5
  import { unpluginRouterGeneratorFactory } from './core/router-generator-plugin'
7
6
  import { unpluginRouterComposedFactory } from './core/router-composed-plugin'
8
7
  import type { CodeSplittingOptions, Config } from './core/config'
9
8
 
9
+ type RspackRouterPluginOptions = Partial<Config> | (() => Partial<Config>)
10
+
11
+ /**
12
+ * Rspack uses webpack-compatible `module.hot` / `import.meta.webpackHot` HMR.
13
+ * Force `plugin.hmr.style = 'webpack'` so the router HMR adapter emits
14
+ * `module.hot`-style accept/dispose code instead of Vite's callback-receive
15
+ * variant, regardless of what the user passes (or doesn't pass).
16
+ */
17
+ function withWebpackHmrStyle(
18
+ options: RspackRouterPluginOptions | undefined,
19
+ ): RspackRouterPluginOptions {
20
+ const mergeHmrStyle = (
21
+ config: Partial<Config> | undefined,
22
+ ): Partial<Config> => ({
23
+ ...config,
24
+ plugin: {
25
+ ...config?.plugin,
26
+ hmr: {
27
+ ...config?.plugin?.hmr,
28
+ style: 'webpack',
29
+ },
30
+ },
31
+ })
32
+
33
+ if (typeof options === 'function') {
34
+ return () => mergeHmrStyle(options())
35
+ }
36
+
37
+ return mergeHmrStyle(options)
38
+ }
39
+
10
40
  /**
11
41
  * @example
12
42
  * ```ts
@@ -40,10 +70,9 @@ const TanStackRouterGeneratorRspack = /* #__PURE__ */ createRspackPlugin(
40
70
  const TanStackRouterCodeSplitterRspack = /* #__PURE__ */ createRspackPlugin(
41
71
  (options, meta) =>
42
72
  unpluginRouterCodeSplitterFactory(
43
- withHmrHotExpression(
44
- options as Partial<Config> | undefined,
45
- 'import.meta.webpackHot',
46
- ),
73
+ withWebpackHmrStyle(
74
+ options as RspackRouterPluginOptions | undefined,
75
+ ) as Partial<Config | (() => Config)>,
47
76
  meta,
48
77
  ),
49
78
  )
@@ -64,10 +93,9 @@ const TanStackRouterCodeSplitterRspack = /* #__PURE__ */ createRspackPlugin(
64
93
  const TanStackRouterRspack = /* #__PURE__ */ createRspackPlugin(
65
94
  (options, meta) =>
66
95
  unpluginRouterComposedFactory(
67
- withHmrHotExpression(
68
- options as Partial<Config> | undefined,
69
- 'import.meta.webpackHot',
70
- ),
96
+ withWebpackHmrStyle(
97
+ options as RspackRouterPluginOptions | undefined,
98
+ ) as Partial<Config | (() => Config)>,
71
99
  meta,
72
100
  ),
73
101
  )
package/src/webpack.ts CHANGED
@@ -1,12 +1,31 @@
1
1
  import { createWebpackPlugin } from 'unplugin'
2
2
 
3
3
  import { configSchema } from './core/config'
4
- import { withHmrHotExpression } from './core/hmr-hot-expression'
5
4
  import { unpluginRouterCodeSplitterFactory } from './core/router-code-splitter-plugin'
6
5
  import { unpluginRouterGeneratorFactory } from './core/router-generator-plugin'
7
6
  import { unpluginRouterComposedFactory } from './core/router-composed-plugin'
8
7
  import type { CodeSplittingOptions, Config } from './core/config'
9
8
 
9
+ /**
10
+ * Webpack uses `module.hot` / `import.meta.webpackHot` HMR. Force
11
+ * `plugin.hmr.style = 'webpack'` so the router HMR adapter emits the correct
12
+ * accept/dispose shape regardless of user config.
13
+ */
14
+ function withWebpackHmrStyle(
15
+ options: Partial<Config> | undefined,
16
+ ): Partial<Config> {
17
+ return {
18
+ ...options,
19
+ plugin: {
20
+ ...options?.plugin,
21
+ hmr: {
22
+ ...options?.plugin?.hmr,
23
+ style: 'webpack',
24
+ },
25
+ },
26
+ }
27
+ }
28
+
10
29
  /**
11
30
  * @example
12
31
  * ```ts
@@ -32,10 +51,7 @@ const TanStackRouterGeneratorWebpack = /* #__PURE__ */ createWebpackPlugin(
32
51
  const TanStackRouterCodeSplitterWebpack = /* #__PURE__ */ createWebpackPlugin(
33
52
  (options, meta) =>
34
53
  unpluginRouterCodeSplitterFactory(
35
- withHmrHotExpression(
36
- options as Partial<Config> | undefined,
37
- 'import.meta.webpackHot',
38
- ),
54
+ withWebpackHmrStyle(options as Partial<Config> | undefined),
39
55
  meta,
40
56
  ),
41
57
  )
@@ -52,10 +68,7 @@ const TanStackRouterCodeSplitterWebpack = /* #__PURE__ */ createWebpackPlugin(
52
68
  const TanStackRouterWebpack = /* #__PURE__ */ createWebpackPlugin(
53
69
  (options, meta) =>
54
70
  unpluginRouterComposedFactory(
55
- withHmrHotExpression(
56
- options as Partial<Config> | undefined,
57
- 'import.meta.webpackHot',
58
- ),
71
+ withWebpackHmrStyle(options as Partial<Config> | undefined),
59
72
  meta,
60
73
  ),
61
74
  )
@@ -1,27 +0,0 @@
1
- const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
- let _babel_template = require("@babel/template");
3
- _babel_template = require_runtime.__toESM(_babel_template);
4
- function resolveHmrHotExpression(hotExpression) {
5
- return hotExpression ?? "import.meta.hot";
6
- }
7
- function createHmrHotExpressionAst(hotExpression) {
8
- return _babel_template.expression.ast(resolveHmrHotExpression(hotExpression));
9
- }
10
- function withHmrHotExpression(config, hotExpression) {
11
- return {
12
- ...config,
13
- plugin: {
14
- ...config?.plugin,
15
- hmr: {
16
- ...config?.plugin?.hmr,
17
- hotExpression: config?.plugin?.hmr?.hotExpression ?? hotExpression
18
- }
19
- }
20
- };
21
- }
22
- //#endregion
23
- exports.createHmrHotExpressionAst = createHmrHotExpressionAst;
24
- exports.resolveHmrHotExpression = resolveHmrHotExpression;
25
- exports.withHmrHotExpression = withHmrHotExpression;
26
-
27
- //# sourceMappingURL=hmr-hot-expression.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hmr-hot-expression.cjs","names":[],"sources":["../../../src/core/hmr-hot-expression.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport type * as t from '@babel/types'\nimport type { Config } from './config'\n\nexport const DEFAULT_HMR_HOT_EXPRESSION = 'import.meta.hot'\n\nexport function resolveHmrHotExpression(hotExpression?: string): string {\n return hotExpression ?? DEFAULT_HMR_HOT_EXPRESSION\n}\n\nexport function createHmrHotExpressionAst(\n hotExpression?: string,\n): t.Expression {\n return template.expression.ast(resolveHmrHotExpression(hotExpression))\n}\n\nexport function withHmrHotExpression(\n config: Partial<Config> | undefined,\n hotExpression: string,\n): Partial<Config> {\n return {\n ...config,\n plugin: {\n ...config?.plugin,\n hmr: {\n ...config?.plugin?.hmr,\n hotExpression: config?.plugin?.hmr?.hotExpression ?? hotExpression,\n },\n },\n }\n}\n"],"mappings":";;;AAMA,SAAgB,wBAAwB,eAAgC;AACtE,QAAO,iBAAA;;AAGT,SAAgB,0BACd,eACc;AACd,QAAO,gBAAS,WAAW,IAAI,wBAAwB,cAAc,CAAC;;AAGxE,SAAgB,qBACd,QACA,eACiB;AACjB,QAAO;EACL,GAAG;EACH,QAAQ;GACN,GAAG,QAAQ;GACX,KAAK;IACH,GAAG,QAAQ,QAAQ;IACnB,eAAe,QAAQ,QAAQ,KAAK,iBAAiB;IACtD;GACF;EACF"}
@@ -1,6 +0,0 @@
1
- import { Config } from './config.cjs';
2
- import type * as t from '@babel/types';
3
- export declare const DEFAULT_HMR_HOT_EXPRESSION = "import.meta.hot";
4
- export declare function resolveHmrHotExpression(hotExpression?: string): string;
5
- export declare function createHmrHotExpressionAst(hotExpression?: string): t.Expression;
6
- export declare function withHmrHotExpression(config: Partial<Config> | undefined, hotExpression: string): Partial<Config>;
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-hmr-statement.cjs","names":[],"sources":["../../../src/core/route-hmr-statement.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport { createHmrHotExpressionAst } from './hmr-hot-expression'\nimport type * as t from '@babel/types'\nimport 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>, 'set'>\n >\n pendingMatchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'set'>\n >\n matchStores: Map<string, Pick<RouterWritableStore<AnyRouteMatch>, 'set'>>\n }\n}\n\ntype AnyRouteMatchWithPrivateProps = AnyRouteMatch & {\n __beforeLoadContext?: 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 // 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 componentKeys.forEach((key) => {\n if (key in oldRoute.options && key in newRoute.options) {\n newRoute.options[key] = oldRoute.options[key]\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 }\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\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function createRouteHmrStatement(\n stableRouteOptionKeys: Array<string>,\n opts?: { hotExpression?: string },\n): t.Statement {\n return template.statement(\n `\nif (%%hotExpression%%) {\n const hot = %%hotExpression%%\n const hotData = hot.data ??= {}\n hot.accept((newModule) => {\n if (Route && newModule && newModule.Route) {\n const routeId = hotData['tsr-route-id'] ?? Route.id\n if (routeId) {\n hotData['tsr-route-id'] = routeId\n }\n (${handleRouteUpdateStr.replace(\n /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n JSON.stringify(stableRouteOptionKeys),\n )})(routeId, newModule.Route)\n }\n })\n}\n`,\n {\n syntacticPlaceholders: true,\n },\n )({\n hotExpression: createHmrHotExpressionAst(opts?.hotExpression),\n })\n}\n"],"mappings":";;;;;AAyCA,SAAS,kBACP,SACA,UACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO,WAAW;AAInC,KAAI,CAAC,SACH;CAYF,MAAM,8BAAc,IAAI,KAAa;AACrC,QAAO,KAAK,SAAS,QAAQ,CAAC,SAAS,QAAQ;AAC7C,MAAI,EAAE,OAAO,SAAS,UAAU;AAC9B,eAAY,IAAI,IAAI;AACpB,UAAO,SAAS,QAAQ;;GAE1B;AAIoB,2BACR,SAAS,QAAQ;AAC7B,MAAI,OAAO,SAAS,WAAW,OAAO,SAAS,QAC7C,UAAS,QAAQ,OAAO,SAAS,QAAQ;GAE3C;AAEF,UAAS,UAAU,SAAS;AAC5B,UAAS,OAAO,SAAS,QAAQ;AACjC,UAAS,qBAAqB,KAAA;AAC9B,UAAS,eAAe,KAAA;AAExB,QAAO,WAAW,SAAS,MAAM;AACjC,QAAO,aAAa,SAAS,YAAY;AAEzC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,YAAY,OAAO;AACxC,QAAO,iBAAiB,OAAO;AAC/B,wBAAuB,UAAU,OAAO,cAAc,YAAY;CAElE,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,CAC/B,MAAK,sBAAsB,KAAA;AAG7B,aAAO;OACP;;KAGN;;AAGJ,SAAO,WAAW;GAAE;GAAQ,MAAM;GAAM,CAAC;;CAG3C,SAAS,uBACP,OACA,MACA;AACA,MAAI,KAAK,OAAO,OAAO,MAAM,GAAI,MAAK,QAAQ;AAC9C,MAAI,KAAK,MAAO,wBAAuB,OAAO,KAAK,MAAM;AACzD,OAAK,QAAQ,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACrE,OAAK,mBAAmB,SAAS,UAC/B,uBAAuB,OAAO,MAAM,CACrC;AACD,OAAK,SAAS,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACtE,OAAK,UAAU,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACvE,OAAK,UAAU,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;;;AAI3E,IAAM,uBAAuB,kBAAkB,UAAU;AAEzD,SAAgB,wBACd,uBACA,MACa;AACb,QAAO,gBAAS,UACd;;;;;;;;;;SAUK,qBAAqB,QACtB,mCACA,KAAK,UAAU,sBAAsB,CACtC,CAAC;;;;GAKJ,EACE,uBAAuB,MACxB,CACF,CAAC,EACA,eAAe,2BAAA,0BAA0B,MAAM,cAAc,EAC9D,CAAC"}
@@ -1,4 +0,0 @@
1
- import type * as t from '@babel/types';
2
- export declare function createRouteHmrStatement(stableRouteOptionKeys: Array<string>, opts?: {
3
- hotExpression?: string;
4
- }): t.Statement;
@@ -1,6 +0,0 @@
1
- import { Config } from './config.js';
2
- import type * as t from '@babel/types';
3
- export declare const DEFAULT_HMR_HOT_EXPRESSION = "import.meta.hot";
4
- export declare function resolveHmrHotExpression(hotExpression?: string): string;
5
- export declare function createHmrHotExpressionAst(hotExpression?: string): t.Expression;
6
- export declare function withHmrHotExpression(config: Partial<Config> | undefined, hotExpression: string): Partial<Config>;
@@ -1,23 +0,0 @@
1
- import * as template from "@babel/template";
2
- function resolveHmrHotExpression(hotExpression) {
3
- return hotExpression ?? "import.meta.hot";
4
- }
5
- function createHmrHotExpressionAst(hotExpression) {
6
- return template.expression.ast(resolveHmrHotExpression(hotExpression));
7
- }
8
- function withHmrHotExpression(config, hotExpression) {
9
- return {
10
- ...config,
11
- plugin: {
12
- ...config?.plugin,
13
- hmr: {
14
- ...config?.plugin?.hmr,
15
- hotExpression: config?.plugin?.hmr?.hotExpression ?? hotExpression
16
- }
17
- }
18
- };
19
- }
20
- //#endregion
21
- export { createHmrHotExpressionAst, resolveHmrHotExpression, withHmrHotExpression };
22
-
23
- //# sourceMappingURL=hmr-hot-expression.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hmr-hot-expression.js","names":[],"sources":["../../../src/core/hmr-hot-expression.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport type * as t from '@babel/types'\nimport type { Config } from './config'\n\nexport const DEFAULT_HMR_HOT_EXPRESSION = 'import.meta.hot'\n\nexport function resolveHmrHotExpression(hotExpression?: string): string {\n return hotExpression ?? DEFAULT_HMR_HOT_EXPRESSION\n}\n\nexport function createHmrHotExpressionAst(\n hotExpression?: string,\n): t.Expression {\n return template.expression.ast(resolveHmrHotExpression(hotExpression))\n}\n\nexport function withHmrHotExpression(\n config: Partial<Config> | undefined,\n hotExpression: string,\n): Partial<Config> {\n return {\n ...config,\n plugin: {\n ...config?.plugin,\n hmr: {\n ...config?.plugin?.hmr,\n hotExpression: config?.plugin?.hmr?.hotExpression ?? hotExpression,\n },\n },\n }\n}\n"],"mappings":";AAMA,SAAgB,wBAAwB,eAAgC;AACtE,QAAO,iBAAA;;AAGT,SAAgB,0BACd,eACc;AACd,QAAO,SAAS,WAAW,IAAI,wBAAwB,cAAc,CAAC;;AAGxE,SAAgB,qBACd,QACA,eACiB;AACjB,QAAO;EACL,GAAG;EACH,QAAQ;GACN,GAAG,QAAQ;GACX,KAAK;IACH,GAAG,QAAQ,QAAQ;IACnB,eAAe,QAAQ,QAAQ,KAAK,iBAAiB;IACtD;GACF;EACF"}
@@ -1,4 +0,0 @@
1
- import type * as t from '@babel/types';
2
- export declare function createRouteHmrStatement(stableRouteOptionKeys: Array<string>, opts?: {
3
- hotExpression?: string;
4
- }): t.Statement;
@@ -1 +0,0 @@
1
- {"version":3,"file":"route-hmr-statement.js","names":[],"sources":["../../../src/core/route-hmr-statement.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport { createHmrHotExpressionAst } from './hmr-hot-expression'\nimport type * as t from '@babel/types'\nimport 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>, 'set'>\n >\n pendingMatchStores: Map<\n string,\n Pick<RouterWritableStore<AnyRouteMatch>, 'set'>\n >\n matchStores: Map<string, Pick<RouterWritableStore<AnyRouteMatch>, 'set'>>\n }\n}\n\ntype AnyRouteMatchWithPrivateProps = AnyRouteMatch & {\n __beforeLoadContext?: 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 // 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 componentKeys.forEach((key) => {\n if (key in oldRoute.options && key in newRoute.options) {\n newRoute.options[key] = oldRoute.options[key]\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 }\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\nconst handleRouteUpdateStr = handleRouteUpdate.toString()\n\nexport function createRouteHmrStatement(\n stableRouteOptionKeys: Array<string>,\n opts?: { hotExpression?: string },\n): t.Statement {\n return template.statement(\n `\nif (%%hotExpression%%) {\n const hot = %%hotExpression%%\n const hotData = hot.data ??= {}\n hot.accept((newModule) => {\n if (Route && newModule && newModule.Route) {\n const routeId = hotData['tsr-route-id'] ?? Route.id\n if (routeId) {\n hotData['tsr-route-id'] = routeId\n }\n (${handleRouteUpdateStr.replace(\n /['\"]__TSR_COMPONENT_TYPES__['\"]/,\n JSON.stringify(stableRouteOptionKeys),\n )})(routeId, newModule.Route)\n }\n })\n}\n`,\n {\n syntacticPlaceholders: true,\n },\n )({\n hotExpression: createHmrHotExpressionAst(opts?.hotExpression),\n })\n}\n"],"mappings":";;;AAyCA,SAAS,kBACP,SACA,UACA;CACA,MAAM,SAAS,OAAO;CACtB,MAAM,WAAW,OAAO,WAAW;AAInC,KAAI,CAAC,SACH;CAYF,MAAM,8BAAc,IAAI,KAAa;AACrC,QAAO,KAAK,SAAS,QAAQ,CAAC,SAAS,QAAQ;AAC7C,MAAI,EAAE,OAAO,SAAS,UAAU;AAC9B,eAAY,IAAI,IAAI;AACpB,UAAO,SAAS,QAAQ;;GAE1B;AAIoB,2BACR,SAAS,QAAQ;AAC7B,MAAI,OAAO,SAAS,WAAW,OAAO,SAAS,QAC7C,UAAS,QAAQ,OAAO,SAAS,QAAQ;GAE3C;AAEF,UAAS,UAAU,SAAS;AAC5B,UAAS,OAAO,SAAS,QAAQ;AACjC,UAAS,qBAAqB,KAAA;AAC9B,UAAS,eAAe,KAAA;AAExB,QAAO,WAAW,SAAS,MAAM;AACjC,QAAO,aAAa,SAAS,YAAY;AAEzC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,YAAY,OAAO;AACxC,QAAO,iBAAiB,OAAO;AAC/B,wBAAuB,UAAU,OAAO,cAAc,YAAY;CAElE,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,CAC/B,MAAK,sBAAsB,KAAA;AAG7B,aAAO;OACP;;KAGN;;AAGJ,SAAO,WAAW;GAAE;GAAQ,MAAM;GAAM,CAAC;;CAG3C,SAAS,uBACP,OACA,MACA;AACA,MAAI,KAAK,OAAO,OAAO,MAAM,GAAI,MAAK,QAAQ;AAC9C,MAAI,KAAK,MAAO,wBAAuB,OAAO,KAAK,MAAM;AACzD,OAAK,QAAQ,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACrE,OAAK,mBAAmB,SAAS,UAC/B,uBAAuB,OAAO,MAAM,CACrC;AACD,OAAK,SAAS,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACtE,OAAK,UAAU,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;AACvE,OAAK,UAAU,SAAS,UAAU,uBAAuB,OAAO,MAAM,CAAC;;;AAI3E,IAAM,uBAAuB,kBAAkB,UAAU;AAEzD,SAAgB,wBACd,uBACA,MACa;AACb,QAAO,SAAS,UACd;;;;;;;;;;SAUK,qBAAqB,QACtB,mCACA,KAAK,UAAU,sBAAsB,CACtC,CAAC;;;;GAKJ,EACE,uBAAuB,MACxB,CACF,CAAC,EACA,eAAe,0BAA0B,MAAM,cAAc,EAC9D,CAAC"}
@@ -1,31 +0,0 @@
1
- import * as template from '@babel/template'
2
- import type * as t from '@babel/types'
3
- import type { Config } from './config'
4
-
5
- export const DEFAULT_HMR_HOT_EXPRESSION = 'import.meta.hot'
6
-
7
- export function resolveHmrHotExpression(hotExpression?: string): string {
8
- return hotExpression ?? DEFAULT_HMR_HOT_EXPRESSION
9
- }
10
-
11
- export function createHmrHotExpressionAst(
12
- hotExpression?: string,
13
- ): t.Expression {
14
- return template.expression.ast(resolveHmrHotExpression(hotExpression))
15
- }
16
-
17
- export function withHmrHotExpression(
18
- config: Partial<Config> | undefined,
19
- hotExpression: string,
20
- ): Partial<Config> {
21
- return {
22
- ...config,
23
- plugin: {
24
- ...config?.plugin,
25
- hmr: {
26
- ...config?.plugin?.hmr,
27
- hotExpression: config?.plugin?.hmr?.hotExpression ?? hotExpression,
28
- },
29
- },
30
- }
31
- }