@bleedingdev/modern-js-plugin-tanstack 3.2.0-ultramodern.12 → 3.2.0-ultramodern.121

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 (136) hide show
  1. package/dist/cjs/cli/index.js +89 -31
  2. package/dist/cjs/cli/routeSplitting.js +55 -0
  3. package/dist/cjs/cli/tanstackTypes.js +172 -170
  4. package/dist/cjs/cli.js +12 -8
  5. package/dist/cjs/runtime/basepathRewrite.js +12 -8
  6. package/dist/cjs/runtime/dataMutation.js +9 -5
  7. package/dist/cjs/runtime/hooks.js +20 -19
  8. package/dist/cjs/runtime/hydrationBoundary.js +48 -0
  9. package/dist/cjs/runtime/index.js +79 -35
  10. package/dist/cjs/runtime/lifecycle.js +21 -91
  11. package/dist/cjs/runtime/loaderBridge.js +173 -0
  12. package/dist/cjs/runtime/outlet.js +58 -0
  13. package/dist/cjs/runtime/plugin.js +195 -114
  14. package/dist/cjs/runtime/plugin.node.js +45 -45
  15. package/dist/cjs/runtime/plugin.worker.js +53 -0
  16. package/dist/cjs/runtime/pluginCore.js +55 -0
  17. package/dist/cjs/runtime/prefetchLink.js +10 -6
  18. package/dist/cjs/runtime/register.js +56 -0
  19. package/dist/cjs/runtime/routeTree.js +74 -207
  20. package/dist/cjs/runtime/router.js +41 -0
  21. package/dist/cjs/runtime/rsc/ClientSlot.js +9 -5
  22. package/dist/cjs/runtime/rsc/CompositeComponent.js +9 -5
  23. package/dist/cjs/runtime/rsc/ReplayableStream.js +14 -9
  24. package/dist/cjs/runtime/rsc/RscNodeRenderer.js +9 -5
  25. package/dist/cjs/runtime/rsc/SlotContext.js +9 -5
  26. package/dist/cjs/runtime/rsc/client.js +9 -5
  27. package/dist/cjs/runtime/rsc/createRscProxy.js +9 -5
  28. package/dist/cjs/runtime/rsc/index.js +9 -5
  29. package/dist/cjs/runtime/rsc/payloadRouter.js +44 -6
  30. package/dist/cjs/runtime/rsc/server.js +9 -5
  31. package/dist/cjs/runtime/rsc/slotUsageSanitizer.js +9 -5
  32. package/dist/cjs/runtime/rsc/symbols.js +20 -15
  33. package/dist/cjs/runtime/state.js +45 -0
  34. package/dist/cjs/runtime/types.js +31 -1
  35. package/dist/cjs/runtime/utils.js +9 -10
  36. package/dist/cjs/runtime.js +9 -5
  37. package/dist/esm/cli/index.mjs +75 -27
  38. package/dist/esm/cli/routeSplitting.mjs +14 -0
  39. package/dist/esm/cli/tanstackTypes.mjs +158 -160
  40. package/dist/esm/runtime/hooks.mjs +1 -8
  41. package/dist/esm/runtime/hydrationBoundary.mjs +10 -0
  42. package/dist/esm/runtime/index.mjs +5 -2
  43. package/dist/esm/runtime/lifecycle.mjs +1 -82
  44. package/dist/esm/runtime/loaderBridge.mjs +114 -0
  45. package/dist/esm/runtime/outlet.mjs +17 -0
  46. package/dist/esm/runtime/plugin.mjs +191 -114
  47. package/dist/esm/runtime/plugin.node.mjs +40 -44
  48. package/dist/esm/runtime/plugin.worker.mjs +1 -0
  49. package/dist/esm/runtime/pluginCore.mjs +14 -0
  50. package/dist/esm/runtime/prefetchLink.mjs +1 -1
  51. package/dist/esm/runtime/register.mjs +18 -0
  52. package/dist/esm/runtime/routeTree.mjs +59 -193
  53. package/dist/esm/runtime/router.mjs +2 -0
  54. package/dist/esm/runtime/rsc/payloadRouter.mjs +35 -1
  55. package/dist/esm/runtime/state.mjs +7 -0
  56. package/dist/esm/runtime/types.mjs +7 -0
  57. package/dist/esm/runtime/utils.mjs +0 -5
  58. package/dist/esm-node/cli/index.mjs +75 -27
  59. package/dist/esm-node/cli/routeSplitting.mjs +15 -0
  60. package/dist/esm-node/cli/tanstackTypes.mjs +158 -160
  61. package/dist/esm-node/runtime/hooks.mjs +1 -8
  62. package/dist/esm-node/runtime/hydrationBoundary.mjs +11 -0
  63. package/dist/esm-node/runtime/index.mjs +5 -2
  64. package/dist/esm-node/runtime/lifecycle.mjs +1 -82
  65. package/dist/esm-node/runtime/loaderBridge.mjs +115 -0
  66. package/dist/esm-node/runtime/outlet.mjs +18 -0
  67. package/dist/esm-node/runtime/plugin.mjs +191 -114
  68. package/dist/esm-node/runtime/plugin.node.mjs +40 -44
  69. package/dist/esm-node/runtime/plugin.worker.mjs +2 -0
  70. package/dist/esm-node/runtime/pluginCore.mjs +15 -0
  71. package/dist/esm-node/runtime/prefetchLink.mjs +1 -1
  72. package/dist/esm-node/runtime/register.mjs +19 -0
  73. package/dist/esm-node/runtime/routeTree.mjs +59 -193
  74. package/dist/esm-node/runtime/router.mjs +3 -0
  75. package/dist/esm-node/runtime/rsc/payloadRouter.mjs +35 -1
  76. package/dist/esm-node/runtime/state.mjs +8 -0
  77. package/dist/esm-node/runtime/types.mjs +7 -0
  78. package/dist/esm-node/runtime/utils.mjs +0 -5
  79. package/dist/types/cli/index.d.ts +14 -1
  80. package/dist/types/cli/routeSplitting.d.ts +20 -0
  81. package/dist/types/cli/tanstackTypes.d.ts +21 -1
  82. package/dist/types/runtime/hooks.d.ts +8 -33
  83. package/dist/types/runtime/hydrationBoundary.d.ts +2 -0
  84. package/dist/types/runtime/index.d.ts +8 -3
  85. package/dist/types/runtime/lifecycle.d.ts +7 -22
  86. package/dist/types/runtime/loaderBridge.d.ts +48 -0
  87. package/dist/types/runtime/outlet.d.ts +2 -0
  88. package/dist/types/runtime/plugin.d.ts +2 -15
  89. package/dist/types/runtime/plugin.node.d.ts +2 -15
  90. package/dist/types/runtime/plugin.worker.d.ts +1 -0
  91. package/dist/types/runtime/pluginCore.d.ts +21 -0
  92. package/dist/types/runtime/register.d.ts +9 -0
  93. package/dist/types/runtime/routeTree.d.ts +0 -2
  94. package/dist/types/runtime/router.d.ts +14 -0
  95. package/dist/types/runtime/state.d.ts +16 -0
  96. package/dist/types/runtime/types.d.ts +14 -53
  97. package/package.json +42 -40
  98. package/rstest.config.mts +6 -0
  99. package/src/cli/index.ts +162 -23
  100. package/src/cli/routeSplitting.ts +43 -0
  101. package/src/cli/tanstackTypes.ts +331 -187
  102. package/src/runtime/hooks.ts +10 -27
  103. package/src/runtime/hydrationBoundary.tsx +12 -0
  104. package/src/runtime/index.tsx +17 -7
  105. package/src/runtime/lifecycle.ts +16 -151
  106. package/src/runtime/loaderBridge.ts +257 -0
  107. package/src/runtime/outlet.tsx +48 -0
  108. package/src/runtime/plugin.node.tsx +72 -85
  109. package/src/runtime/plugin.tsx +361 -206
  110. package/src/runtime/plugin.worker.tsx +4 -0
  111. package/src/runtime/pluginCore.ts +48 -0
  112. package/src/runtime/prefetchLink.tsx +1 -1
  113. package/src/runtime/register.ts +58 -0
  114. package/src/runtime/routeTree.ts +163 -354
  115. package/src/runtime/router.ts +15 -0
  116. package/src/runtime/rsc/payloadRouter.ts +45 -2
  117. package/src/runtime/ssr-shim.d.ts +1 -3
  118. package/src/runtime/state.ts +29 -0
  119. package/src/runtime/types.ts +32 -66
  120. package/src/runtime/utils.tsx +3 -6
  121. package/tests/router/cli.test.ts +586 -5
  122. package/tests/router/fastDefaults.test.ts +25 -0
  123. package/tests/router/hooks.test.ts +26 -0
  124. package/tests/router/hydrationBoundary.test.tsx +23 -0
  125. package/tests/router/loaderBridge.test.ts +211 -0
  126. package/tests/router/packageSurface.test.ts +24 -0
  127. package/tests/router/prefetchLink.test.tsx +43 -7
  128. package/tests/router/register.test.ts +46 -0
  129. package/tests/router/routeTree.test.ts +381 -81
  130. package/tests/router/rsc.test.tsx +70 -0
  131. package/tests/router/tanstackTypes.test.ts +573 -1
  132. package/dist/cjs/runtime/DefaultNotFound.js +0 -47
  133. package/dist/esm/runtime/DefaultNotFound.mjs +0 -13
  134. package/dist/esm-node/runtime/DefaultNotFound.mjs +0 -14
  135. package/dist/types/runtime/DefaultNotFound.d.ts +0 -2
  136. package/src/runtime/DefaultNotFound.tsx +0 -15
