@bleedingdev/modern-js-plugin-tanstack 3.8.3-ultramodern.6 → 3.9.0-ultramodern.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/cjs/cli/index.js +9 -0
  2. package/dist/cjs/cli/tanstackTypes/source.js +3 -1
  3. package/dist/cjs/runtime/basepathRewrite.js +13 -6
  4. package/dist/cjs/runtime/lifecycle.js +7 -7
  5. package/dist/cjs/runtime/plugin.js +1 -1
  6. package/dist/cjs/runtime/plugin.node.js +5 -1
  7. package/dist/cjs/runtime/prefetchLink.js +2 -7
  8. package/dist/cjs/runtime/register.js +0 -2
  9. package/dist/cjs/runtime/routeTree/construction.js +2 -0
  10. package/dist/cjs/runtime/router.js +25 -9
  11. package/dist/cjs/runtime/state.js +2 -2
  12. package/dist/cjs/runtime/utils.js +2 -0
  13. package/dist/esm/cli/index.mjs +13 -5
  14. package/dist/esm/cli/tanstackTypes/source.mjs +3 -1
  15. package/dist/esm/runtime/basepathRewrite.mjs +10 -3
  16. package/dist/esm/runtime/lifecycle.mjs +1 -1
  17. package/dist/esm/runtime/plugin.mjs +1 -1
  18. package/dist/esm/runtime/plugin.node.mjs +5 -1
  19. package/dist/esm/runtime/prefetchLink.mjs +1 -6
  20. package/dist/esm/runtime/register.mjs +0 -2
  21. package/dist/esm/runtime/routeTree/construction.mjs +2 -0
  22. package/dist/esm/runtime/router.mjs +27 -11
  23. package/dist/esm/runtime/state.mjs +1 -1
  24. package/dist/esm/runtime/utils.mjs +2 -0
  25. package/dist/esm-node/cli/index.mjs +15 -5
  26. package/dist/esm-node/cli/tanstackTypes/source.mjs +3 -1
  27. package/dist/esm-node/runtime/basepathRewrite.mjs +10 -3
  28. package/dist/esm-node/runtime/lifecycle.mjs +1 -1
  29. package/dist/esm-node/runtime/plugin.mjs +1 -1
  30. package/dist/esm-node/runtime/plugin.node.mjs +5 -1
  31. package/dist/esm-node/runtime/prefetchLink.mjs +1 -6
  32. package/dist/esm-node/runtime/register.mjs +0 -2
  33. package/dist/esm-node/runtime/routeTree/construction.mjs +2 -0
  34. package/dist/esm-node/runtime/router.mjs +27 -11
  35. package/dist/esm-node/runtime/state.mjs +1 -1
  36. package/dist/esm-node/runtime/utils.mjs +2 -0
  37. package/dist/types/cli/index.d.ts +5 -5
  38. package/dist/types/cli/tanstackTypes/shared.d.ts +1 -1
  39. package/dist/types/cli/tanstackTypes.d.ts +3 -3
  40. package/dist/types/cli.d.ts +2 -2
  41. package/dist/types/runtime/basepathRewrite.d.ts +2 -1
  42. package/dist/types/runtime/dataMutation.d.ts +3 -3
  43. package/dist/types/runtime/index.d.ts +14 -14
  44. package/dist/types/runtime/lifecycle.d.ts +9 -2
  45. package/dist/types/runtime/loaderBridge.d.ts +2 -2
  46. package/dist/types/runtime/plugin.d.ts +2 -2
  47. package/dist/types/runtime/plugin.node.d.ts +2 -2
  48. package/dist/types/runtime/plugin.worker.d.ts +1 -1
  49. package/dist/types/runtime/pluginShared.d.ts +2 -2
  50. package/dist/types/runtime/register.d.ts +1 -9
  51. package/dist/types/runtime/routeTree/construction.d.ts +1 -1
  52. package/dist/types/runtime/routeTree/index.d.ts +2 -2
  53. package/dist/types/runtime/routeTree/loaders.d.ts +1 -1
  54. package/dist/types/runtime/routeTree/tanstackRoutes.d.ts +1 -1
  55. package/dist/types/runtime/router.d.ts +2 -13
  56. package/dist/types/runtime/rsc/CompositeComponent.d.ts +1 -1
  57. package/dist/types/runtime/rsc/RscNodeRenderer.d.ts +1 -1
  58. package/dist/types/runtime/rsc/client.d.ts +4 -4
  59. package/dist/types/runtime/rsc/createRscProxy.d.ts +1 -1
  60. package/dist/types/runtime/rsc/payloadFetch.d.ts +1 -1
  61. package/dist/types/runtime/rsc/payloadRouter.d.ts +2 -2
  62. package/dist/types/runtime/rsc/payloadStorage.d.ts +1 -1
  63. package/dist/types/runtime/rsc/server.d.ts +3 -3
  64. package/dist/types/runtime/rsc/shared.d.ts +1 -1
  65. package/dist/types/runtime/rsc/slotUsageSanitizer.d.ts +1 -1
  66. package/dist/types/runtime/ssrManagedTags.d.ts +1 -1
  67. package/dist/types/runtime/ssrPreload.d.ts +1 -1
  68. package/dist/types/runtime/state.d.ts +1 -1
  69. package/dist/types/runtime/submitAction.d.ts +1 -1
  70. package/dist/types/runtime/types.d.ts +2 -1
  71. package/dist/types/runtime/utils.d.ts +1 -1
  72. package/dist/types/runtime.d.ts +1 -1
  73. package/package.json +19 -16
  74. package/rstest.config.mts +1 -24
  75. package/src/cli/index.ts +10 -0
  76. package/src/cli/tanstackTypes/source.ts +3 -1
  77. package/src/runtime/basepathRewrite.ts +11 -2
  78. package/src/runtime/lifecycle.ts +14 -3
  79. package/src/runtime/plugin.node.tsx +9 -2
  80. package/src/runtime/plugin.tsx +5 -1
  81. package/src/runtime/prefetchLink.tsx +1 -23
  82. package/src/runtime/register.ts +1 -12
  83. package/src/runtime/routeTree/construction.ts +2 -0
  84. package/src/runtime/router.ts +25 -40
  85. package/src/runtime/state.ts +1 -1
  86. package/src/runtime/types.ts +2 -2
  87. package/src/runtime/utils.tsx +3 -1
  88. package/tests/router/cli.test.ts +148 -824
  89. package/tests/router/dataMutation.test.tsx +17 -85
  90. package/tests/router/flightSerialization.roundtrip.test.tsx +9 -6
  91. package/tests/router/generateRouteArtifacts.test.ts +68 -28
  92. package/tests/router/loaderBridge.test.ts +0 -25
  93. package/tests/router/localisedIdentity.test.tsx +95 -0
  94. package/tests/router/prefetchLink.test.tsx +17 -21
  95. package/tests/router/prefetchLinkPreload.test.tsx +11 -31
  96. package/tests/router/routeHooks.test.ts +41 -105
  97. package/tests/router/routeTree.test.ts +144 -836
  98. package/tests/router/rsc.test.tsx +131 -166
  99. package/tests/router/serverPlugin.test.ts +43 -1
  100. package/tests/router/tanstackTypes.test.ts +109 -973
  101. package/tests/realm-isolation.test.ts +0 -114
  102. package/tests/router/fastDefaults.test.ts +0 -32
  103. package/tests/router/fixtures/legacyRuntimeRouter.ts +0 -10
  104. package/tests/router/fixtures/rscDecoderSecurityChild.cjs +0 -162
  105. package/tests/router/hooks.test.ts +0 -40
  106. package/tests/router/hydrationBoundary.test.tsx +0 -23
  107. package/tests/router/packageSurface.test.ts +0 -24
  108. package/tests/router/preloadRedirect.test.ts +0 -64
  109. package/tests/router/register.test.ts +0 -8
  110. package/tests/router/routerCompatibility.test.ts +0 -239
  111. package/tests/router/rscDecoderSecurity.test.ts +0 -113
  112. package/tests/router/rscPayloadRouterMatrix.test.ts +0 -197
  113. /package/dist/esm/{rslib-runtime.mjs → rslib-runtime~1.mjs} +0 -0
  114. /package/dist/esm-node/{rslib-runtime.mjs → rslib-runtime~0.mjs} +0 -0
