@tanstack/router-plugin 1.167.2 → 1.167.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/cjs/core/code-splitter/compilers.cjs +28 -21
  2. package/dist/cjs/core/code-splitter/compilers.cjs.map +1 -1
  3. package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs +6 -1
  4. package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs.map +1 -1
  5. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs +49 -0
  6. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs.map +1 -0
  7. package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.d.cts +2 -0
  8. package/dist/cjs/core/code-splitter/plugins/react-refresh-route-components.cjs +24 -12
  9. package/dist/cjs/core/code-splitter/plugins/react-refresh-route-components.cjs.map +1 -1
  10. package/dist/cjs/core/code-splitter/plugins.d.cts +2 -0
  11. package/dist/cjs/core/route-hmr-statement.cjs +58 -15
  12. package/dist/cjs/core/route-hmr-statement.cjs.map +1 -1
  13. package/dist/cjs/core/route-hmr-statement.d.cts +1 -1
  14. package/dist/cjs/core/router-code-splitter-plugin.cjs +3 -3
  15. package/dist/cjs/core/router-code-splitter-plugin.cjs.map +1 -1
  16. package/dist/cjs/core/router-hmr-plugin.cjs +2 -2
  17. package/dist/cjs/core/router-hmr-plugin.cjs.map +1 -1
  18. package/dist/cjs/core/utils.cjs +6 -0
  19. package/dist/cjs/core/utils.cjs.map +1 -1
  20. package/dist/cjs/core/utils.d.cts +1 -0
  21. package/dist/esm/core/code-splitter/compilers.js +23 -16
  22. package/dist/esm/core/code-splitter/compilers.js.map +1 -1
  23. package/dist/esm/core/code-splitter/plugins/framework-plugins.js +6 -1
  24. package/dist/esm/core/code-splitter/plugins/framework-plugins.js.map +1 -1
  25. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.d.ts +2 -0
  26. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js +46 -0
  27. package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js.map +1 -0
  28. package/dist/esm/core/code-splitter/plugins/react-refresh-route-components.js +25 -13
  29. package/dist/esm/core/code-splitter/plugins/react-refresh-route-components.js.map +1 -1
  30. package/dist/esm/core/code-splitter/plugins.d.ts +2 -0
  31. package/dist/esm/core/route-hmr-statement.d.ts +1 -1
  32. package/dist/esm/core/route-hmr-statement.js +58 -15
  33. package/dist/esm/core/route-hmr-statement.js.map +1 -1
  34. package/dist/esm/core/router-code-splitter-plugin.js +3 -3
  35. package/dist/esm/core/router-code-splitter-plugin.js.map +1 -1
  36. package/dist/esm/core/router-hmr-plugin.js +3 -3
  37. package/dist/esm/core/router-hmr-plugin.js.map +1 -1
  38. package/dist/esm/core/utils.d.ts +1 -0
  39. package/dist/esm/core/utils.js +6 -1
  40. package/dist/esm/core/utils.js.map +1 -1
  41. package/package.json +4 -4
  42. package/src/core/code-splitter/compilers.ts +47 -25
  43. package/src/core/code-splitter/plugins/framework-plugins.ts +2 -0
  44. package/src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts +65 -0
  45. package/src/core/code-splitter/plugins/react-refresh-route-components.ts +68 -39
  46. package/src/core/code-splitter/plugins.ts +4 -0
  47. package/src/core/route-hmr-statement.ts +141 -25
  48. package/src/core/router-code-splitter-plugin.ts +2 -2
  49. package/src/core/router-hmr-plugin.ts +7 -6
  50. package/src/core/utils.ts +18 -0
@@ -1,10 +1,15 @@
1
+ const require_react_refresh_ignored_route_exports = require("./react-refresh-ignored-route-exports.cjs");
1
2
  const require_react_refresh_route_components = require("./react-refresh-route-components.cjs");
2
3
  const require_react_stable_hmr_split_route_components = require("./react-stable-hmr-split-route-components.cjs");
3
4
  //#region src/core/code-splitter/plugins/framework-plugins.ts