package/src/cli/index.ts CHANGED
@@ -19,13 +19,26 @@ import {
19
19
  NESTED_ROUTE_SPEC_FILE,
20
20
  } from '@modern-js/utils';
21
21
  import {
22
+ createTanstackRsbuildRouteSplittingProfile,
23
+ type TanstackRouteCodeSplittingOption,
24
+ } from './routeSplitting';
25
+ import {
26
+ collectCanonicalRoutesForEntry,
22
27
  generateTanstackRouterTypesSourceForEntry,
23
- isTanstackRouterFrameworkEnabled,
24
28
  } from './tanstackTypes';
25
29
 
30
+ export type {
31
+ TanstackRouteCodeSplittingOption,
32
+ TanstackRsbuildRouteSplittingProfile,
33
+ } from './routeSplitting';
34
+ export {
35
+ createTanstackRsbuildRouteSplittingProfile,
36
+ resolveTanstackRouteCodeSplittingEnabled,
37
+ } from './routeSplitting';
26
38
  export {
39
+ type CollectCanonicalRoutesOptions,
40
+ collectCanonicalRoutesForEntry,
27
41
  generateTanstackRouterTypesSourceForEntry,
28
- isTanstackRouterFrameworkEnabled,
29
42
  } from './tanstackTypes';