@@ -1,18 +1,12 @@
1
1
  import { execFile } from 'node:child_process';
2
- import { mkdir, mkdtemp, rm } from 'node:fs/promises';
2
+ import { mkdtemp, rm } from 'node:fs/promises';
3
3
  import { tmpdir } from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { promisify } from 'node:util';
6
- import { mergeConfig } from '@modern-js/plugin/cli';
6
+ import { compile } from '@modern-js/server-utils';
7
7
  import type { Entrypoint } from '@modern-js/types';
8
- import { fs, NESTED_ROUTE_SPEC_FILE } from '@modern-js/utils';
9
- import {
10
- createTanstackRsbuildRouteSplittingProfile,
11
- generateTanstackRouteArtifacts,
12
- tanstackRouterPlugin,
13
- writeTanstackRegisterFile,
14
- writeTanstackRouterTypesForEntries,
15
- } from '../../src/cli';
8
+ import { fs } from '@modern-js/utils';
9
+ import { tanstackRouterPlugin, writeTanstackRegisterFile } from '../../src/cli';
16
10
 
17
11
  const execFileAsync = promisify(execFile);
18
12
  const strictestTsconfigPath = path.resolve(
@@ -20,11 +14,24 @@ const strictestTsconfigPath = path.resolve(
20
14
  '../../node_modules/@tsconfig/strictest/tsconfig.json',
21
15
  );
22
16
 
17
+ function createAppContextApi<T extends object>(initial: T) {
18
+ let context: T & { serverCompileExcludedFiles?: string[] } = { ...initial };
19
+ return {
20
+ getAppContext: () => context,
21
+ updateAppContext: (update: Partial<typeof context>) => {
22
+ context = { ...context, ...update };
23
+ },
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Compiles the generated registration output with `tsgo` under
29
+ * @tsconfig/strictest — the way a consumer's own type check would see it.
30
+ */
23
31
  async function typecheckGeneratedRegistration(options: {
24
32
  entries: string[];
25
33
  generatedDirName: string;
26
34
  srcDirectory: string;
27
- runtimeModule?: string;
28
35
  i18nRuntimeModule?: string;
29
36
  canonicalTypeChecks?: string[];
30
37
  }) {
@@ -32,10 +39,10 @@ async function typecheckGeneratedRegistration(options: {
32
39
  entries,
33
40
  generatedDirName,
34
41
  srcDirectory,
35
- runtimeModule = '@modern-js/plugin-tanstack/runtime',
36
42
  i18nRuntimeModule,
37
43
  canonicalTypeChecks = [],
38
44
  } = options;
45
+ const runtimeModule = '@modern-js/plugin-tanstack/runtime';
39
46
  const projectDirectory = path.dirname(srcDirectory);
40
47
 
41
48
  for (const entry of entries) {
@@ -64,33 +71,28 @@ async function typecheckGeneratedRegistration(options: {
64
71
  ' export function modernLoaderToTanstack<TLoader extends (...args: never[]) => unknown>(options: { hasSplat: boolean }, loader: TLoader): (context: unknown) => Promise<Awaited<ReturnType<TLoader>>>;',
65
72
  ' export const modernTanstackRouterFastDefaults: Record<string, unknown>;',
66
73
  '}',
74
+ ...(i18nRuntimeModule
75
+ ? [
76
+ `declare module '${i18nRuntimeModule}' { export interface UltramodernCanonicalRoutes {} }`,
77
+ ]
78
+ : []),
67
79
  ];
68
- if (i18nRuntimeModule) {
69
- runtimeDeclaration.push(
70
- `declare module '${i18nRuntimeModule}' { export interface UltramodernCanonicalRoutes {} }`,
71
- );
72
- }
73
80
  await fs.outputFile(
74
81
  path.join(srcDirectory, 'generated-runtime-shim.d.ts'),
75
82
  runtimeDeclaration.join('\n'),
76
83
  );
77
84
 
78
- const contractLines = [
79
- `import type { Register } from '${runtimeModule}';`,
80
- ...entries.map(
81
- (entry, index) =>
82
- `import { router as router${index} } from './${generatedDirName}/${entry}/router.gen';`,
83
- ),
84
- ...entries.map(
85
- (_, index) =>
86
- `const registeredRouter${index}: Register['router'] = router${index};`,
87
- ),
88
- ...entries.map((_, index) => `void registeredRouter${index};`),
89
- ...canonicalTypeChecks,
90
- ];
91
85
  await fs.outputFile(
92
86
  path.join(srcDirectory, 'registration-contract.ts'),
93
- contractLines.join('\n'),
87
+ [
88
+ `import type { Register } from '${runtimeModule}';`,
89
+ ...entries.flatMap((entry, index) => [
90
+ `import { router as router${index} } from './${generatedDirName}/${entry}/router.gen';`,
91
+ `const registeredRouter${index}: Register['router'] = router${index};`,
92
+ `void registeredRouter${index};`,
93
+ ]),
94
+ ...canonicalTypeChecks,
95
+ ].join('\n'),
94
96
  );
95
97
  await fs.outputJSON(path.join(projectDirectory, 'tsconfig.json'), {
96
98
  extends: strictestTsconfigPath,
@@ -109,26 +111,16 @@ async function typecheckGeneratedRegistration(options: {
109
111
  await execFileAsync(
110
112
  process.platform === 'win32' ? 'tsgo.cmd' : 'tsgo',
111
113
  ['-p', 'tsconfig.json'],
112
- {
113
- cwd: projectDirectory,
114
- shell: process.platform === 'win32',
115
- },
114
+ { cwd: projectDirectory, shell: process.platform === 'win32' },
116
115
  );
117
- } catch (error) {
118
- if (
119
- error &&
120
- typeof error === 'object' &&
121
- 'stdout' in error &&
122
- typeof error.stdout === 'string'
123
- ) {
124
- throw new Error(error.stdout, { cause: error });
125
- }
126
- throw error;
116
+ } catch (error: any) {
117
+ throw typeof error?.stdout === 'string'
118
+ ? new Error(error.stdout, { cause: error })
119
+ : error;
127
120
  }
128
121
  }
129
122
 
130
123
  const runtimeCliMocks = {
131
- handleFileChange: rstest.fn(),
132
124
  handleGeneratorEntryCode: rstest.fn(),
133
125
  };
134
126
 
@@ -151,40 +143,14 @@ rstest.mock('@modern-js/runtime/cli', () => {
151
143
  : null),
152
144
  getEntrypointRoutesOwner: (entrypoint: any) =>
153
145
  entrypoint.__modernRoutesOwner || null,
154
- // Forward through arrows: the mock factory is hoisted above the
146
+ // Forward through an arrow: the mock factory is hoisted above the
155
147
  // `runtimeCliMocks` initializer, so it must not dereference it eagerly.
156
- handleFileChange: (...args: unknown[]) =>
157
- runtimeCliMocks.handleFileChange(...args),
158
148
  handleGeneratorEntryCode: (...args: unknown[]) =>
159
149
  runtimeCliMocks.handleGeneratorEntryCode(...args),
160
- handleModifyEntrypoints: async (
161
- entrypoints: Entrypoint[],
162
- routesDir = 'routes',
163
- ) =>
164
- entrypoints.map(entrypoint => {
165
- const routesEntry = path.join(entrypoint.absoluteEntryDir!, routesDir);
166
- return {
167
- ...entrypoint,
168
- nestedRoutesEntry: routesEntry,
169
- [routesDirMetaKey]: routesDir,
170
- };
171
- }),
172
- isRouteEntry: (dir: string, routesDir = 'routes') => {
173
- const routesEntry = path.join(dir, routesDir);
174
- return fs.existsSync(routesEntry) ? routesEntry : false;
175
- },
176
- updateNestedRoutesSpec: async (
177
- specPath: string,
178
- nextRoutes: Record<string, unknown>,
179
- ) => {
180
- const existingRoutes = fs.existsSync(specPath)
181
- ? await fs.readJSON(specPath)
182
- : {};
183
- await fs.outputJSON(specPath, {
184
- ...existingRoutes,
185
- ...nextRoutes,
186
- });
187
- },
150
+ handleFileChange: async () => {},
151
+ handleModifyEntrypoints: async (entrypoints: Entrypoint[]) => entrypoints,
152
+ isRouteEntry: () => false,
153
+ updateNestedRoutesSpec: async () => {},
188
154
  };
189
155
  });
190
156
 
@@ -192,264 +158,95 @@ describe('tanstack router cli plugin', () => {
192
158
  let tempDir: string | undefined;
193
159
 
194
160
  afterEach(async () => {
195
- runtimeCliMocks.handleFileChange.mockReset();
196
161
  runtimeCliMocks.handleGeneratorEntryCode.mockReset();
197
-
198
162
  if (tempDir) {
199
163
  await rm(tempDir, { recursive: true, force: true });
200
164
  tempDir = undefined;
201
165
  }
202
166
  });
203
167
 
204
- test('typechecks plugin-owned routers and register metadata under strictest', async () => {
205
- tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
206
- const srcDirectory = path.join(tempDir, 'src');
207
- await mkdir(srcDirectory, { recursive: true });
208
-
209
- await writeTanstackRouterTypesForEntries({
210
- appContext: {
211
- srcDirectory,
212
- internalSrcAlias: '@/_',
213
- entrypoints: [
214
- { entryName: 'dashboard', isMainEntry: false },
215
- { entryName: 'main', isMainEntry: true },
216
- ],
217
- } as any,
218
- generatedDirName: 'generated-router',
219
- routesByEntry: {
220
- dashboard: [
221
- {
222
- type: 'nested',
223
- id: 'layout',
224
- isRoot: true,
225
- children: [{ type: 'nested', id: 'page', index: true }],
226
- },
227
- ],
228
- main: [
229
- {
230
- type: 'nested',
231
- id: 'layout',
232
- isRoot: true,
233
- children: [{ type: 'nested', id: 'page', index: true }],
234
- },
235
- ],
236
- },
237
- });
238
-
239
- await typecheckGeneratedRegistration({
240
- entries: ['main', 'dashboard'],
241
- generatedDirName: 'generated-router',
242
- srcDirectory,
243
- });
244
- });
245
-
246
- test('typechecks register metadata for custom entry lists without routes', async () => {
247
- tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
248
- const srcDirectory = path.join(tempDir, 'src');
249
-
250
- await writeTanstackRegisterFile({
251
- entries: ['main'],
252
- generatedDirName: 'tanstack',
253
- srcDirectory,
254
- });
255
-
256
- await typecheckGeneratedRegistration({
257
- entries: ['main'],
258
- generatedDirName: 'tanstack',
259
- srcDirectory,
260
- });
261
- });
262
-
263
- test('exposes canonical route params through plugin-i18n types', async () => {
264
- tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
265
- const srcDirectory = path.join(tempDir, 'src');
266
-
267
- await writeTanstackRegisterFile({
268
- entries: ['main'],
269
- generatedDirName: 'tanstack',
270
- srcDirectory,
271
- canonicalRoutes: {
272
- '/': 'Record<string, never>',
273
- '/products/$slug': '{ "slug": string }',
274
- },
275
- });
276
-
277
- await typecheckGeneratedRegistration({
278
- entries: ['main'],
279
- generatedDirName: 'tanstack',
280
- srcDirectory,
281
- i18nRuntimeModule: '@modern-js/plugin-i18n/runtime',
282
- canonicalTypeChecks: [
283
- "import type { UltramodernCanonicalRoutes } from '@modern-js/plugin-i18n/runtime';",
284
- "const rootParams: UltramodernCanonicalRoutes['/'] = {};",
285
- "const productParams: UltramodernCanonicalRoutes['/products/$slug'] = { slug: 'tractor' };",
286
- 'void rootParams;',
287
- 'void productParams;',
288
- ],
289
- });
290
- });
291
-
292
- test('typechecks a plain TanStack register without plugin-i18n installed', async () => {
293
- tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
294
- const srcDirectory = path.join(tempDir, 'src');
295
-
296
- await writeTanstackRegisterFile({
297
- entries: ['main'],
298
- generatedDirName: 'tanstack',
299
- srcDirectory,
300
- });
301
-
302
- await typecheckGeneratedRegistration({
303
- entries: ['main'],
304
- generatedDirName: 'tanstack',
305
- srcDirectory,
306
- });
307
- });
308
-
309
- test('typechecks custom runtime module augmentations', async () => {
310
- tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
168
+ test('excludes its generated declaration from server roots only when installed', async () => {
169
+ tempDir = await fs.realpath(
170
+ await mkdtemp(path.join(tmpdir(), 'tanstack-server-roots-')),
171
+ );
311
172
  const srcDirectory = path.join(tempDir, 'src');
312
-
313
- await writeTanstackRegisterFile({
314
- entries: ['main'],
315
- generatedDirName: 'tanstack',
316
- runtimeModule: '@my-org/tanstack/runtime',
173
+ const declaration = path.join(
317
174
  srcDirectory,
318
- canonicalRoutes: {
319
- '/talks': 'Record<string, never>',
320
- },
321
- i18nRuntimeModule: '@my-org/i18n/runtime',
322
- });
323
-
324
- await typecheckGeneratedRegistration({
325
- entries: ['main'],
326
- generatedDirName: 'tanstack',
327
- srcDirectory,
328
- runtimeModule: '@my-org/tanstack/runtime',
329
- i18nRuntimeModule: '@my-org/i18n/runtime',
330
- canonicalTypeChecks: [
331
- "import type { UltramodernCanonicalRoutes } from '@my-org/i18n/runtime';",
332
- "const talksParams: UltramodernCanonicalRoutes['/talks'] = {};",
333
- 'void talksParams;',
334
- ],
175
+ 'modern-tanstack',
176
+ 'register.gen.d.ts',
177
+ );
178
+ const apiDirectory = path.join(tempDir, 'api');
179
+ const compileOptions = {
180
+ sourceDirs: [apiDirectory],
181
+ distDir: path.join(tempDir, 'dist'),
182
+ tsconfigPath: path.join(tempDir, 'tsconfig.json'),
183
+ throwErrorInsteadOfExit: true,
184
+ };
185
+ await fs.outputJSON(compileOptions.tsconfigPath, {
186
+ compilerOptions: {
187
+ module: 'commonjs',
188
+ target: 'ES2022',
189
+ types: [],
190
+ noEmitOnError: true,
191
+ skipLibCheck: false,
192
+ },
193
+ include: ['api', 'src'],
335
194
  });
336
- });
195
+ await fs.outputFile(
196
+ path.join(apiDirectory, 'index.ts'),
197
+ 'export const server = true;\n',
198
+ );
199
+ await fs.outputFile(
200
+ path.join(srcDirectory, 'routes/page.tsx'),
201
+ "import type { Missing } from 'missing-browser-only-types';\nexport const page: Missing = undefined;\n",
202
+ );
203
+ await fs.outputFile(
204
+ path.join(srcDirectory, 'modern-tanstack', 'main/router.gen.ts'),
205
+ "import { page } from '../../routes/page';\nexport const router = { page };\n",
206
+ );
207
+ await writeTanstackRegisterFile({ entries: ['main'], srcDirectory });
337
208
 
338
- test('claims custom routes, injects runtime plugin, and merges route specs', async () => {
339
- tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
340
- const srcDirectory = path.join(tempDir, 'src');
341
- const distDirectory = path.join(tempDir, 'dist');
342
- const entryDir = path.join(srcDirectory, 'main');
343
- const viewsDir = path.join(entryDir, 'views');
344
- await mkdir(viewsDir, { recursive: true });
209
+ await expect(compile(tempDir, {}, compileOptions)).rejects.toThrow(
210
+ /missing-browser-only-types/,
211
+ );
345
212
 
346
- const taps: Record<string, any> = {};
213
+ const previousExclusions = [path.join(tempDir, 'other-client.d.ts')];
347
214
  const api = {
348
- getAppContext: () => ({
215
+ ...createAppContextApi({
349
216
  srcDirectory,
350
- distDirectory,
351
- metaName: 'modern-js',
352
- serverRoutes: [{ entryName: 'main', urlPath: '/dashboard' }],
217
+ serverCompileExcludedFiles: previousExclusions,
353
218
  }),
354
- _internalRuntimePlugins: (tap: any) => {
355
- taps.internalRuntimePlugins = tap;
356
- },
357
- checkEntryPoint: (tap: any) => {
358
- taps.checkEntryPoint = tap;
359
- },
360
- config: (tap: any) => {
361
- taps.config = tap;
362
- },
363
- modifyEntrypoints: (tap: any) => {
364
- taps.modifyEntrypoints = tap;
365
- },
366
- generateEntryCode: (tap: any) => {
367
- taps.generateEntryCode = tap;
368
- },
369
- onFileChanged: (tap: any) => {
370
- taps.onFileChanged = tap;
371
- },
372
- modifyFileSystemRoutes: (tap: any) => {
373
- taps.modifyFileSystemRoutes = tap;
374
- },
375
- onBeforeGenerateRoutes: (tap: any) => {
376
- taps.onBeforeGenerateRoutes = tap;
377
- },
219
+ _internalRuntimePlugins: () => {},
220
+ checkEntryPoint: () => {},
221
+ config: () => {},
222
+ modifyEntrypoints: () => {},
223
+ generateEntryCode: () => {},
224
+ onFileChanged: () => {},
225
+ modifyFileSystemRoutes: () => {},
226
+ onBeforeGenerateRoutes: () => {},
378
227
  };
379
-
380
- tanstackRouterPlugin({ routesDir: 'views' }).setup!(api as any);
381
-
382
- expect(taps.checkEntryPoint({ path: entryDir, entry: false })).toEqual({
383
- path: entryDir,
384
- entry: viewsDir,
385
- });
386
-
387
- const { entrypoints } = await taps.modifyEntrypoints({
388
- entrypoints: [
389
- {
390
- entryName: 'main',
391
- entry: entryDir,
392
- absoluteEntryDir: entryDir,
393
- isAutoMount: true,
394
- isMainEntry: true,
395
- } as Entrypoint,
396
- ],
397
- });
398
- const [entrypoint] = entrypoints;
399
- expect(entrypoint.nestedRoutesEntry).toBe(viewsDir);
400
-
228
+ tanstackRouterPlugin().setup!(api as never);
229
+ const excludeFiles = api.getAppContext().serverCompileExcludedFiles;
230
+ expect(excludeFiles).toEqual([...previousExclusions, declaration]);
231
+ await compile(tempDir, {}, { ...compileOptions, excludeFiles });
401
232
  expect(
402
- taps.internalRuntimePlugins({ entrypoint, plugins: [] }).plugins,
403
- ).toEqual([
404
- {
405
- name: 'tanstackRouter',
406
- path: '@modern-js/plugin-tanstack/runtime',
407
- config: { serverBase: ['/dashboard'] },
408
- },
409
- ]);
410
-
411
- expect(taps.config()).toMatchObject({
412
- output: {
413
- splitRouteChunks: true,
414
- },
415
- });
416
-
417
- const specPath = path.join(distDirectory, NESTED_ROUTE_SPEC_FILE);
418
- await fs.outputJSON(specPath, {
419
- existing: [{ id: 'keep-me' }],
420
- });
421
-
422
- await taps.modifyFileSystemRoutes({
423
- entrypoint,
424
- routes: [
425
- {
426
- id: 'main-route',
427
- type: 'nested',
428
- origin: 'file-system',
429
- },
430
- ],
431
- });
432
- await taps.onBeforeGenerateRoutes({ entrypoint, code: '' });
433
-
434
- expect(await fs.readJSON(specPath)).toEqual({
435
- existing: [{ id: 'keep-me' }],
436
- main: [
437
- {
438
- id: 'main-route',
439
- type: 'nested',
440
- origin: 'file-system',
441
- },
442
- ],
443
- });
233
+ await fs.pathExists(path.join(compileOptions.distDir, 'api/index.js')),
234
+ ).toBe(true);
235
+ expect(await fs.pathExists(path.join(compileOptions.distDir, 'src'))).toBe(
236
+ false,
237
+ );
444
238
  });
445
239
 
446
- test('injects the framework-resolving router wrapper for non-file-route entrypoints', async () => {
240
+ test('installs the TanStack router only for entrypoints it owns', () => {
447
241
  const taps: Record<string, any> = {};
448
242
  const api = {
449
- getAppContext: () => ({
243
+ ...createAppContextApi({
450
244
  srcDirectory: '/tmp/app/src',
451
245
  metaName: 'modern-js',
452
- serverRoutes: [{ entryName: 'custom', urlPath: '/' }],
246
+ serverRoutes: [
247
+ { entryName: 'custom', urlPath: '/' },
248
+ { entryName: 'home', urlPath: '/' },
249
+ ],
453
250
  }),
454
251
  _internalRuntimePlugins: (tap: any) => {
455
252
  taps.internalRuntimePlugins = tap;
@@ -463,168 +260,70 @@ describe('tanstack router cli plugin', () => {
463
260
  onBeforeGenerateRoutes: () => {},
464
261
  };
465
262
 
466
- tanstackRouterPlugin().setup!(api as any);
263
+ tanstackRouterPlugin({ routesDir: 'ts-routes' }).setup!(api as any);
467
264
 
468
265
  // Custom entry without a routes dir (e.g. `createRoutes` in
469
- // modern.runtime.ts): installing the plugin is the explicit opt-in, no
470
- // source sniffing — the wrapper plus the provider registration is
471
- // injected through the package's own runtime/router module.
266
+ // modern.runtime.ts): installing the plugin is the explicit opt-in, so
267
+ // the wrapper plus the provider registration is injected through the
268
+ // package's own runtime/router module.
472
269
  const customEntrypoint = {
473
270
  entryName: 'custom',
474
271
  isAutoMount: true,
475
272
  } as Entrypoint;
273
+ const tanstackRouterEntry = {
274
+ name: 'router',
275
+ path: '@modern-js/plugin-tanstack/runtime/router',
276
+ config: { serverBase: ['/'] },
277
+ };
476
278
  expect(
477
279
  taps.internalRuntimePlugins({ entrypoint: customEntrypoint, plugins: [] })
478
280
  .plugins,
479
- ).toEqual([
480
- {
481
- name: 'router',
482
- path: '@modern-js/plugin-tanstack/runtime/router',
483
- config: { serverBase: ['/'] },
484
- },
485
- ]);
281
+ ).toEqual([tanstackRouterEntry]);
486
282
 
487
283
  // If the built-in router CLI already installed the internal router for
488
284
  // this custom entry (explicit `runtime.router` config), only the module
489
- // path is redirected so the TanStack provider registration is
490
- // value-imported with it.
491
- const existingRouterPlugin = {
285
+ // path is redirected — pushing a second entry installs two routers.
286
+ const builtInPlugin = {
492
287
  name: 'router',
493
288
  path: '@modern-js/runtime/router/internal',
494
289
  config: { serverBase: ['/'] },
495
290
  };
496
- const { plugins } = taps.internalRuntimePlugins({
497
- entrypoint: customEntrypoint,
498
- plugins: [existingRouterPlugin],
499
- });
500
- expect(plugins).toHaveLength(1);
501
- expect(plugins[0]).toEqual({
502
- name: 'router',
503
- path: '@modern-js/plugin-tanstack/runtime/router',
504
- config: { serverBase: ['/'] },
505
- });
506
- });
507
-
508
- test('leaves built-in and foreign-owned route entrypoints to their own router', () => {
509
- const taps: Record<string, any> = {};
510
- const api = {
511
- getAppContext: () => ({
512
- srcDirectory: '/tmp/app/src',
513
- metaName: 'modern-js',
514
- serverRoutes: [{ entryName: 'home', urlPath: '/' }],
515
- }),
516
- _internalRuntimePlugins: (tap: any) => {
517
- taps.internalRuntimePlugins = tap;
518
- },
519
- checkEntryPoint: () => {},
520
- config: () => {},
521
- modifyEntrypoints: () => {},
522
- generateEntryCode: () => {},
523
- onFileChanged: () => {},
524
- modifyFileSystemRoutes: () => {},
525
- onBeforeGenerateRoutes: () => {},
526
- };
527
-
528
- tanstackRouterPlugin({ routesDir: 'ts-routes' }).setup!(api as any);
291
+ expect(
292
+ taps.internalRuntimePlugins({
293
+ entrypoint: customEntrypoint,
294
+ plugins: [builtInPlugin],
295
+ }).plugins,
296
+ ).toEqual([tanstackRouterEntry]);
529
297
 
530
298
  // A classic react-router file-route entry (src/<entry>/routes) living
531
299
  // next to the TanStack entries: its internal router plugin must be left
532
- // untouched — redirecting it through the TanStack wrapper would pull
533
- // @tanstack/react-router into a pure react-router bundle.
534
- const builtInEntrypoint = {
535
- entryName: 'home',
536
- isAutoMount: true,
537
- nestedRoutesEntry: '/tmp/app/src/home/routes',
538
- __modernRoutesDir: 'routes',
539
- } as Entrypoint;
540
- const { plugins: builtInPlugins } = taps.internalRuntimePlugins({
541
- entrypoint: builtInEntrypoint,
542
- plugins: [
543
- {
544
- name: 'router',
545
- path: '@modern-js/runtime/router/internal',
546
- config: { serverBase: ['/'] },
547
- },
548
- ],
549
- });
550
- expect(builtInPlugins).toEqual([
551
- {
552
- name: 'router',
553
- path: '@modern-js/runtime/router/internal',
554
- config: { serverBase: ['/'] },
555
- },
556
- ]);
300
+ // untouched — redirecting it would pull @tanstack/react-router into a
301
+ // pure react-router bundle.
302
+ expect(
303
+ taps.internalRuntimePlugins({
304
+ entrypoint: {
305
+ entryName: 'home',
306
+ isAutoMount: true,
307
+ nestedRoutesEntry: '/tmp/app/src/home/routes',
308
+ __modernRoutesDir: 'routes',
309
+ } as Entrypoint,
310
+ plugins: [builtInPlugin],
311
+ }).plugins,
312
+ ).toEqual([builtInPlugin]);
557
313
 
558
314
  // An entry tagged by another routes-owner plugin: nothing is pushed.
559
- // The replaced sniffing path in @modern-js/runtime excluded
560
- // plugin-owned entrypoints for the same reason — pushing a second
561
- // `router` plugin can install two routers for one entry.
562
- const foreignEntrypoint = {
563
- entryName: 'home',
564
- isAutoMount: true,
565
- nestedRoutesEntry: '/tmp/app/src/home/acme-routes',
566
- __modernRoutesDir: 'acme-routes',
567
- __modernRoutesOwner: '@acme/plugin-file-router',
568
- } as Entrypoint;
569
315
  expect(
570
316
  taps.internalRuntimePlugins({
571
- entrypoint: foreignEntrypoint,
317
+ entrypoint: {
318
+ entryName: 'home',
319
+ isAutoMount: true,
320
+ nestedRoutesEntry: '/tmp/app/src/home/acme-routes',
321
+ __modernRoutesDir: 'acme-routes',
322
+ __modernRoutesOwner: '@acme/plugin-file-router',
323
+ } as Entrypoint,
572
324
  plugins: [],
573
325
  }).plugins,
574
326
  ).toEqual([]);
575
-
576
- // The built-in pages/ convention is foreign too.
577
- const pagesEntrypoint = {
578
- entryName: 'home',
579
- isAutoMount: true,
580
- pageRoutesEntry: '/tmp/app/src/home/pages',
581
- } as Entrypoint;
582
- expect(
583
- taps.internalRuntimePlugins({ entrypoint: pagesEntrypoint, plugins: [] })
584
- .plugins,
585
- ).toEqual([]);
586
- });
587
-
588
- test('source.include covers the package dist and TanStack runtime deps without string surgery', () => {
589
- const taps: Record<string, any> = {};
590
- const api = {
591
- getAppContext: () => ({
592
- srcDirectory: '/tmp/app/src',
593
- serverRoutes: [],
594
- }),
595
- _internalRuntimePlugins: () => {},
596
- checkEntryPoint: () => {},
597
- config: (tap: any) => {
598
- taps.config = tap;
599
- },
600
- modifyEntrypoints: () => {},
601
- generateEntryCode: () => {},
602
- onFileChanged: () => {},
603
- modifyFileSystemRoutes: () => {},
604
- onBeforeGenerateRoutes: () => {},
605
- };
606
-
607
- tanstackRouterPlugin().setup!(api as any);
608
-
609
- const include = taps.config().source.include as Array<RegExp | string>;
610
- const regexes = include.filter(
611
- (entry): entry is RegExp => entry instanceof RegExp,
612
- );
613
- for (const dep of ['react-router', 'router-core', 'react-store']) {
614
- const sample = `/repo/node_modules/@tanstack/${dep}/dist/esm/index.js`;
615
- expect(regexes.some(regex => regex.test(sample))).toBe(true);
616
- }
617
-
618
- const stringEntries = include.filter(
619
- (entry): entry is string => typeof entry === 'string',
620
- );
621
- expect(stringEntries).toHaveLength(1);
622
- // The include must point at the package root (two levels above the cli
623
- // build dir) so dist/esm, dist/esm-node and dist/cjs are all covered —
624
- // the old `.replace('cjs', 'esm')` never matched the bundled dist/esm
625
- // runtime when the CLI was loaded through the ESM condition.
626
- expect(stringEntries[0]).toBe(path.resolve(__dirname, '..', '..'));
627
- expect(stringEntries[0]).not.toContain('esm');
628
327
  });
629
328
 
630
329
  test('emits the plugin-i18n augmentation only when plugin-i18n is registered', async () => {
@@ -666,7 +365,7 @@ describe('tanstack router cli plugin', () => {
666
365
 
667
366
  const taps: Record<string, any> = {};
668
367
  const api = {
669
- getAppContext: () => ({
368
+ ...createAppContextApi({
670
369
  srcDirectory,
671
370
  internalSrcAlias: '@/_',
672
371
  entrypoints: [entrypoint],
@@ -718,379 +417,4 @@ describe('tanstack router cli plugin', () => {
718
417
  { name: '@modern-js/plugin-i18n' },
719
418
  ]);
720
419
  });
721
-
722
- test('generates plugin-owned TanStack route files through core route generation', async () => {
723
- tempDir = await mkdtemp(path.join(tmpdir(), 'modern-tanstack-cli-'));
724
- const srcDirectory = path.join(tempDir, 'src');
725
- const entryDir = path.join(srcDirectory, 'main');
726
- const viewsDir = path.join(entryDir, 'views');
727
- await mkdir(path.join(viewsDir, 'mf'), { recursive: true });
728
- await fs.outputFile(
729
- path.join(viewsDir, 'mf', 'page.data.ts'),
730
- [
731
- 'export const loader = () => ({ count: 0 });',
732
- 'export const action = () => Response.json({ count: 1 });',
733
- ].join('\n'),
734
- );
735
-
736
- const entrypoint = {
737
- entryName: 'main',
738
- entry: entryDir,
739
- absoluteEntryDir: entryDir,
740
- isAutoMount: true,
741
- isMainEntry: true,
742
- nestedRoutesEntry: viewsDir,
743
- __modernRoutesDir: 'views',
744
- } as Entrypoint;
745
- runtimeCliMocks.handleGeneratorEntryCode.mockResolvedValue({
746
- main: [
747
- {
748
- type: 'nested',
749
- id: 'layout',
750
- isRoot: true,
751
- children: [
752
- {
753
- type: 'nested',
754
- id: 'mf/page',
755
- path: 'mf',
756
- data: '@/_/main/views/mf/page.data',
757
- action: '@/_/main/views/mf/page.data',
758
- },
759
- ],
760
- },
761
- ],
762
- });
763
-
764
- const taps: Record<string, any> = {};
765
- const api = {
766
- getAppContext: () => ({
767
- srcDirectory,
768
- internalSrcAlias: '@/_',
769
- entrypoints: [entrypoint],
770
- }),
771
- _internalRuntimePlugins: () => {},
772
- checkEntryPoint: (tap: any) => {
773
- taps.checkEntryPoint = tap;
774
- },
775
- config: (tap: any) => {
776
- taps.config = tap;
777
- },
778
- modifyEntrypoints: (tap: any) => {
779
- taps.modifyEntrypoints = tap;
780
- },
781
- generateEntryCode: (tap: any) => {
782
- taps.generateEntryCode = tap;
783
- },
784
- onFileChanged: (tap: any) => {
785
- taps.onFileChanged = tap;
786
- },
787
- modifyFileSystemRoutes: (tap: any) => {
788
- taps.modifyFileSystemRoutes = tap;
789
- },
790
- onBeforeGenerateRoutes: (tap: any) => {
791
- taps.onBeforeGenerateRoutes = tap;
792
- },
793
- };
794
-
795
- tanstackRouterPlugin({
796
- generatedDirName: 'tanstack-generated',
797
- routesDir: 'views',
798
- }).setup!(api as any);
799
-
800
- await taps.generateEntryCode({ entrypoints: [entrypoint] });
801
-
802
- expect(runtimeCliMocks.handleGeneratorEntryCode).toHaveBeenCalledWith(
803
- api,
804
- [entrypoint],
805
- {
806
- entrypointsKey: '@modern-js/plugin-tanstack',
807
- hydrateRscClientRoutes: true,
808
- includeRouteServerLoadersInSsrEntry: false,
809
- isolateRouteDataInRscLayer: true,
810
- serverRoutesFileName: 'tanstack-routes.server.js',
811
- },
812
- );
813
-
814
- await typecheckGeneratedRegistration({
815
- entries: ['main'],
816
- generatedDirName: 'tanstack-generated',
817
- srcDirectory,
818
- });
819
- });
820
-
821
- test('regenerates plugin-owned TanStack files for scoped file changes', async () => {
822
- const regenerateEvent = {
823
- eventType: 'add',
824
- filename: 'src/main/views/page.tsx',
825
- };
826
- const entrypoint = {
827
- entryName: 'main',
828
- __modernRoutesDir: 'views',
829
- } as any as Entrypoint;
830
- const api = {
831
- getAppContext: () => ({
832
- srcDirectory: '/tmp/app/src',
833
- internalSrcAlias: '@/_',
834
- entrypoints: [entrypoint],
835
- }),
836
- _internalRuntimePlugins: () => {},
837
- checkEntryPoint: () => {},
838
- config: () => {},
839
- modifyEntrypoints: () => {},
840
- generateEntryCode: () => {},
841
- onFileChanged: (tap: any) => {
842
- api.onFileChangedTap = tap;
843
- },
844
- modifyFileSystemRoutes: () => {},
845
- onBeforeGenerateRoutes: () => {},
846
- onFileChangedTap: undefined as any,
847
- };
848
-
849
- tanstackRouterPlugin({ routesDir: 'views' }).setup!(api as any);
850
-
851
- runtimeCliMocks.handleFileChange.mockImplementationOnce(
852
- async (_api, _event, options) => {
853
- expect(options.entrypointsKey).toBe('@modern-js/plugin-tanstack');
854
- expect(options.includeEntry(entrypoint)).toBe(true);
855
- expect(
856
- options.includeEntry({
857
- ...entrypoint,
858
- __modernRoutesDir: 'routes',
859
- }),
860
- ).toBe(false);
861
- expect(typeof options.regenerate).toBe('function');
862
- },
863
- );
864
-
865
- await api.onFileChangedTap(regenerateEvent);
866
-
867
- expect(runtimeCliMocks.handleFileChange).toHaveBeenCalledWith(
868
- api,
869
- regenerateEvent,
870
- expect.objectContaining({
871
- entrypointsKey: '@modern-js/plugin-tanstack',
872
- }),
873
- );
874
- });
875
-
876
- test('can opt out of Modern-owned route code splitting', async () => {
877
- const taps: Record<string, any> = {};
878
- const api = {
879
- getAppContext: () => ({
880
- srcDirectory: '/tmp/app/src',
881
- serverRoutes: [],
882
- }),
883
- _internalRuntimePlugins: () => {},
884
- checkEntryPoint: () => {},
885
- config: (tap: any) => {
886
- taps.config = tap;
887
- },
888
- modifyEntrypoints: () => {},
889
- generateEntryCode: () => {},
890
- onFileChanged: () => {},
891
- modifyFileSystemRoutes: () => {},
892
- onBeforeGenerateRoutes: () => {},
893
- };
894
-
895
- tanstackRouterPlugin({ routeCodeSplitting: false }).setup!(api as any);
896
-
897
- expect(taps.config()).toMatchObject({
898
- output: {
899
- splitRouteChunks: false,
900
- },
901
- });
902
- });
903
-
904
- test('route splitting profile carries only the rsbuild config production consumes', () => {
905
- expect(createTanstackRsbuildRouteSplittingProfile({})).toEqual({
906
- defaultConfig: {
907
- output: {
908
- splitRouteChunks: true,
909
- },
910
- },
911
- });
912
- expect(
913
- createTanstackRsbuildRouteSplittingProfile({ routeCodeSplitting: false }),
914
- ).toEqual({
915
- defaultConfig: {
916
- output: {
917
- splitRouteChunks: false,
918
- },
919
- },
920
- });
921
- });
922
-
923
- test('preserves user-selected route and builder chunk splitting modes', () => {
924
- const pluginDefaults = createTanstackRsbuildRouteSplittingProfile(
925
- {},
926
- ).defaultConfig;
927
- const chunkSplits = [
928
- { strategy: 'split-by-module' },
929
- { strategy: 'split-by-experience' },
930
- { strategy: 'all-in-one' },
931
- { strategy: 'single-vendor' },
932
- { strategy: 'split-by-size', minSize: 10_000, maxSize: 60_000 },
933
- {
934
- strategy: 'custom',
935
- splitChunks: {
936
- chunks: 'all',
937
- cacheGroups: {
938
- tractors: {
939
- name: 'tractors',
940
- test: /tractors/u,
941
- },
942
- },
943
- },
944
- },
945
- ];
946
-
947
- for (const chunkSplit of chunkSplits) {
948
- expect(
949
- mergeConfig([
950
- pluginDefaults,
951
- {
952
- output: {
953
- splitRouteChunks: false,
954
- },
955
- performance: {
956
- chunkSplit,
957
- },
958
- splitChunks: false,
959
- },
960
- ]),
961
- ).toMatchObject({
962
- output: {
963
- splitRouteChunks: false,
964
- },
965
- performance: {
966
- chunkSplit,
967
- },
968
- splitChunks: false,
969
- });
970
- }
971
-
972
- const pageSplitWithManualAsyncChunks = mergeConfig([
973
- pluginDefaults,
974
- {
975
- performance: {
976
- chunkSplit: {
977
- strategy: 'custom',
978
- splitChunks: {
979
- chunks: 'async',
980
- },
981
- },
982
- },
983
- },
984
- ]);
985
-
986
- expect(pageSplitWithManualAsyncChunks).toMatchObject({
987
- output: {
988
- splitRouteChunks: true,
989
- },
990
- performance: {
991
- chunkSplit: {
992
- strategy: 'custom',
993
- splitChunks: {
994
- chunks: 'async',
995
- },
996
- },
997
- },
998
- });
999
- });
1000
-
1001
- test('keeps custom cache group details intact', () => {
1002
- const pluginDefaults = createTanstackRsbuildRouteSplittingProfile(
1003
- {},
1004
- ).defaultConfig;
1005
-
1006
- const mergedConfig = mergeConfig([
1007
- pluginDefaults,
1008
- {
1009
- performance: {
1010
- chunkSplit: {
1011
- strategy: 'custom',
1012
- splitChunks: {
1013
- chunks: 'all',
1014
- cacheGroups: {
1015
- tractors: {
1016
- name: 'tractors',
1017
- test: /tractors/u,
1018
- },
1019
- },
1020
- },
1021
- },
1022
- },
1023
- },
1024
- ]);
1025
-
1026
- expect(
1027
- (
1028
- mergedConfig as {
1029
- performance?: {
1030
- chunkSplit?: {
1031
- splitChunks?: {
1032
- cacheGroups?: {
1033
- tractors?: {
1034
- test?: RegExp;
1035
- };
1036
- };
1037
- };
1038
- };
1039
- };
1040
- }
1041
- ).performance?.chunkSplit?.splitChunks?.cacheGroups?.tractors?.test,
1042
- ).toEqual(/tractors/u);
1043
- expect(mergedConfig).toMatchObject({
1044
- output: {
1045
- splitRouteChunks: true,
1046
- },
1047
- performance: {
1048
- chunkSplit: {
1049
- strategy: 'custom',
1050
- splitChunks: {
1051
- chunks: 'all',
1052
- cacheGroups: {
1053
- tractors: {
1054
- name: 'tractors',
1055
- },
1056
- },
1057
- },
1058
- },
1059
- },
1060
- });
1061
- });
1062
-
1063
- test('plugin opt-out can still combine with manual builder chunking', () => {
1064
- const pluginDefaults = createTanstackRsbuildRouteSplittingProfile({
1065
- routeCodeSplitting: false,
1066
- }).defaultConfig;
1067
-
1068
- expect(
1069
- mergeConfig([
1070
- pluginDefaults,
1071
- {
1072
- performance: {
1073
- chunkSplit: {
1074
- strategy: 'single-vendor',
1075
- },
1076
- },
1077
- },
1078
- ]),
1079
- ).toMatchObject({
1080
- output: {
1081
- splitRouteChunks: false,
1082
- },
1083
- performance: {
1084
- chunkSplit: {
1085
- strategy: 'single-vendor',
1086
- },
1087
- },
1088
- });
1089
- });
1090
- });
1091
-
1092
- describe('generateTanstackRouteArtifacts export', () => {
1093
- test('is exported as a function', () => {
1094
- expect(typeof generateTanstackRouteArtifacts).toBe('function');
1095
- });
1096
420
  });