4
5
  function getReferenceRouteCompilerPlugins(opts) {
5
6
  switch (opts.targetFramework) {
6
7
  case "react":
7
- if (opts.addHmr) return [require_react_refresh_route_components.createReactRefreshRouteComponentsPlugin(), require_react_stable_hmr_split_route_components.createReactStableHmrSplitRouteComponentsPlugin()];
8
+ if (opts.addHmr) return [
9
+ require_react_refresh_ignored_route_exports.createReactRefreshIgnoredRouteExportsPlugin(),
10
+ require_react_refresh_route_components.createReactRefreshRouteComponentsPlugin(),
11
+ require_react_stable_hmr_split_route_components.createReactStableHmrSplitRouteComponentsPlugin()
12
+ ];
8
13
  return;
9
14
  default: return;
10
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"framework-plugins.cjs","names":[],"sources":["../../../../../src/core/code-splitter/plugins/framework-plugins.ts"],"sourcesContent":["import { createReactRefreshRouteComponentsPlugin } from './react-refresh-route-components'\nimport { createReactStableHmrSplitRouteComponentsPlugin } from './react-stable-hmr-split-route-components'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\nimport type { Config } from '../../config'\n\nexport function getReferenceRouteCompilerPlugins(opts: {\n targetFramework: Config['target']\n addHmr?: boolean\n}): Array<ReferenceRouteCompilerPlugin> | undefined {\n switch (opts.targetFramework) {\n case 'react': {\n if (opts.addHmr) {\n return [\n createReactRefreshRouteComponentsPlugin(),\n createReactStableHmrSplitRouteComponentsPlugin(),\n ]\n }\n return undefined\n }\n default:\n return undefined\n }\n}\n"],"mappings":";;;AAKA,SAAgB,iCAAiC,MAGG;AAClD,SAAQ,KAAK,iBAAb;EACE,KAAK;AACH,OAAI,KAAK,OACP,QAAO,CACL,uCAAA,yCAAyC,EACzC,gDAAA,gDAAgD,CACjD;AAEH;EAEF,QACE"}
1
+ {"version":3,"file":"framework-plugins.cjs","names":[],"sources":["../../../../../src/core/code-splitter/plugins/framework-plugins.ts"],"sourcesContent":["import { createReactRefreshIgnoredRouteExportsPlugin } from './react-refresh-ignored-route-exports'\nimport { createReactRefreshRouteComponentsPlugin } from './react-refresh-route-components'\nimport { createReactStableHmrSplitRouteComponentsPlugin } from './react-stable-hmr-split-route-components'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\nimport type { Config } from '../../config'\n\nexport function getReferenceRouteCompilerPlugins(opts: {\n targetFramework: Config['target']\n addHmr?: boolean\n}): Array<ReferenceRouteCompilerPlugin> | undefined {\n switch (opts.targetFramework) {\n case 'react': {\n if (opts.addHmr) {\n return [\n createReactRefreshIgnoredRouteExportsPlugin(),\n createReactRefreshRouteComponentsPlugin(),\n createReactStableHmrSplitRouteComponentsPlugin(),\n ]\n }\n return undefined\n }\n default:\n return undefined\n }\n}\n"],"mappings":";;;;AAMA,SAAgB,iCAAiC,MAGG;AAClD,SAAQ,KAAK,iBAAb;EACE,KAAK;AACH,OAAI,KAAK,OACP,QAAO;IACL,4CAAA,6CAA6C;IAC7C,uCAAA,yCAAyC;IACzC,gDAAA,gDAAgD;IACjD;AAEH;EAEF,QACE"}
@@ -0,0 +1,49 @@
1
+ const require_runtime = require("../../../_virtual/_rolldown/runtime.cjs");
2
+ const require_utils = require("../../utils.cjs");
3
+ let _babel_types = require("@babel/types");
4
+ _babel_types = require_runtime.__toESM(_babel_types);
5
+ let _babel_template = require("@babel/template");
6
+ _babel_template = require_runtime.__toESM(_babel_template);
7
+ //#region src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts
8
+ var buildReactRefreshIgnoredRouteExportsStatement = _babel_template.statement(`
9
+ if (import.meta.hot && typeof window !== 'undefined') {
10
+ const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {
11
+ const ignoredExportsById = new Map()
12
+ const previousGetIgnoredExports = window.__getReactRefreshIgnoredExports
13
+
14
+ window.__getReactRefreshIgnoredExports = (ctx) => {
15
+ const ignoredExports = previousGetIgnoredExports?.(ctx) ?? []
16
+ const moduleIgnored = ignoredExportsById.get(ctx.id) ?? []
17
+ return [...ignoredExports, ...moduleIgnored]
18
+ }
19
+
20
+ return {
21
+ ignoredExportsById,
22
+ }
23
+ })()
24
+
25
+ tsrReactRefresh.ignoredExportsById.set(%%moduleId%%, ['Route'])
26
+ }
27
+ `, { syntacticPlaceholders: true });
28
+ /**
29
+ * A trivial component-shaped export that gives `@vitejs/plugin-react` a valid
30
+ * Fast Refresh boundary. Without at least one non-ignored component export,
31
+ * the module would be invalidated (full page reload) on every update even
32
+ * though our custom route HMR handler already manages the update.
33
+ */
34
+ var buildRefreshAnchorStatement = _babel_template.statement(`export function %%anchorName%%() { return null }`, { syntacticPlaceholders: true });
35
+ function createReactRefreshIgnoredRouteExportsPlugin() {
36
+ return {
37
+ name: "react-refresh-ignored-route-exports",
38
+ onAddHmr(ctx) {
39
+ const anchorName = require_utils.getUniqueProgramIdentifier(ctx.programPath, "TSRFastRefreshAnchor");
40
+ ctx.programPath.pushContainer("body", buildReactRefreshIgnoredRouteExportsStatement({ moduleId: _babel_types.stringLiteral(ctx.opts.id) }));
41
+ ctx.programPath.pushContainer("body", buildRefreshAnchorStatement({ anchorName }));
42
+ return { modified: true };
43
+ }
44
+ };
45
+ }
46
+ //#endregion
47
+ exports.createReactRefreshIgnoredRouteExportsPlugin = createReactRefreshIgnoredRouteExportsPlugin;
48
+
49
+ //# sourceMappingURL=react-refresh-ignored-route-exports.cjs.map
@@ -0,0 +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 buildReactRefreshIgnoredRouteExportsStatement = template.statement(\n `\nif (import.meta.hot && typeof window !== 'undefined') {\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 buildReactRefreshIgnoredRouteExportsStatement({\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,gDAAgD,gBAAS,UAC7D;;;;;;;;;;;;;;;;;;;GAoBA,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,8CAA8C,EAC5C,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"}
@@ -0,0 +1,2 @@
1
+ import { ReferenceRouteCompilerPlugin } from '../plugins.cjs';
2
+ export declare function createReactRefreshIgnoredRouteExportsPlugin(): ReferenceRouteCompilerPlugin;
@@ -5,27 +5,39 @@ _babel_types = require_runtime.__toESM(_babel_types);
5
5
  //#region src/core/code-splitter/plugins/react-refresh-route-components.ts
6
6
  var REACT_REFRESH_ROUTE_COMPONENT_IDENTS = new Set([
7
7
  "component",
8
+ "shellComponent",
8
9
  "pendingComponent",
9
10
  "errorComponent",
10
11
  "notFoundComponent"
11
12
  ]);
13
+ function hoistInlineRouteComponents(ctx) {
14
+ const hoistedDeclarations = [];
15
+ ctx.routeOptions.properties.forEach((prop) => {
16
+ if (!_babel_types.isObjectProperty(prop)) return;
17
+ const key = require_utils.getObjectPropertyKeyName(prop);
18
+ if (!key || !REACT_REFRESH_ROUTE_COMPONENT_IDENTS.has(key)) return;
19
+ if (!_babel_types.isArrowFunctionExpression(prop.value) && !_babel_types.isFunctionExpression(prop.value)) return;
20
+ const hoistedIdentifier = require_utils.getUniqueProgramIdentifier(ctx.programPath, `TSR${key[0].toUpperCase()}${key.slice(1)}`);
21
+ hoistedDeclarations.push(_babel_types.variableDeclaration("const", [_babel_types.variableDeclarator(hoistedIdentifier, _babel_types.cloneNode(prop.value, true))]));
22
+ prop.value = _babel_types.cloneNode(hoistedIdentifier);
23
+ });
24
+ if (hoistedDeclarations.length === 0) return false;
25
+ ctx.insertionPath.insertBefore(hoistedDeclarations);
26
+ return true;
27
+ }
12
28
  function createReactRefreshRouteComponentsPlugin() {
13
29
  return {
14
30
  name: "react-refresh-route-components",
31
+ getStableRouteOptionKeys() {
32
+ return [...REACT_REFRESH_ROUTE_COMPONENT_IDENTS];
33
+ },
15
34
  onUnsplittableRoute(ctx) {
16
35
  if (!ctx.opts.addHmr) return;
17
- const hoistedDeclarations = [];
18
- ctx.routeOptions.properties.forEach((prop) => {
19
- if (!_babel_types.isObjectProperty(prop) || !_babel_types.isIdentifier(prop.key)) return;
20
- if (!REACT_REFRESH_ROUTE_COMPONENT_IDENTS.has(prop.key.name)) return;
21
- if (!_babel_types.isArrowFunctionExpression(prop.value) && !_babel_types.isFunctionExpression(prop.value)) return;
22
- const hoistedIdentifier = require_utils.getUniqueProgramIdentifier(ctx.programPath, `TSR${prop.key.name[0].toUpperCase()}${prop.key.name.slice(1)}`);
23
- hoistedDeclarations.push(_babel_types.variableDeclaration("const", [_babel_types.variableDeclarator(hoistedIdentifier, _babel_types.cloneNode(prop.value, true))]));
24
- prop.value = _babel_types.cloneNode(hoistedIdentifier);
25
- });
26
- if (hoistedDeclarations.length === 0) return;
27
- ctx.insertionPath.insertBefore(hoistedDeclarations);
28
- return { modified: true };
36
+ if (hoistInlineRouteComponents(ctx)) return { modified: true };
37
+ },
38
+ onAddHmr(ctx) {
39
+ if (!ctx.opts.addHmr) return;
40
+ if (hoistInlineRouteComponents(ctx)) return { modified: true };
29
41
  }
30
42
  };
31
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"react-refresh-route-components.cjs","names":[],"sources":["../../../../../src/core/code-splitter/plugins/react-refresh-route-components.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport { getUniqueProgramIdentifier } from '../../utils'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\n\nconst REACT_REFRESH_ROUTE_COMPONENT_IDENTS = new Set([\n 'component',\n 'pendingComponent',\n 'errorComponent',\n 'notFoundComponent',\n])\n\nexport function createReactRefreshRouteComponentsPlugin(): ReferenceRouteCompilerPlugin {\n return {\n name: 'react-refresh-route-components',\n onUnsplittableRoute(ctx) {\n if (!ctx.opts.addHmr) {\n return\n }\n\n const hoistedDeclarations: Array<t.VariableDeclaration> = []\n\n ctx.routeOptions.properties.forEach((prop) => {\n if (!t.isObjectProperty(prop) || !t.isIdentifier(prop.key)) {\n return\n }\n\n if (!REACT_REFRESH_ROUTE_COMPONENT_IDENTS.has(prop.key.name)) {\n return\n }\n\n if (\n !t.isArrowFunctionExpression(prop.value) &&\n !t.isFunctionExpression(prop.value)\n ) {\n return\n }\n\n const hoistedIdentifier = getUniqueProgramIdentifier(\n ctx.programPath,\n `TSR${prop.key.name[0]!.toUpperCase()}${prop.key.name.slice(1)}`,\n )\n\n hoistedDeclarations.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n hoistedIdentifier,\n t.cloneNode(prop.value, true),\n ),\n ]),\n )\n\n prop.value = t.cloneNode(hoistedIdentifier)\n })\n\n if (hoistedDeclarations.length === 0) {\n return\n }\n\n ctx.insertionPath.insertBefore(hoistedDeclarations)\n return { modified: true }\n },\n }\n}\n"],"mappings":";;;;;AAIA,IAAM,uCAAuC,IAAI,IAAI;CACnD;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAgB,0CAAwE;AACtF,QAAO;EACL,MAAM;EACN,oBAAoB,KAAK;AACvB,OAAI,CAAC,IAAI,KAAK,OACZ;GAGF,MAAM,sBAAoD,EAAE;AAE5D,OAAI,aAAa,WAAW,SAAS,SAAS;AAC5C,QAAI,CAAC,aAAE,iBAAiB,KAAK,IAAI,CAAC,aAAE,aAAa,KAAK,IAAI,CACxD;AAGF,QAAI,CAAC,qCAAqC,IAAI,KAAK,IAAI,KAAK,CAC1D;AAGF,QACE,CAAC,aAAE,0BAA0B,KAAK,MAAM,IACxC,CAAC,aAAE,qBAAqB,KAAK,MAAM,CAEnC;IAGF,MAAM,oBAAoB,cAAA,2BACxB,IAAI,aACJ,MAAM,KAAK,IAAI,KAAK,GAAI,aAAa,GAAG,KAAK,IAAI,KAAK,MAAM,EAAE,GAC/D;AAED,wBAAoB,KAClB,aAAE,oBAAoB,SAAS,CAC7B,aAAE,mBACA,mBACA,aAAE,UAAU,KAAK,OAAO,KAAK,CAC9B,CACF,CAAC,CACH;AAED,SAAK,QAAQ,aAAE,UAAU,kBAAkB;KAC3C;AAEF,OAAI,oBAAoB,WAAW,EACjC;AAGF,OAAI,cAAc,aAAa,oBAAoB;AACnD,UAAO,EAAE,UAAU,MAAM;;EAE5B"}
1
+ {"version":3,"file":"react-refresh-route-components.cjs","names":[],"sources":["../../../../../src/core/code-splitter/plugins/react-refresh-route-components.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport {\n getObjectPropertyKeyName,\n getUniqueProgramIdentifier,\n} from '../../utils'\nimport type { ReferenceRouteCompilerPlugin } from '../plugins'\n\nconst REACT_REFRESH_ROUTE_COMPONENT_IDENTS = new Set([\n 'component',\n 'shellComponent',\n 'pendingComponent',\n 'errorComponent',\n 'notFoundComponent',\n])\n\nfunction hoistInlineRouteComponents(ctx: {\n programPath: Parameters<typeof getUniqueProgramIdentifier>[0]\n insertionPath: { insertBefore: (nodes: Array<t.VariableDeclaration>) => void }\n routeOptions: t.ObjectExpression\n}) {\n const hoistedDeclarations: Array<t.VariableDeclaration> = []\n\n ctx.routeOptions.properties.forEach((prop) => {\n if (!t.isObjectProperty(prop)) {\n return\n }\n\n const key = getObjectPropertyKeyName(prop)\n\n if (!key || !REACT_REFRESH_ROUTE_COMPONENT_IDENTS.has(key)) {\n return\n }\n\n if (\n !t.isArrowFunctionExpression(prop.value) &&\n !t.isFunctionExpression(prop.value)\n ) {\n return\n }\n\n const hoistedIdentifier = getUniqueProgramIdentifier(\n ctx.programPath,\n `TSR${key[0]!.toUpperCase()}${key.slice(1)}`,\n )\n\n hoistedDeclarations.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(hoistedIdentifier, t.cloneNode(prop.value, true)),\n ]),\n )\n\n prop.value = t.cloneNode(hoistedIdentifier)\n })\n\n if (hoistedDeclarations.length === 0) {\n return false\n }\n\n ctx.insertionPath.insertBefore(hoistedDeclarations)\n return true\n}\n\nexport function createReactRefreshRouteComponentsPlugin(): ReferenceRouteCompilerPlugin {\n return {\n name: 'react-refresh-route-components',\n getStableRouteOptionKeys() {\n return [...REACT_REFRESH_ROUTE_COMPONENT_IDENTS]\n },\n onUnsplittableRoute(ctx) {\n if (!ctx.opts.addHmr) {\n return\n }\n\n if (hoistInlineRouteComponents(ctx)) {\n return { modified: true }\n }\n\n return\n },\n onAddHmr(ctx) {\n if (!ctx.opts.addHmr) {\n return\n }\n\n if (hoistInlineRouteComponents(ctx)) {\n return { modified: true }\n }\n\n return\n },\n }\n}\n"],"mappings":";;;;;AAOA,IAAM,uCAAuC,IAAI,IAAI;CACnD;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,2BAA2B,KAIjC;CACD,MAAM,sBAAoD,EAAE;AAE5D,KAAI,aAAa,WAAW,SAAS,SAAS;AAC5C,MAAI,CAAC,aAAE,iBAAiB,KAAK,CAC3B;EAGF,MAAM,MAAM,cAAA,yBAAyB,KAAK;AAE1C,MAAI,CAAC,OAAO,CAAC,qCAAqC,IAAI,IAAI,CACxD;AAGF,MACE,CAAC,aAAE,0BAA0B,KAAK,MAAM,IACxC,CAAC,aAAE,qBAAqB,KAAK,MAAM,CAEnC;EAGF,MAAM,oBAAoB,cAAA,2BACxB,IAAI,aACJ,MAAM,IAAI,GAAI,aAAa,GAAG,IAAI,MAAM,EAAE,GAC3C;AAED,sBAAoB,KAClB,aAAE,oBAAoB,SAAS,CAC7B,aAAE,mBAAmB,mBAAmB,aAAE,UAAU,KAAK,OAAO,KAAK,CAAC,CACvE,CAAC,CACH;AAED,OAAK,QAAQ,aAAE,UAAU,kBAAkB;GAC3C;AAEF,KAAI,oBAAoB,WAAW,EACjC,QAAO;AAGT,KAAI,cAAc,aAAa,oBAAoB;AACnD,QAAO;;AAGT,SAAgB,0CAAwE;AACtF,QAAO;EACL,MAAM;EACN,2BAA2B;AACzB,UAAO,CAAC,GAAG,qCAAqC;;EAElD,oBAAoB,KAAK;AACvB,OAAI,CAAC,IAAI,KAAK,OACZ;AAGF,OAAI,2BAA2B,IAAI,CACjC,QAAO,EAAE,UAAU,MAAM;;EAK7B,SAAS,KAAK;AACZ,OAAI,CAAC,IAAI,KAAK,OACZ;AAGF,OAAI,2BAA2B,IAAI,CACjC,QAAO,EAAE,UAAU,MAAM;;EAK9B"}
@@ -34,6 +34,8 @@ export type ReferenceRouteCompilerPluginResult = {
34
34
  };
35
35
  export type ReferenceRouteCompilerPlugin = {
36
36
  name: string;
37
+ getStableRouteOptionKeys?: () => Array<string>;
38
+ onAddHmr?: (ctx: ReferenceRouteCompilerPluginContext) => void | ReferenceRouteCompilerPluginResult;
37
39
  onUnsplittableRoute?: (ctx: ReferenceRouteCompilerPluginContext) => void | ReferenceRouteCompilerPluginResult;
38
40
  onSplitRouteProperty?: (ctx: ReferenceRouteSplitPropertyCompilerPluginContext) => void | t.Expression;
39
41
  };
@@ -2,23 +2,59 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
2
  let _babel_template = require("@babel/template");
3
3
  _babel_template = require_runtime.__toESM(_babel_template);
4
4
  //#region src/core/route-hmr-statement.ts
5
- function handleRouteUpdate(oldRoute, newRoute) {
6
- newRoute._path = oldRoute._path;
7
- newRoute._id = oldRoute._id;
8
- newRoute._fullPath = oldRoute._fullPath;
9
- newRoute._to = oldRoute._to;
10
- newRoute.children = oldRoute.children;
11
- newRoute.parentRoute = oldRoute.parentRoute;
5
+ function handleRouteUpdate(routeId, newRoute) {
12
6
  const router = window.__TSR_ROUTER__;
13
- router.routesById[newRoute.id] = newRoute;
14
- router.routesByPath[newRoute.fullPath] = newRoute;
7
+ const oldRoute = router.routesById[routeId];
8
+ if (!oldRoute) return;
9
+ const removedKeys = /* @__PURE__ */ new Set();
10
+ Object.keys(oldRoute.options).forEach((key) => {
11
+ if (!(key in newRoute.options)) {
12
+ removedKeys.add(key);
13
+ delete oldRoute.options[key];
14
+ }
15
+ });
16
+ "__TSR_COMPONENT_TYPES__".forEach((key) => {
17
+ if (key in oldRoute.options && key in newRoute.options) newRoute.options[key] = oldRoute.options[key];
18
+ });
19
+ oldRoute.options = newRoute.options;
20
+ oldRoute.update(newRoute.options);
21
+ oldRoute._componentsPromise = void 0;
22
+ oldRoute._lazyPromise = void 0;
23
+ router.routesById[oldRoute.id] = oldRoute;
24
+ router.routesByPath[oldRoute.fullPath] = oldRoute;
15
25
  router.processedTree.matchCache.clear();
16
26
  router.processedTree.flatCache?.clear();
17
27
  router.processedTree.singleCache.clear();
18
28
  router.resolvePathCache.clear();
19
- walkReplaceSegmentTree(newRoute, router.processedTree.segmentTree);
29
+ walkReplaceSegmentTree(oldRoute, router.processedTree.segmentTree);
20
30
  const filter = (m) => m.routeId === oldRoute.id;
21
- if (router.stores.activeMatchesSnapshot.state.find(filter) || router.stores.pendingMatchesSnapshot.state.find(filter)) router.invalidate({ filter });
31
+ const activeMatch = router.stores.activeMatchesSnapshot.state.find(filter);
32
+ const pendingMatch = router.stores.pendingMatchesSnapshot.state.find(filter);
33
+ const cachedMatches = router.stores.cachedMatchesSnapshot.state.filter(filter);
34
+ if (activeMatch || pendingMatch || cachedMatches.length > 0) {
35
+ if (removedKeys.has("loader") || removedKeys.has("beforeLoad")) {
36
+ const matchIds = [
37
+ activeMatch?.id,
38
+ pendingMatch?.id,
39
+ ...cachedMatches.map((match) => match.id)
40
+ ].filter(Boolean);
41
+ router.batch(() => {
42
+ for (const matchId of matchIds) {
43
+ const store = router.stores.pendingMatchStoresById.get(matchId) || router.stores.activeMatchStoresById.get(matchId) || router.stores.cachedMatchStoresById.get(matchId);
44
+ if (store) store.setState((prev) => {
45
+ const next = { ...prev };
46
+ if (removedKeys.has("loader")) next.loaderData = void 0;
47
+ if (removedKeys.has("beforeLoad")) next.__beforeLoadContext = void 0;
48
+ return next;
49
+ });
50
+ }
51
+ });
52
+ }
53
+ router.invalidate({
54
+ filter,
55
+ sync: true
56
+ });
57
+ }
22
58
  function walkReplaceSegmentTree(route, node) {
23
59
  if (node.route?.id === route.id) node.route = route;
24
60
  if (node.index) walkReplaceSegmentTree(route, node.index);
@@ -29,16 +65,23 @@ function handleRouteUpdate(oldRoute, newRoute) {
29
65
  node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child));
30
66
  }
31
67
  }
32
- var routeHmrStatement = _babel_template.statement(`
68
+ var handleRouteUpdateStr = handleRouteUpdate.toString();
69
+ function createRouteHmrStatement(stableRouteOptionKeys) {
70
+ return _babel_template.statement(`
33
71
  if (import.meta.hot) {
34
72
  import.meta.hot.accept((newModule) => {
35
73
  if (Route && newModule && newModule.Route) {
36
- (${handleRouteUpdate.toString()})(Route, newModule.Route)
74
+ const routeId = import.meta.hot.data['tsr-route-id'] ?? Route.id
75
+ if (routeId) {
76
+ import.meta.hot.data['tsr-route-id'] = routeId
77
+ }
78
+ (${handleRouteUpdateStr.replace(/['"]__TSR_COMPONENT_TYPES__['"]/, JSON.stringify(stableRouteOptionKeys))})(routeId, newModule.Route)
37
79
  }
38
- })
80
+ })
39
81
  }
40
82
  `, { placeholderPattern: false })();
83
+ }
41
84
  //#endregion
42
- exports.routeHmrStatement = routeHmrStatement;
85
+ exports.createRouteHmrStatement = createRouteHmrStatement;
43
86
 
44
87
  //# sourceMappingURL=route-hmr-statement.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"route-hmr-statement.cjs","names":[],"sources":["../../../src/core/route-hmr-statement.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport type { AnyRoute, AnyRouteMatch, AnyRouter } from '@tanstack/router-core'\n\ntype AnyRouteWithPrivateProps = AnyRoute & {\n _path: string\n _id: string\n _fullPath: string\n _to: string\n}\n\nfunction handleRouteUpdate(\n oldRoute: AnyRouteWithPrivateProps,\n newRoute: AnyRouteWithPrivateProps,\n) {\n newRoute._path = oldRoute._path\n newRoute._id = oldRoute._id\n newRoute._fullPath = oldRoute._fullPath\n newRoute._to = oldRoute._to\n newRoute.children = oldRoute.children\n newRoute.parentRoute = oldRoute.parentRoute\n\n const router = window.__TSR_ROUTER__!\n router.routesById[newRoute.id] = newRoute\n router.routesByPath[newRoute.fullPath] = newRoute\n router.processedTree.matchCache.clear()\n router.processedTree.flatCache?.clear()\n router.processedTree.singleCache.clear()\n router.resolvePathCache.clear()\n // TODO: how to rebuild the tree if we add a new route?\n walkReplaceSegmentTree(newRoute, router.processedTree.segmentTree)\n const filter = (m: AnyRouteMatch) => m.routeId === oldRoute.id\n if (\n router.stores.activeMatchesSnapshot.state.find(filter) ||\n router.stores.pendingMatchesSnapshot.state.find(filter)\n ) {\n router.invalidate({ filter })\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\nexport const routeHmrStatement = template.statement(\n `\nif (import.meta.hot) {\n import.meta.hot.accept((newModule) => {\n if (Route && newModule && newModule.Route) {\n (${handleRouteUpdate.toString()})(Route, newModule.Route)\n }\n })\n}\n`,\n // Disable placeholder parsing so identifiers like __TSR_ROUTER__ are treated as normal identifiers instead of template placeholders\n { placeholderPattern: false },\n)()\n"],"mappings":";;;;AAUA,SAAS,kBACP,UACA,UACA;AACA,UAAS,QAAQ,SAAS;AAC1B,UAAS,MAAM,SAAS;AACxB,UAAS,YAAY,SAAS;AAC9B,UAAS,MAAM,SAAS;AACxB,UAAS,WAAW,SAAS;AAC7B,UAAS,cAAc,SAAS;CAEhC,MAAM,SAAS,OAAO;AACtB,QAAO,WAAW,SAAS,MAAM;AACjC,QAAO,aAAa,SAAS,YAAY;AACzC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,WAAW,OAAO;AACvC,QAAO,cAAc,YAAY,OAAO;AACxC,QAAO,iBAAiB,OAAO;AAE/B,wBAAuB,UAAU,OAAO,cAAc,YAAY;CAClE,MAAM,UAAU,MAAqB,EAAE,YAAY,SAAS;AAC5D,KACE,OAAO,OAAO,sBAAsB,MAAM,KAAK,OAAO,IACtD,OAAO,OAAO,uBAAuB,MAAM,KAAK,OAAO,CAEvD,QAAO,WAAW,EAAE,QAAQ,CAAC;CAE/B,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,IAAa,oBAAoB,gBAAS,UACxC;;;;SAIO,kBAAkB,UAAU,CAAC;;;;GAMpC,EAAE,oBAAoB,OAAO,CAC9B,EAAE"}
1
+ {"version":3,"file":"route-hmr-statement.cjs","names":[],"sources":["../../../src/core/route-hmr-statement.ts"],"sourcesContent":["import * as template from '@babel/template'\nimport type { AnyRoute, AnyRouteMatch, AnyRouter } 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 cachedMatchStoresById: Map<\n string,\n {\n setState: (updater: (prev: AnyRouteMatch) => AnyRouteMatch) => void\n }\n >\n pendingMatchStoresById: Map<\n string,\n {\n setState: (updater: (prev: AnyRouteMatch) => AnyRouteMatch) => void\n }\n >\n activeMatchStoresById: Map<\n string,\n {\n setState: (updater: (prev: AnyRouteMatch) => AnyRouteMatch) => void\n }\n >\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 import.meta.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.activeMatchesSnapshot.state.find(filter)\n const pendingMatch = router.stores.pendingMatchesSnapshot.state.find(filter)\n const cachedMatches = router.stores.cachedMatchesSnapshot.state.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.pendingMatchStoresById.get(matchId) ||\n router.stores.activeMatchStoresById.get(matchId) ||\n router.stores.cachedMatchStoresById.get(matchId)\n if (store) {\n store.setState((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(stableRouteOptionKeys: Array<string>) {\n return template.statement(\n `\nif (import.meta.hot) {\n import.meta.hot.accept((newModule) => {\n if (Route && newModule && newModule.Route) {\n const routeId = import.meta.hot.data['tsr-route-id'] ?? Route.id\n if (routeId) {\n import.meta.hot.data['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 { placeholderPattern: false },\n )()\n}\n"],"mappings":";;;;AA2CA,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,sBAAsB,MAAM,KAAK,OAAO;CAC1E,MAAM,eAAe,OAAO,OAAO,uBAAuB,MAAM,KAAK,OAAO;CAC5E,MAAM,gBAAgB,OAAO,OAAO,sBAAsB,MAAM,OAAO,OAAO;AAE9E,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,uBAAuB,IAAI,QAAQ,IACjD,OAAO,OAAO,sBAAsB,IAAI,QAAQ,IAChD,OAAO,OAAO,sBAAsB,IAAI,QAAQ;AAClD,SAAI,MACF,OAAM,UAAU,SAAS;MACvB,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,wBAAwB,uBAAsC;AAC5E,QAAO,gBAAS,UACd;;;;;;;;SAQK,qBAAqB,QACtB,mCACA,KAAK,UAAU,sBAAsB,CACtC,CAAC;;;;GAKJ,EAAE,oBAAoB,OAAO,CAC9B,EAAE"}
@@ -1 +1 @@
1
- export declare const routeHmrStatement: import('@babel/types').Statement;
1
+ export declare function createRouteHmrStatement(stableRouteOptionKeys: Array<string>): import('@babel/types').Statement;
@@ -1,9 +1,9 @@
1
1
  require("../_virtual/_rolldown/runtime.cjs");
2
2
  const require_config = require("./config.cjs");
3
3
  const require_constants = require("./constants.cjs");
4
+ const require_utils = require("./utils.cjs");
4
5
  const require_path_ids = require("./code-splitter/path-ids.cjs");
5
6
  const require_compilers = require("./code-splitter/compilers.cjs");
6
- const require_utils = require("./utils.cjs");
7
7
  const require_framework_plugins = require("./code-splitter/plugins/framework-plugins.cjs");
8
8
  let node_url = require("node:url");
9
9
  let _tanstack_router_utils = require("@tanstack/router-utils");
@@ -60,7 +60,7 @@ var unpluginRouterCodeSplitterFactory = (options = {}, { framework: _framework }
60
60
  const handleCompilingReferenceFile = (code, id, generatorNodeInfo) => {
61
61
  if (require_utils.debug) console.info("Compiling Route: ", id);
62
62
  const fromCode = require_compilers.detectCodeSplitGroupingsFromRoute({ code });
63
- if (fromCode.groupings) {
63
+ if (fromCode.groupings !== void 0) {
64
64
  const res = require_config.splitGroupingsSchema.safeParse(fromCode.groupings);
65
65
  if (!res.success) {
66
66
  const message = res.error.errors.map((e) => e.message).join(". ");
@@ -75,7 +75,7 @@ var unpluginRouterCodeSplitterFactory = (options = {}, { framework: _framework }
75
75
  throw new Error(`The groupings returned when using \`splitBehavior\` for the route "${id}" are invalid.\n${message}`);
76
76
  }
77
77
  }
78
- const splitGroupings = fromCode.groupings || pluginSplitBehavior || getGlobalCodeSplitGroupings();
78
+ const splitGroupings = fromCode.groupings ?? pluginSplitBehavior ?? getGlobalCodeSplitGroupings();
79
79
  const sharedBindings = require_compilers.computeSharedBindings({
80
80
  code,
81
81
  codeSplitGroupings: splitGroupings
@@ -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 type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst PLUGIN_NAME = 'unplugin:router-code-splitter'\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 const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}, { framework: _framework }) => {\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 })\n\n if (fromCode.groupings) {\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.routePath,\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 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\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 sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: userConfig.target,\n addHmr,\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 globalThis.TSR_ROUTES_BY_ID_MAP?.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(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\n },\n\n webpack(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\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"],"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 } from './utils'\nimport type { CodeSplitGroupings, SplitRouteIdentNodes } from './constants'\nimport type { GetRoutesByFileMapResultValue } from '@tanstack/router-generator'\nimport type { Config } from './config'\nimport type {\n UnpluginFactory,\n TransformResult as UnpluginTransformResult,\n} from 'unplugin'\n\nconst PLUGIN_NAME = 'unplugin:router-code-splitter'\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 const unpluginRouterCodeSplitterFactory: UnpluginFactory<\n Partial<Config | (() => Config)> | undefined\n> = (options = {}, { framework: _framework }) => {\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 })\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.routePath,\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 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\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 sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: userConfig.target,\n addHmr,\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 globalThis.TSR_ROUTES_BY_ID_MAP?.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(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\n },\n\n webpack(compiler) {\n ROOT = process.cwd()\n initUserConfig()\n\n if (compiler.options.mode === 'production') {\n compiler.hooks.done.tap(PLUGIN_NAME, () => {\n console.info('✅ ' + PLUGIN_NAME + ': code-splitting done!')\n })\n }\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"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  require("../_virtual/_rolldown/runtime.cjs");
2
2
  const require_config = require("./config.cjs");
3
3
  const require_route_hmr_statement = require("./route-hmr-statement.cjs");
4
- const require_compilers = require("./code-splitter/compilers.cjs");
5
4
  const require_utils = require("./utils.cjs");
5
+ const require_compilers = require("./code-splitter/compilers.cjs");
6
6
  const require_framework_plugins = require("./code-splitter/plugins/framework-plugins.cjs");
7
7
  let _tanstack_router_utils = require("@tanstack/router-utils");
8
8
  //#region src/core/router-hmr-plugin.ts
@@ -53,7 +53,7 @@ var unpluginRouterHmrFactory = (options = {}) => {
53
53
  }
54
54
  }
55
55
  const ast = (0, _tanstack_router_utils.parseAst)({ code });
56
- ast.program.body.push(require_route_hmr_statement.routeHmrStatement);
56
+ ast.program.body.push(require_route_hmr_statement.createRouteHmrStatement([]));
57
57
  const result = (0, _tanstack_router_utils.generateFromAst)(ast, {
58
58
  sourceMaps: true,
59
59
  filename: normalizedId,
@@ -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 { routeHmrStatement } from './route-hmr-statement'\nimport { debug, normalizePath } from './utils'\nimport { getConfig } from './config'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\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]\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n let ROOT: string = process.cwd()\n let userConfig = options as Config\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 if (!globalThis.TSR_ROUTES_BY_ID_MAP?.has(normalizedId)) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n if (userConfig.target === 'react') {\n const compiled = compileCodeSplitReferenceRoute({\n code,\n filename: normalizedId,\n id: normalizedId,\n addHmr: true,\n codeSplitGroupings: [],\n targetFramework: 'react',\n compilerPlugins: getReferenceRouteCompilerPlugins({\n targetFramework: 'react',\n addHmr: true,\n }),\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 })\n ast.program.body.push(routeHmrStatement)\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 = getConfig(options, ROOT)\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"],"mappings":";;;;;;;;;;;;;AAeA,IAAM,cAAc;CAClB;CACA;CACA;CACD;AACD,IAAa,4BAER,UAAU,EAAE,KAAK;CACpB,IAAI,OAAe,QAAQ,KAAK;CAChC,IAAI,aAAa;AAEjB,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;AACtC,QAAI,CAAC,WAAW,sBAAsB,IAAI,aAAa,CACrD,QAAO;AAGT,QAAI,cAAA,MAAO,SAAQ,KAAK,iCAAiC,aAAa;AAEtE,QAAI,WAAW,WAAW,SAAS;KACjC,MAAM,WAAW,kBAAA,+BAA+B;MAC9C;MACA,UAAU;MACV,IAAI;MACJ,QAAQ;MACR,oBAAoB,EAAE;MACtB,iBAAiB;MACjB,iBAAiB,0BAAA,iCAAiC;OAChD,iBAAiB;OACjB,QAAQ;OACT,CAAC;MACH,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,EAAE,MAAM,CAAC;AAC9B,QAAI,QAAQ,KAAK,KAAK,4BAAA,kBAAkB;IACxC,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,eAAA,UAAU,SAAS,KAAK;;GAEvC,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 './route-hmr-statement'\nimport { debug, normalizePath } from './utils'\nimport { getConfig } from './config'\nimport type { UnpluginFactory } from 'unplugin'\nimport type { Config } from './config'\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]\nexport const unpluginRouterHmrFactory: UnpluginFactory<\n Partial<Config> | undefined\n> = (options = {}) => {\n let ROOT: string = process.cwd()\n let userConfig = options as Config\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 if (!globalThis.TSR_ROUTES_BY_ID_MAP?.has(normalizedId)) {\n return null\n }\n\n if (debug) console.info('Adding HMR handling to route ', normalizedId)\n\n if (userConfig.target === 'react') {\n const compilerPlugins = getReferenceRouteCompilerPlugins({\n targetFramework: 'react',\n addHmr: true,\n })\n const compiled = compileCodeSplitReferenceRoute({\n code,\n filename: normalizedId,\n id: normalizedId,\n addHmr: true,\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 })\n ast.program.body.push(createRouteHmrStatement([]))\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 = getConfig(options, ROOT)\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"],"mappings":";;;;;;;;;;;;;AAeA,IAAM,cAAc;CAClB;CACA;CACA;CACD;AACD,IAAa,4BAER,UAAU,EAAE,KAAK;CACpB,IAAI,OAAe,QAAQ,KAAK;CAChC,IAAI,aAAa;AAEjB,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;AACtC,QAAI,CAAC,WAAW,sBAAsB,IAAI,aAAa,CACrD,QAAO;AAGT,QAAI,cAAA,MAAO,SAAQ,KAAK,iCAAiC,aAAa;AAEtE,QAAI,WAAW,WAAW,SAAS;KAKjC,MAAM,WAAW,kBAAA,+BAA+B;MAC9C;MACA,UAAU;MACV,IAAI;MACJ,QAAQ;MACR,oBAAoB,EAAE;MACtB,iBAAiB;MACjB,iBAXsB,0BAAA,iCAAiC;OACvD,iBAAiB;OACjB,QAAQ;OACT,CAAC;MASD,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,EAAE,MAAM,CAAC;AAC9B,QAAI,QAAQ,KAAK,KAAK,4BAAA,wBAAwB,EAAE,CAAC,CAAC;IAClD,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,eAAA,UAAU,SAAS,KAAK;;GAEvC,mBAAmB,aAAa;AAC9B,QAAI,WAAW,QAAQ,MAAM,gBAC3B,QAAO,WAAW,OAAO,KAAK,oBAAoB,YAAY;AAEhE,WAAO;;GAEV;EACF"}
@@ -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
+ function getObjectPropertyKeyName(prop) {
17
+ if (prop.computed) return;
18
+ if (_babel_types.isIdentifier(prop.key)) return prop.key.name;
19
+ if (_babel_types.isStringLiteral(prop.key)) return prop.key.value;
20
+ }
16
21
  function getUniqueProgramIdentifier(programPath, baseName) {
17
22
  let name = baseName;
18
23
  let suffix = 2;
@@ -26,6 +31,7 @@ function getUniqueProgramIdentifier(programPath, baseName) {
26
31
  }
27
32
  //#endregion
28
33
  exports.debug = debug;
34
+ exports.getObjectPropertyKeyName = getObjectPropertyKeyName;
29
35
  exports.getUniqueProgramIdentifier = getUniqueProgramIdentifier;
30
36
  exports.normalizePath = normalizePath;
31
37
 
@@ -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 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,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 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"}
@@ -9,4 +9,5 @@ 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 function getObjectPropertyKeyName(prop: t.ObjectProperty): string | undefined;
12
13
  export declare function getUniqueProgramIdentifier(programPath: babel.NodePath<t.Program>, baseName: string): t.Identifier;
@@ -1,5 +1,6 @@
1
1
  import { tsrShared, tsrSplit } from "../constants.js";
2
- import { routeHmrStatement } from "../route-hmr-statement.js";
2
+ import { createRouteHmrStatement } from "../route-hmr-statement.js";
3
+ import { getObjectPropertyKeyName } from "../utils.js";
3
4
  import { createIdentifier } from "./path-ids.js";
4
5
  import { getFrameworkOptions } from "./framework-options.js";
5
6
  import { deadCodeElimination, findReferencedIdentifiers, generateFromAst, parseAst } from "@tanstack/router-utils";
@@ -96,10 +97,6 @@ function collectIdentifiersFromNode(node) {
96
97
  })(node);
97
98
  return ids;
98
99
  }
99
- function getObjectPropertyKeyName(prop) {
100
- if (t.isIdentifier(prop.key)) return prop.key.name;
101
- if (t.isStringLiteral(prop.key)) return prop.key.value;
102
- }
103
100
  /**
104
101
  * Build a map from binding name → declaration AST node for all
105
102
  * locally-declared module-level bindings. Built once, O(1) lookup.
@@ -365,6 +362,7 @@ function compileCodeSplitReferenceRoute(opts) {
365
362
  const PACKAGE = frameworkOptions.package;
366
363
  const LAZY_ROUTE_COMPONENT_IDENT = frameworkOptions.idents.lazyRouteComponent;
367
364
  const LAZY_FN_IDENT = frameworkOptions.idents.lazyFn;
365
+ const stableRouteOptionKeys = [...new Set((opts.compilerPlugins ?? []).flatMap((plugin) => plugin.getStableRouteOptionKeys?.() ?? []))];
368
366
  let createRouteFn;
369
367
  let modified = false;
370
368
  let hmrAdded = false;
@@ -388,7 +386,24 @@ function compileCodeSplitReferenceRoute(opts) {
388
386
  const hasImportedOrDefinedIdentifier = (name) => {
389
387
  return programPath.scope.hasBinding(name);
390
388
  };
389
+ const addRouteHmr = (insertionPath, routeOptions) => {
390
+ if (!opts.addHmr || hmrAdded) return;
391
+ opts.compilerPlugins?.forEach((plugin) => {
392
+ if ((plugin.onAddHmr?.({
393
+ programPath,
394
+ callExpressionPath: path,
395
+ insertionPath,
396
+ routeOptions,
397
+ createRouteFn,
398
+ opts
399
+ }))?.modified) modified = true;
400
+ });
401
+ programPath.pushContainer("body", createRouteHmrStatement(stableRouteOptionKeys));
402
+ modified = true;
403
+ hmrAdded = true;
404
+ };
391
405
  if (t.isObjectExpression(routeOptions)) {
406
+ const insertionPath = path.getStatementParent() ?? path;
392
407
  if (opts.deleteNodes && opts.deleteNodes.size > 0) routeOptions.properties = routeOptions.properties.filter((prop) => {
393
408
  if (t.isObjectProperty(prop)) {
394
409
  const key = getObjectPropertyKeyName(prop);
@@ -400,7 +415,6 @@ function compileCodeSplitReferenceRoute(opts) {
400
415
  return true;
401
416
  });
402
417
  if (!splittableCreateRouteFns.includes(createRouteFn)) {
403
- const insertionPath = path.getStatementParent() ?? path;
404
418
  opts.compilerPlugins?.forEach((plugin) => {
405
419
  if ((plugin.onUnsplittableRoute?.({
406
420
  programPath,
@@ -411,11 +425,7 @@ function compileCodeSplitReferenceRoute(opts) {
411
425
  opts
412
426
  }))?.modified) modified = true;
413
427
  });
414
- if (opts.addHmr && !hmrAdded) {
415
- programPath.pushContainer("body", routeHmrStatement);
416
- modified = true;
417
- hmrAdded = true;
418
- }
428
+ addRouteHmr(insertionPath, routeOptions);
419
429
  return programPath.stop();
420
430
  }
421
431
  routeOptions.properties.forEach((prop) => {
@@ -463,11 +473,7 @@ function compileCodeSplitReferenceRoute(opts) {
463
473
  }
464
474
  if (splitPropValue) prop.value = splitPropValue;
465
475
  else prop.value = template.expression(`${LAZY_ROUTE_COMPONENT_IDENT}(${splitNodeMeta.localImporterIdent}, '${splitNodeMeta.exporterIdent}')`)();
466
- if (opts.addHmr && !hmrAdded) {
467
- programPath.pushContainer("body", routeHmrStatement);
468
- modified = true;
469
- hmrAdded = true;
470
- }
476
+ addRouteHmr(insertionPath, routeOptions);
471
477
  } else {
472
478
  const value = prop.value;
473
479
  let shouldSplit = true;
@@ -489,6 +495,7 @@ function compileCodeSplitReferenceRoute(opts) {
489
495
  }
490
496
  programPath.scope.crawl();
491
497
  });
498
+ addRouteHmr(insertionPath, routeOptions);
492
499
  }
493
500
  }
494
501
  if (t.isCallExpression(path.parentPath.node)) babelHandleReference(resolveIdentifier(path, path.parentPath.node.arguments[0]));