30
43
 
31
44
  const DEFAULT_ROUTES_DIR = 'routes';
@@ -35,10 +48,12 @@ const ENTRYPOINTS_KEY = '@modern-js/plugin-tanstack';
35
48
  export type TanstackRouterPluginOptions = {
36
49
  routesDir?: string;
37
50
  generatedDirName?: string;
51
+ routeCodeSplitting?: TanstackRouteCodeSplittingOption;
38
52
  };
39
53
 
40
54
  type RuntimeRouterCliHelpers = {
41
55
  getEntrypointRoutesDir: (entrypoint: Entrypoint) => string | null;
56
+ getEntrypointRoutesOwner: (entrypoint: Entrypoint) => string | null;
42
57
  handleFileChange: (
43
58
  api: CLIPluginAPI<AppTools>,
44
59
  event: unknown,
@@ -58,9 +73,6 @@ type RuntimeRouterCliHelpers = {
58
73
  entrypoints: Entrypoint[],
59
74
  options?: {
60
75
  entrypointsKey?: string;
61
- generateCodeOptions?: {
62
- enableTanstackTypes?: boolean;
63
- };
64
76
  },
65
77
  ) => Promise<Record<string, (NestedRouteForCli | PageRoute)[]>>;
66
78
  handleModifyEntrypoints: (
@@ -82,7 +94,11 @@ function getRuntimeRouterCli(): RuntimeRouterCliHelpers {
82
94
 
83
95
  const cli =
84
96
  require('@modern-js/runtime/cli') as Partial<RuntimeRouterCliHelpers>;
85
- if (cli.handleGeneratorEntryCode && cli.getEntrypointRoutesDir) {
97
+ if (
98
+ cli.handleGeneratorEntryCode &&
99
+ cli.getEntrypointRoutesDir &&
100
+ cli.getEntrypointRoutesOwner
101
+ ) {
86
102
  runtimeRouterCli = cli as RuntimeRouterCliHelpers;
87
103
  return runtimeRouterCli;
88
104
  }
@@ -110,6 +126,8 @@ async function writeFileIfChanged(filePath: string, content: string) {
110
126
  function createRegisterDtsContent(opts: {
111
127
  entries: string[];
112
128
  runtimeModule: string;
129
+ canonicalRoutes?: Record<string, string> | null;
130
+ i18nRuntimeModule?: string;
113
131
  }) {
114
132
  const importStatements = opts.entries
115
133
  .map(
@@ -121,6 +139,20 @@ function createRegisterDtsContent(opts: {
121
139
  .map((_, index) => `typeof router${index}`)
122
140
  .join(' | ');
123
141
 
142
+ const canonicalEntries = Object.entries(opts.canonicalRoutes ?? {});
143
+ const canonicalRoutesAugmentation =
144
+ canonicalEntries.length > 0
145
+ ? `
146
+ declare module '${opts.i18nRuntimeModule || '@modern-js/plugin-i18n/runtime'}' {
147
+ interface UltramodernCanonicalRoutes {
148
+ ${canonicalEntries
149
+ .map(([routePath, paramsType]) => ` '${routePath}': ${paramsType};`)
150
+ .join('\n')}
151
+ }
152
+ }
153
+ `
154
+ : '';
155
+
124
156
  return `// This file is auto-generated by Modern.js. Do not edit manually.
125
157
 
126
158
  ${importStatements}
@@ -130,7 +162,7 @@ declare module '${opts.runtimeModule}' {
130
162
  router: ${routerUnionType};
131
163
  }
132
164
  }
133
- `;
165
+ ${canonicalRoutesAugmentation}`;
134
166
  }
135
167
 
136
168
  export async function writeTanstackRegisterFile(opts: {
@@ -138,12 +170,16 @@ export async function writeTanstackRegisterFile(opts: {
138
170
  generatedDirName?: string;
139
171
  runtimeModule?: string;
140
172
  srcDirectory: string;
173
+ canonicalRoutes?: Record<string, string> | null;
174
+ i18nRuntimeModule?: string;
141
175
  }) {
142
176
  const {
143
177
  entries,
144
178
  generatedDirName = DEFAULT_GENERATED_DIR_NAME,
145
179
  runtimeModule = '@modern-js/plugin-tanstack/runtime',
146
180
  srcDirectory,
181
+ canonicalRoutes,
182
+ i18nRuntimeModule,
147
183
  } = opts;
148
184
 
149
185
  if (entries.length === 0) {
@@ -158,7 +194,12 @@ export async function writeTanstackRegisterFile(opts: {
158
194
 
159
195
  await writeFileIfChanged(
160
196
  registerDtsPath,
161
- createRegisterDtsContent({ entries, runtimeModule }),
197
+ createRegisterDtsContent({
198
+ entries,
199
+ runtimeModule,
200
+ canonicalRoutes,
201
+ i18nRuntimeModule,
202
+ }),
162
203
  );
163
204
  }
164
205
 
@@ -166,11 +207,19 @@ export async function writeTanstackRouterTypesForEntries(opts: {
166
207
  appContext: AppToolsContext;
167
208
  generatedDirName?: string;
168
209
  routesByEntry: Record<string, (NestedRouteForCli | PageRoute)[]>;
210
+ /**
211
+ * Whether `@modern-js/plugin-i18n` is actually installed in the app. The
212
+ * `register.gen.d.ts` augmentation of '@modern-js/plugin-i18n/runtime' is
213
+ * only emitted when this is true — otherwise apps with a hand-rolled
214
+ * `/:lang/` param would fail typechecking on an unresolvable module.
215
+ */
216
+ i18nPluginInstalled?: boolean;
169
217
  }) {
170
218
  const {
171
219
  appContext,
172
220
  generatedDirName = DEFAULT_GENERATED_DIR_NAME,
173
221
  routesByEntry,
222
+ i18nPluginInstalled = false,
174
223
  } = opts;
175
224
 
176
225
  const entryNames = Object.keys(routesByEntry);
@@ -211,10 +260,31 @@ export async function writeTanstackRouterTypesForEntries(opts: {
211
260
  return a.localeCompare(b);
212
261
  });
213
262
 
263
+ // Merge the canonical (language-agnostic) route maps of every entry so the
264
+ // typed i18n Link covers all routes the app can navigate to. Only relevant
265
+ // when plugin-i18n is actually installed — without it the emitted module
266
+ // augmentation would reference an unresolvable module.
267
+ let canonicalRoutes: Record<string, string> | null = null;
268
+ if (i18nPluginInstalled) {
269
+ for (const entryName of registerEntries) {
270
+ const entryCanonicalRoutes = collectCanonicalRoutesForEntry(
271
+ routesByEntry[entryName],
272
+ { localeParamHeuristic: true },
273
+ );
274
+ if (entryCanonicalRoutes) {
275
+ canonicalRoutes = {
276
+ ...entryCanonicalRoutes,
277
+ ...(canonicalRoutes ?? {}),
278
+ };
279
+ }
280
+ }
281
+ }
282
+
214
283
  await writeTanstackRegisterFile({
215
284
  entries: registerEntries,
216
285
  generatedDirName,
217
286
  srcDirectory: appContext.srcDirectory,
287
+ canonicalRoutes,
218
288
  });
219
289
  }
220
290
 
@@ -224,6 +294,8 @@ export function tanstackRouterPlugin(
224
294
  const routesDir = options.routesDir || DEFAULT_ROUTES_DIR;
225
295
  const generatedDirName =
226
296
  options.generatedDirName || DEFAULT_GENERATED_DIR_NAME;
297
+ const routeSplittingProfile =
298
+ createTanstackRsbuildRouteSplittingProfile(options);
227
299
 
228
300
  return {
229
301
  name: '@modern-js/plugin-tanstack',
@@ -236,11 +308,38 @@ export function tanstackRouterPlugin(
236
308
  return getEntrypointRoutesDir(entrypoint) === routesDir;
237
309
  };
238
310
 
239
- api._internalRuntimePlugins(({ entrypoint, plugins }) => {
240
- if (!isTanstackEntrypoint(entrypoint as Entrypoint)) {
241
- return { entrypoint, plugins };
311
+ // Entrypoints claimed by another file-route convention — the built-in
312
+ // pages/ or routes/ entries of @modern-js/runtime's router plugin, or
313
+ // an entry tagged by a different routes-owner plugin. Their router
314
+ // runtime plugin must be left untouched: redirecting it through our
315
+ // wrapper would value-import the TanStack runtime into bundles that
316
+ // never use it, and pushing a second `router` plugin can install two
317
+ // routers for one entry.
318
+ const isForeignRouteEntrypoint = (entrypoint: Entrypoint) => {
319
+ const { getEntrypointRoutesDir, getEntrypointRoutesOwner } =
320
+ getRuntimeRouterCli();
321
+ if (getEntrypointRoutesOwner(entrypoint)) {
322
+ // Owned by some routes-owner plugin. TanStack-owned entries were
323
+ // already claimed by the isTanstackEntrypoint branch, so any owner
324
+ // seen here is foreign.
325
+ return true;
326
+ }
327
+ if (entrypoint.pageRoutesEntry) {
328
+ return true;
242
329
  }
330
+ return getEntrypointRoutesDir(entrypoint) !== null;
331
+ };
243
332
 
333
+ const isI18nPluginInstalled = () => {
334
+ const { plugins } = api.getAppContext() as {
335
+ plugins?: Array<{ name?: string }>;
336
+ };
337
+ return Boolean(
338
+ plugins?.some(plugin => plugin?.name === '@modern-js/plugin-i18n'),
339
+ );
340
+ };
341
+
342
+ api._internalRuntimePlugins(({ entrypoint, plugins }) => {
244
343
  const { metaName, serverRoutes } = api.getAppContext();
245
344
  const serverBase = serverRoutes
246
345
  .filter(
@@ -249,11 +348,44 @@ export function tanstackRouterPlugin(
249
348
  .map(route => route.urlPath)
250
349
  .sort((a, b) => (a.length - b.length > 0 ? -1 : 1));
251
350
 
252
- plugins.push({
253
- name: 'tanstackRouter',
254
- path: `@${metaName}/plugin-tanstack/runtime`,
255
- config: { serverBase },
256
- });
351
+ if (isTanstackEntrypoint(entrypoint as Entrypoint)) {
352
+ plugins.push({
353
+ name: 'tanstackRouter',
354
+ path: `@${metaName}/plugin-tanstack/runtime`,
355
+ config: { serverBase },
356
+ });
357
+
358
+ return { entrypoint, plugins };
359
+ }
360
+
361
+ // Entries owned by the built-in router (classic routes/ or pages/
362
+ // conventions) or by another routes-owner plugin keep their own
363
+ // router runtime plugin untouched.
364
+ if (isForeignRouteEntrypoint(entrypoint as Entrypoint)) {
365
+ return { entrypoint, plugins };
366
+ }
367
+
368
+ // True custom entry without any file-route convention (`createRoutes`
369
+ // apps, hand-rolled App entries, ...): having this plugin installed
370
+ // is the explicit signal that the app routes through the
371
+ // router-provider registry — no source sniffing of modern.runtime.ts.
372
+ // Inject the framework-resolving router plugin of @modern-js/runtime
373
+ // through our own runtime/router module, so the TanStack provider
374
+ // registration is value-imported together with it and can never be
375
+ // tree-shaken away from the entry.
376
+ const routerWrapperPath = `@${metaName}/plugin-tanstack/runtime/router`;
377
+ const existingRouterPlugin = plugins.find(
378
+ plugin => plugin.name === 'router',
379
+ );
380
+ if (existingRouterPlugin) {
381
+ existingRouterPlugin.path = routerWrapperPath;
382
+ } else {
383
+ plugins.push({
384
+ name: 'router',
385
+ path: routerWrapperPath,
386
+ config: { serverBase },
387
+ });
388
+ }
257
389
 
258
390
  return { entrypoint, plugins };
259
391
  });
@@ -265,10 +397,21 @@ export function tanstackRouterPlugin(
265
397
  }));
266
398
 
267
399
  api.config(() => ({
400
+ ...routeSplittingProfile.defaultConfig,
268
401
  source: {
269
402
  include: [
403
+ // TanStack Router and its runtime deps ship modern syntax and
404
+ // must be down-leveled for the app's browser targets.
270
405
  /[\\/]node_modules[\\/]@tanstack[\\/]react-router[\\/]/,
271
- path.resolve(__dirname, '../runtime').replace('cjs', 'esm'),
406
+ /[\\/]node_modules[\\/]@tanstack[\\/]router-core[\\/]/,
407
+ /[\\/]node_modules[\\/]@tanstack[\\/]react-store[\\/]/,
408
+ // This package's own dist runtime, too. `__dirname` is
409
+ // dist/{cjs,esm-node}/cli (or src/cli in tests), so the package
410
+ // dist root is two levels up. Resolution-based — no string
411
+ // surgery: the old `.replace('cjs', 'esm')` corrupted workspace
412
+ // paths containing 'cjs' and, under the ESM CLI condition, never
413
+ // matched the dist/esm runtime that browsers actually bundle.
414
+ path.resolve(__dirname, '..', '..'),
272
415
  ],
273
416
  },
274
417
  }));
@@ -295,9 +438,6 @@ export function tanstackRouterPlugin(
295
438
  tanstackEntrypoints,
296
439
  {
297
440
  entrypointsKey: ENTRYPOINTS_KEY,
298
- generateCodeOptions: {
299
- enableTanstackTypes: false,
300
- },
301
441
  },
302
442
  );
303
443
 
@@ -305,6 +445,7 @@ export function tanstackRouterPlugin(
305
445
  appContext: api.getAppContext(),
306
446
  generatedDirName,
307
447
  routesByEntry,
448
+ i18nPluginInstalled: isI18nPluginInstalled(),
308
449
  });
309
450
  });
310
451
 
@@ -323,9 +464,6 @@ export function tanstackRouterPlugin(
323
464
  entrypoints,
324
465
  {
325
466
  entrypointsKey: ENTRYPOINTS_KEY,
326
- generateCodeOptions: {
327
- enableTanstackTypes: false,
328
- },
329
467
  },
330
468
  );
331
469
 
@@ -333,6 +471,7 @@ export function tanstackRouterPlugin(
333
471
  appContext: api.getAppContext(),
334
472
  generatedDirName,
335
473
  routesByEntry,
474
+ i18nPluginInstalled: isI18nPluginInstalled(),
336
475
  });
337
476
  },
338
477
  });
@@ -0,0 +1,43 @@
1
+ export type TanstackRouteCodeSplittingOption =
2
+ | boolean
3
+ | {
4
+ enabled?: boolean;
5
+ };
6
+
7
+ export type TanstackRsbuildRouteSplittingProfile = {
8
+ defaultConfig: {
9
+ output: {
10
+ splitRouteChunks: boolean;
11
+ };
12
+ };
13
+ };
14
+
15
+ export function resolveTanstackRouteCodeSplittingEnabled(
16
+ option?: TanstackRouteCodeSplittingOption,
17
+ ) {
18
+ if (typeof option === 'boolean') {
19
+ return option;
20
+ }
21
+
22
+ return option?.enabled ?? true;
23
+ }
24
+
25
+ /**
26
+ * Route chunking for TanStack entries is owned by Modern's
27
+ * `output.splitRouteChunks`; the TanStack Start Rspack splitter does not
28
+ * apply because Modern generates TanStack route trees from Modern route
29
+ * metadata rather than TanStack file-route factory modules.
30
+ */
31
+ export function createTanstackRsbuildRouteSplittingProfile(opts: {
32
+ routeCodeSplitting?: TanstackRouteCodeSplittingOption;
33
+ }): TanstackRsbuildRouteSplittingProfile {
34
+ return {
35
+ defaultConfig: {
36
+ output: {
37
+ splitRouteChunks: resolveTanstackRouteCodeSplittingEnabled(
38
+ opts.routeCodeSplitting,
39
+ ),
40
+ },
41
+ },
42
+ };
43
+ }