rsbuild-plugin-react-router 0.1.1 → 0.3.0
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.
- package/README.md +185 -204
- package/dist/451.js +1087 -0
- package/dist/bounded-cache.d.ts +1 -0
- package/dist/build-manifest.d.ts +1 -1
- package/dist/build-output-transforms.d.ts +30 -0
- package/dist/concurrency.d.ts +2 -0
- package/dist/config-imports.d.ts +3 -0
- package/dist/constants.d.ts +3 -0
- package/dist/dev-generation.d.ts +25 -0
- package/dist/dev-runtime-artifacts.d.ts +39 -0
- package/dist/dev-runtime-compilation.d.ts +32 -0
- package/dist/dev-runtime-controller.d.ts +14 -0
- package/dist/dev-runtime-session.d.ts +34 -0
- package/dist/dev-server.d.ts +11 -2
- package/dist/export-utils.d.ts +15 -7
- package/dist/index.cjs +3085 -1272
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2039 -1299
- package/dist/lazy-compilation.d.ts +5 -0
- package/dist/manifest.d.ts +32 -9
- package/dist/modify-browser-manifest.d.ts +30 -13
- package/dist/parallel-route-transform-protocol.d.ts +25 -0
- package/dist/parallel-route-transform-worker.d.ts +1 -0
- package/dist/parallel-route-transform-worker.js +38 -0
- package/dist/parallel-route-transforms.d.ts +14 -0
- package/dist/performance.d.ts +26 -0
- package/dist/plugin-utils.d.ts +2 -12
- package/dist/prerender-build.d.ts +32 -0
- package/dist/prerender.d.ts +28 -2
- package/dist/react-router-config.d.ts +8 -1
- package/dist/route-artifacts.d.ts +33 -0
- package/dist/route-ast.d.ts +21 -0
- package/dist/route-chunks.d.ts +9 -1
- package/dist/route-component-transform.d.ts +5 -0
- package/dist/route-export-pruning.d.ts +6 -0
- package/dist/route-export-resolution.d.ts +5 -0
- package/dist/route-transform-tasks.d.ts +47 -0
- package/dist/route-watch.d.ts +27 -0
- package/dist/server-build-plan.d.ts +22 -0
- package/dist/server-utils.d.ts +3 -2
- package/dist/templates/entry.client.js +3 -3
- package/dist/templates/entry.server.cjs +11 -8
- package/dist/templates/entry.server.js +5 -5
- package/dist/typegen.d.ts +2 -0
- package/dist/types.d.ts +30 -12
- package/dist/virtual-modules.d.ts +2 -0
- package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
- package/dist/yuku.d.ts +15 -0
- package/package.json +26 -22
- package/src/bounded-cache.ts +18 -0
- package/src/build-manifest.ts +168 -0
- package/src/build-output-transforms.ts +273 -0
- package/src/concurrency.ts +34 -0
- package/src/config-imports.ts +45 -0
- package/src/constants.ts +91 -0
- package/src/dev-generation.ts +700 -0
- package/src/dev-runtime-artifacts.ts +207 -0
- package/src/dev-runtime-compilation.ts +92 -0
- package/src/dev-runtime-controller.ts +462 -0
- package/src/dev-runtime-session.ts +184 -0
- package/src/dev-server.ts +58 -0
- package/src/export-utils.ts +219 -0
- package/src/index.ts +1025 -0
- package/src/lazy-compilation.ts +94 -0
- package/src/manifest.ts +480 -0
- package/src/modify-browser-manifest.ts +245 -0
- package/src/parallel-route-transform-protocol.ts +35 -0
- package/src/parallel-route-transform-worker.ts +82 -0
- package/src/parallel-route-transforms.ts +332 -0
- package/src/performance.ts +254 -0
- package/src/plugin-utils.ts +82 -0
- package/src/prerender-build.ts +623 -0
- package/src/prerender.ts +367 -0
- package/src/react-router-config.ts +220 -0
- package/src/route-artifacts.ts +155 -0
- package/src/route-ast.ts +163 -0
- package/src/route-chunks.ts +857 -0
- package/src/route-component-transform.ts +314 -0
- package/src/route-config.ts +106 -0
- package/src/route-export-pruning.ts +668 -0
- package/src/route-export-resolution.ts +329 -0
- package/src/route-transform-tasks.ts +249 -0
- package/src/route-watch.ts +322 -0
- package/src/server-build-plan.ts +91 -0
- package/src/server-utils.ts +210 -0
- package/src/ssr-externals.ts +59 -0
- package/src/templates/context.ts +12 -0
- package/src/templates/entry.client.tsx +12 -0
- package/src/templates/entry.server.tsx +76 -0
- package/src/typegen.ts +49 -0
- package/src/types.ts +82 -0
- package/src/validation/validate-plugin-order.ts +76 -0
- package/src/virtual-modules.ts +30 -0
- package/src/warnings/warn-on-client-source-maps.ts +96 -0
- package/src/yuku.ts +67 -0
- package/dist/906.js +0 -1
- package/dist/946.js +0 -1
- package/dist/babel.d.ts +0 -8
- package/dist/rslib-runtime.js +0 -23
|
@@ -0,0 +1,857 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Analyzer,
|
|
3
|
+
type Module,
|
|
4
|
+
type Symbol as YukuSymbol,
|
|
5
|
+
} from 'yuku-analyzer';
|
|
6
|
+
import { print } from 'yuku-codegen';
|
|
7
|
+
import { walk } from 'yuku-parser';
|
|
8
|
+
import { normalize, relative, resolve } from 'pathe';
|
|
9
|
+
|
|
10
|
+
type AnyNode = Record<string, any>;
|
|
11
|
+
|
|
12
|
+
export type RouteChunkExportName =
|
|
13
|
+
| 'clientAction'
|
|
14
|
+
| 'clientLoader'
|
|
15
|
+
| 'clientMiddleware'
|
|
16
|
+
| 'HydrateFallback';
|
|
17
|
+
|
|
18
|
+
export type RouteChunkName = 'main' | RouteChunkExportName;
|
|
19
|
+
|
|
20
|
+
export type RouteChunkConfig = {
|
|
21
|
+
splitRouteModules?: boolean | 'enforce';
|
|
22
|
+
appDirectory: string;
|
|
23
|
+
rootRouteFile: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type RouteChunkCacheEntry<T> = {
|
|
27
|
+
value: T;
|
|
28
|
+
version: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type RouteChunkCache = Map<string, RouteChunkCacheEntry<unknown>>;
|
|
32
|
+
|
|
33
|
+
export type RouteChunkInfo = {
|
|
34
|
+
exportNames: string[];
|
|
35
|
+
hasRouteChunks: boolean;
|
|
36
|
+
hasRouteChunkByExportName: Record<RouteChunkExportName, boolean>;
|
|
37
|
+
chunkedExports: RouteChunkExportName[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const routeChunkExportNames: RouteChunkExportName[] = [
|
|
41
|
+
'clientAction',
|
|
42
|
+
'clientLoader',
|
|
43
|
+
'clientMiddleware',
|
|
44
|
+
'HydrateFallback',
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export const routeChunkNames: RouteChunkName[] = [
|
|
48
|
+
'main',
|
|
49
|
+
...routeChunkExportNames,
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
export const mightContainRouteChunkExportName = (source: string): boolean =>
|
|
53
|
+
routeChunkExportNames.some(exportName => source.includes(exportName));
|
|
54
|
+
|
|
55
|
+
const createRouteChunkExportMap = (
|
|
56
|
+
getValue: (exportName: RouteChunkExportName) => boolean
|
|
57
|
+
): Record<RouteChunkExportName, boolean> =>
|
|
58
|
+
Object.fromEntries(
|
|
59
|
+
routeChunkExportNames.map(exportName => [exportName, getValue(exportName)])
|
|
60
|
+
) as Record<RouteChunkExportName, boolean>;
|
|
61
|
+
|
|
62
|
+
export const emptyRouteChunkSnippet = (): string => 'export {};';
|
|
63
|
+
|
|
64
|
+
const routeChunkQueryStringPrefix = '?route-chunk=';
|
|
65
|
+
|
|
66
|
+
const routeChunkQueryStrings: Record<RouteChunkName, string> = {
|
|
67
|
+
main: `${routeChunkQueryStringPrefix}main`,
|
|
68
|
+
clientAction: `${routeChunkQueryStringPrefix}clientAction`,
|
|
69
|
+
clientLoader: `${routeChunkQueryStringPrefix}clientLoader`,
|
|
70
|
+
clientMiddleware: `${routeChunkQueryStringPrefix}clientMiddleware`,
|
|
71
|
+
HydrateFallback: `${routeChunkQueryStringPrefix}HydrateFallback`,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const routeChunkEntrySuffix: Record<RouteChunkExportName, string> = {
|
|
75
|
+
clientAction: 'client-action',
|
|
76
|
+
clientLoader: 'client-loader',
|
|
77
|
+
clientMiddleware: 'client-middleware',
|
|
78
|
+
HydrateFallback: 'hydrate-fallback',
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const invariant: (value: unknown, message: string) => asserts value = (
|
|
82
|
+
value,
|
|
83
|
+
message
|
|
84
|
+
) => {
|
|
85
|
+
if (!value) {
|
|
86
|
+
throw new Error(message);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const getOrSetFromCache = <T>(
|
|
91
|
+
cache: RouteChunkCache,
|
|
92
|
+
key: string,
|
|
93
|
+
version: string,
|
|
94
|
+
getValue: () => T
|
|
95
|
+
): T => {
|
|
96
|
+
const entry = cache.get(key) as RouteChunkCacheEntry<T> | undefined;
|
|
97
|
+
if (entry?.version === version) {
|
|
98
|
+
return entry.value;
|
|
99
|
+
}
|
|
100
|
+
const value = getValue();
|
|
101
|
+
cache.set(key, { value, version });
|
|
102
|
+
return value;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const hasCachedValue = (
|
|
106
|
+
cache: RouteChunkCache,
|
|
107
|
+
key: string,
|
|
108
|
+
version: string
|
|
109
|
+
): boolean => cache.get(key)?.version === version;
|
|
110
|
+
|
|
111
|
+
type AnalyzedModule = {
|
|
112
|
+
module: Module;
|
|
113
|
+
// Dependency sets use these node identities. Consumers must shallow-copy
|
|
114
|
+
// any node whose children they narrow instead of mutating this cached AST.
|
|
115
|
+
program: AnyNode;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const analyzeCode = (
|
|
119
|
+
code: string,
|
|
120
|
+
cache: RouteChunkCache,
|
|
121
|
+
cacheKey: string
|
|
122
|
+
): AnalyzedModule => {
|
|
123
|
+
return getOrSetFromCache(cache, `${cacheKey}::analyzeCode`, code, () => {
|
|
124
|
+
const analyzer = new Analyzer();
|
|
125
|
+
const module = analyzer.addFile(cacheKey, code, {
|
|
126
|
+
lang: 'tsx',
|
|
127
|
+
sourceType: 'module',
|
|
128
|
+
attachComments: true,
|
|
129
|
+
});
|
|
130
|
+
const errors = module.diagnostics.filter(
|
|
131
|
+
diagnostic => diagnostic.severity === 'error'
|
|
132
|
+
);
|
|
133
|
+
if (errors.length > 0) {
|
|
134
|
+
throw new Error(errors.map(error => error.message).join('\n'));
|
|
135
|
+
}
|
|
136
|
+
return { module, program: module.ast as AnyNode };
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
type ExportDependencies = {
|
|
141
|
+
topLevelStatements: Set<AnyNode>;
|
|
142
|
+
topLevelNonModuleStatements: Set<AnyNode>;
|
|
143
|
+
importedIdentifierNames: Set<string>;
|
|
144
|
+
exportedVariableDeclarators: Set<AnyNode>;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const getTopLevelStatementForNode = (
|
|
148
|
+
module: Module,
|
|
149
|
+
node: AnyNode
|
|
150
|
+
): AnyNode => {
|
|
151
|
+
let current: AnyNode = node;
|
|
152
|
+
let parent = module.parentOf(current as never) as AnyNode | null;
|
|
153
|
+
while (parent && parent.type !== 'Program') {
|
|
154
|
+
current = parent;
|
|
155
|
+
parent = module.parentOf(current as never) as AnyNode | null;
|
|
156
|
+
}
|
|
157
|
+
invariant(parent?.type === 'Program', 'Expected node to be within Program');
|
|
158
|
+
return current;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const getVariableDeclaratorForNode = (
|
|
162
|
+
module: Module,
|
|
163
|
+
node: AnyNode
|
|
164
|
+
): AnyNode | null => {
|
|
165
|
+
let current: AnyNode | null = node;
|
|
166
|
+
while (current) {
|
|
167
|
+
if (current.type === 'VariableDeclarator') {
|
|
168
|
+
return current;
|
|
169
|
+
}
|
|
170
|
+
current = module.parentOf(current as never) as AnyNode | null;
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const getExportedName = (exported: AnyNode): string => {
|
|
176
|
+
if (exported.type === 'Identifier') {
|
|
177
|
+
return exported.name;
|
|
178
|
+
}
|
|
179
|
+
return String(exported.value);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const setsIntersect = <T>(set1: Set<T>, set2: Set<T>) => {
|
|
183
|
+
let smallerSet = set1;
|
|
184
|
+
let largerSet = set2;
|
|
185
|
+
if (set1.size > set2.size) {
|
|
186
|
+
smallerSet = set2;
|
|
187
|
+
largerSet = set1;
|
|
188
|
+
}
|
|
189
|
+
for (const element of smallerSet) {
|
|
190
|
+
if (largerSet.has(element)) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const getExportDependencies = (
|
|
198
|
+
code: string,
|
|
199
|
+
cache: RouteChunkCache,
|
|
200
|
+
cacheKey: string
|
|
201
|
+
): Map<string, ExportDependencies> => {
|
|
202
|
+
return getOrSetFromCache(
|
|
203
|
+
cache,
|
|
204
|
+
`${cacheKey}::getExportDependencies`,
|
|
205
|
+
code,
|
|
206
|
+
() => {
|
|
207
|
+
const { module } = analyzeCode(code, cache, cacheKey);
|
|
208
|
+
const exportDependencies = new Map<string, ExportDependencies>();
|
|
209
|
+
const topLevelStatementCache = new Map<AnyNode, AnyNode>();
|
|
210
|
+
const variableDeclaratorCache = new Map<AnyNode, AnyNode | null>();
|
|
211
|
+
const getCachedTopLevelStatementForNode = (node: AnyNode): AnyNode => {
|
|
212
|
+
const cached = topLevelStatementCache.get(node);
|
|
213
|
+
if (cached) {
|
|
214
|
+
return cached;
|
|
215
|
+
}
|
|
216
|
+
const statement = getTopLevelStatementForNode(module, node);
|
|
217
|
+
topLevelStatementCache.set(node, statement);
|
|
218
|
+
return statement;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const getCachedVariableDeclaratorForNode = (
|
|
222
|
+
node: AnyNode
|
|
223
|
+
): AnyNode | null => {
|
|
224
|
+
if (variableDeclaratorCache.has(node)) {
|
|
225
|
+
return variableDeclaratorCache.get(node) ?? null;
|
|
226
|
+
}
|
|
227
|
+
const declarator = getVariableDeclaratorForNode(module, node);
|
|
228
|
+
variableDeclaratorCache.set(node, declarator);
|
|
229
|
+
return declarator;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const addCachedTopLevelStatement = (
|
|
233
|
+
dependencies: ExportDependencies,
|
|
234
|
+
node: AnyNode
|
|
235
|
+
) => {
|
|
236
|
+
const statement = getCachedTopLevelStatementForNode(node);
|
|
237
|
+
dependencies.topLevelStatements.add(statement);
|
|
238
|
+
if (
|
|
239
|
+
statement.type !== 'ImportDeclaration' &&
|
|
240
|
+
!statement.type.startsWith('Export')
|
|
241
|
+
) {
|
|
242
|
+
dependencies.topLevelNonModuleStatements.add(statement);
|
|
243
|
+
}
|
|
244
|
+
return statement;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const handleExport = (
|
|
248
|
+
exportName: string,
|
|
249
|
+
exportNode: AnyNode,
|
|
250
|
+
localSymbol: YukuSymbol | null
|
|
251
|
+
) => {
|
|
252
|
+
const dependencies: ExportDependencies = {
|
|
253
|
+
topLevelStatements: new Set(),
|
|
254
|
+
topLevelNonModuleStatements: new Set(),
|
|
255
|
+
importedIdentifierNames: new Set(),
|
|
256
|
+
exportedVariableDeclarators: new Set(),
|
|
257
|
+
};
|
|
258
|
+
const visitedSymbols = new Set<YukuSymbol>();
|
|
259
|
+
const scannedNodes = new Set<AnyNode>();
|
|
260
|
+
|
|
261
|
+
const scanNode = (node: AnyNode) => {
|
|
262
|
+
if (scannedNodes.has(node)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
scannedNodes.add(node);
|
|
266
|
+
walk(node as any, {
|
|
267
|
+
Identifier(node: AnyNode) {
|
|
268
|
+
const reference = module.referenceOf(node as never);
|
|
269
|
+
if (reference?.symbol) {
|
|
270
|
+
visitSymbol(reference.symbol);
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const visitSymbol = (symbol: YukuSymbol) => {
|
|
277
|
+
if (visitedSymbols.has(symbol)) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
visitedSymbols.add(symbol);
|
|
281
|
+
|
|
282
|
+
for (const declaration of symbol.declarations as AnyNode[]) {
|
|
283
|
+
const statement = addCachedTopLevelStatement(
|
|
284
|
+
dependencies,
|
|
285
|
+
declaration
|
|
286
|
+
);
|
|
287
|
+
if (statement.type === 'ImportDeclaration') {
|
|
288
|
+
dependencies.importedIdentifierNames.add(symbol.name);
|
|
289
|
+
}
|
|
290
|
+
const declarator = getCachedVariableDeclaratorForNode(declaration);
|
|
291
|
+
if (
|
|
292
|
+
declarator &&
|
|
293
|
+
getCachedTopLevelStatementForNode(declarator).type ===
|
|
294
|
+
'ExportNamedDeclaration'
|
|
295
|
+
) {
|
|
296
|
+
dependencies.exportedVariableDeclarators.add(declarator);
|
|
297
|
+
}
|
|
298
|
+
scanNode(declarator ?? statement);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
for (const reference of symbol.references as any[]) {
|
|
302
|
+
const statement = addCachedTopLevelStatement(
|
|
303
|
+
dependencies,
|
|
304
|
+
reference.node
|
|
305
|
+
);
|
|
306
|
+
const declarator = getCachedVariableDeclaratorForNode(
|
|
307
|
+
reference.node
|
|
308
|
+
);
|
|
309
|
+
scanNode(declarator ?? statement);
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
addCachedTopLevelStatement(dependencies, exportNode);
|
|
314
|
+
|
|
315
|
+
if (localSymbol) {
|
|
316
|
+
visitSymbol(localSymbol);
|
|
317
|
+
} else {
|
|
318
|
+
const statement = getCachedTopLevelStatementForNode(exportNode);
|
|
319
|
+
scanNode(statement);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
exportDependencies.set(exportName, dependencies);
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
for (const exp of module.exports as any[]) {
|
|
326
|
+
if (exp.typeOnly || exp.isStar || exp.isExportEquals) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
handleExport(exp.name, exp.node as AnyNode, exp.local ?? null);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return exportDependencies;
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const isExportChunkable = (
|
|
338
|
+
exportName: string,
|
|
339
|
+
exportDependencies: Map<string, ExportDependencies>
|
|
340
|
+
) => {
|
|
341
|
+
const dependencies = exportDependencies.get(exportName);
|
|
342
|
+
if (!dependencies) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
for (const [currentExportName, currentDependencies] of exportDependencies) {
|
|
346
|
+
if (currentExportName === exportName) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (
|
|
350
|
+
setsIntersect(
|
|
351
|
+
currentDependencies.topLevelNonModuleStatements,
|
|
352
|
+
dependencies.topLevelNonModuleStatements
|
|
353
|
+
)
|
|
354
|
+
) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (dependencies.exportedVariableDeclarators.size > 1) {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
if (dependencies.exportedVariableDeclarators.size > 0) {
|
|
362
|
+
for (const [currentExportName, currentDependencies] of exportDependencies) {
|
|
363
|
+
if (currentExportName === exportName) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (
|
|
367
|
+
setsIntersect(
|
|
368
|
+
currentDependencies.exportedVariableDeclarators,
|
|
369
|
+
dependencies.exportedVariableDeclarators
|
|
370
|
+
)
|
|
371
|
+
) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return true;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const getChunkableExportMap = (
|
|
380
|
+
code: string,
|
|
381
|
+
cache: RouteChunkCache,
|
|
382
|
+
cacheKey: string
|
|
383
|
+
): Record<RouteChunkExportName, boolean> =>
|
|
384
|
+
getOrSetFromCache(cache, `${cacheKey}::getChunkableExportMap`, code, () => {
|
|
385
|
+
const exportDependencies = getExportDependencies(code, cache, cacheKey);
|
|
386
|
+
return createRouteChunkExportMap(exportName =>
|
|
387
|
+
isExportChunkable(exportName, exportDependencies)
|
|
388
|
+
);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
const hasChunkableExport = (
|
|
392
|
+
code: string,
|
|
393
|
+
exportName: string,
|
|
394
|
+
cache: RouteChunkCache,
|
|
395
|
+
cacheKey: string
|
|
396
|
+
) =>
|
|
397
|
+
(routeChunkExportNames as string[]).includes(exportName)
|
|
398
|
+
? getChunkableExportMap(code, cache, cacheKey)[
|
|
399
|
+
exportName as RouteChunkExportName
|
|
400
|
+
]
|
|
401
|
+
: false;
|
|
402
|
+
|
|
403
|
+
const generateCode = (program: AnyNode): string | undefined => {
|
|
404
|
+
if (program.body.length === 0) {
|
|
405
|
+
return undefined;
|
|
406
|
+
}
|
|
407
|
+
const result = print(program as any, { comments: true });
|
|
408
|
+
if (result.errors.length > 0) {
|
|
409
|
+
throw new Error(result.errors.map(error => error.message).join('\n'));
|
|
410
|
+
}
|
|
411
|
+
return result.code;
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const filterImportSpecifiers = (
|
|
415
|
+
node: AnyNode,
|
|
416
|
+
shouldKeep: (importedName: string) => boolean
|
|
417
|
+
) => {
|
|
418
|
+
if (node.specifiers.length === 0) {
|
|
419
|
+
return node;
|
|
420
|
+
}
|
|
421
|
+
const specifiers = node.specifiers.filter((specifier: AnyNode) =>
|
|
422
|
+
shouldKeep(specifier.local.name)
|
|
423
|
+
);
|
|
424
|
+
return specifiers.length > 0 ? { ...node, specifiers } : null;
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
const getChunkedExport = (
|
|
428
|
+
code: string,
|
|
429
|
+
exportName: string,
|
|
430
|
+
cache: RouteChunkCache,
|
|
431
|
+
cacheKey: string
|
|
432
|
+
): string | undefined => {
|
|
433
|
+
return getOrSetFromCache(
|
|
434
|
+
cache,
|
|
435
|
+
`${cacheKey}::getChunkedExport::${exportName}`,
|
|
436
|
+
code,
|
|
437
|
+
() => {
|
|
438
|
+
if (!hasChunkableExport(code, exportName, cache, cacheKey)) {
|
|
439
|
+
return undefined;
|
|
440
|
+
}
|
|
441
|
+
const exportDependencies = getExportDependencies(code, cache, cacheKey);
|
|
442
|
+
const dependencies = exportDependencies.get(exportName);
|
|
443
|
+
invariant(dependencies, 'Expected export to have dependencies');
|
|
444
|
+
|
|
445
|
+
const program = analyzeCode(code, cache, cacheKey).program;
|
|
446
|
+
const body = program.body
|
|
447
|
+
.filter((node: AnyNode) => dependencies.topLevelStatements.has(node))
|
|
448
|
+
.map((node: AnyNode) => {
|
|
449
|
+
if (node.type !== 'ImportDeclaration') {
|
|
450
|
+
return node;
|
|
451
|
+
}
|
|
452
|
+
if (dependencies.importedIdentifierNames.size === 0) {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
return filterImportSpecifiers(node, importedName =>
|
|
456
|
+
dependencies.importedIdentifierNames.has(importedName)
|
|
457
|
+
);
|
|
458
|
+
})
|
|
459
|
+
.map((node: AnyNode | null) => {
|
|
460
|
+
if (!node || !node.type.startsWith('Export')) {
|
|
461
|
+
return node;
|
|
462
|
+
}
|
|
463
|
+
if (node.type === 'ExportAllDeclaration') {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
467
|
+
return exportName === 'default' ? node : null;
|
|
468
|
+
}
|
|
469
|
+
const { declaration } = node;
|
|
470
|
+
if (declaration?.type === 'VariableDeclaration') {
|
|
471
|
+
const declarations = declaration.declarations.filter(
|
|
472
|
+
(declarationNode: AnyNode) =>
|
|
473
|
+
dependencies.exportedVariableDeclarators.has(declarationNode)
|
|
474
|
+
);
|
|
475
|
+
return declarations.length > 0
|
|
476
|
+
? {
|
|
477
|
+
...node,
|
|
478
|
+
declaration: { ...declaration, declarations },
|
|
479
|
+
}
|
|
480
|
+
: null;
|
|
481
|
+
}
|
|
482
|
+
if (
|
|
483
|
+
declaration?.type === 'FunctionDeclaration' ||
|
|
484
|
+
declaration?.type === 'ClassDeclaration'
|
|
485
|
+
) {
|
|
486
|
+
return declaration.id?.name === exportName ? node : null;
|
|
487
|
+
}
|
|
488
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
489
|
+
const specifiers = node.specifiers.filter(
|
|
490
|
+
(specifier: AnyNode) =>
|
|
491
|
+
getExportedName(specifier.exported) === exportName
|
|
492
|
+
);
|
|
493
|
+
return specifiers.length > 0 ? { ...node, specifiers } : null;
|
|
494
|
+
}
|
|
495
|
+
throw new Error('Unknown export node type');
|
|
496
|
+
})
|
|
497
|
+
.filter(Boolean) as AnyNode[];
|
|
498
|
+
|
|
499
|
+
return generateCode({ ...program, body });
|
|
500
|
+
}
|
|
501
|
+
);
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
const getChunkedExportCacheKey = (
|
|
505
|
+
cacheKey: string,
|
|
506
|
+
exportName: RouteChunkExportName
|
|
507
|
+
) => `${cacheKey}::getChunkedExport::${exportName}`;
|
|
508
|
+
|
|
509
|
+
const hasCachedChunkedExport = (
|
|
510
|
+
code: string,
|
|
511
|
+
exportName: RouteChunkExportName,
|
|
512
|
+
cache: RouteChunkCache,
|
|
513
|
+
cacheKey: string
|
|
514
|
+
): boolean =>
|
|
515
|
+
hasCachedValue(cache, getChunkedExportCacheKey(cacheKey, exportName), code);
|
|
516
|
+
|
|
517
|
+
const omitChunkedExports = (
|
|
518
|
+
code: string,
|
|
519
|
+
exportNames: string[],
|
|
520
|
+
cache: RouteChunkCache,
|
|
521
|
+
cacheKey: string
|
|
522
|
+
): string | undefined => {
|
|
523
|
+
return getOrSetFromCache(
|
|
524
|
+
cache,
|
|
525
|
+
`${cacheKey}::omitChunkedExports::${exportNames.join(',')}`,
|
|
526
|
+
code,
|
|
527
|
+
() => {
|
|
528
|
+
const chunkableExportMap = getChunkableExportMap(code, cache, cacheKey);
|
|
529
|
+
const exportNameSet = new Set(exportNames);
|
|
530
|
+
const isOmitted = (exportName: string) =>
|
|
531
|
+
exportNameSet.has(exportName) &&
|
|
532
|
+
Boolean(chunkableExportMap[exportName as RouteChunkExportName]);
|
|
533
|
+
const isRetained = (exportName: string) => !isOmitted(exportName);
|
|
534
|
+
|
|
535
|
+
const exportDependencies = getExportDependencies(code, cache, cacheKey);
|
|
536
|
+
const allExportNames = Array.from(exportDependencies.keys());
|
|
537
|
+
const omittedExportNames = allExportNames.filter(isOmitted);
|
|
538
|
+
const retainedExportNames = allExportNames.filter(isRetained);
|
|
539
|
+
|
|
540
|
+
const omittedStatements = new Set<AnyNode>();
|
|
541
|
+
const omittedExportedVariableDeclarators = new Set<AnyNode>();
|
|
542
|
+
const retainedImportedIdentifierNames = new Set<string>();
|
|
543
|
+
const omittedImportedIdentifierNames = new Set<string>();
|
|
544
|
+
|
|
545
|
+
for (const omittedExportName of omittedExportNames) {
|
|
546
|
+
const dependencies = exportDependencies.get(omittedExportName);
|
|
547
|
+
invariant(
|
|
548
|
+
dependencies,
|
|
549
|
+
`Expected dependencies for ${omittedExportName}`
|
|
550
|
+
);
|
|
551
|
+
for (const statement of dependencies.topLevelNonModuleStatements) {
|
|
552
|
+
omittedStatements.add(statement);
|
|
553
|
+
}
|
|
554
|
+
for (const declarator of dependencies.exportedVariableDeclarators) {
|
|
555
|
+
omittedExportedVariableDeclarators.add(declarator);
|
|
556
|
+
}
|
|
557
|
+
for (const importedName of dependencies.importedIdentifierNames) {
|
|
558
|
+
omittedImportedIdentifierNames.add(importedName);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
for (const retainedExportName of retainedExportNames) {
|
|
563
|
+
const dependencies = exportDependencies.get(retainedExportName);
|
|
564
|
+
if (!dependencies) {
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
for (const importedName of dependencies.importedIdentifierNames) {
|
|
568
|
+
retainedImportedIdentifierNames.add(importedName);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const program = analyzeCode(code, cache, cacheKey).program;
|
|
573
|
+
const body = program.body
|
|
574
|
+
.filter((node: AnyNode) => !omittedStatements.has(node))
|
|
575
|
+
.map((node: AnyNode) => {
|
|
576
|
+
if (node.type !== 'ImportDeclaration') {
|
|
577
|
+
return node;
|
|
578
|
+
}
|
|
579
|
+
return filterImportSpecifiers(node, importedName => {
|
|
580
|
+
if (retainedImportedIdentifierNames.has(importedName)) return true;
|
|
581
|
+
if (omittedImportedIdentifierNames.has(importedName)) return false;
|
|
582
|
+
return true;
|
|
583
|
+
});
|
|
584
|
+
})
|
|
585
|
+
.map((node: AnyNode | null) => {
|
|
586
|
+
if (!node || !node.type.startsWith('Export')) {
|
|
587
|
+
return node;
|
|
588
|
+
}
|
|
589
|
+
if (node.type === 'ExportAllDeclaration') {
|
|
590
|
+
return node;
|
|
591
|
+
}
|
|
592
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
593
|
+
return isOmitted('default') ? null : node;
|
|
594
|
+
}
|
|
595
|
+
if (node.declaration?.type === 'VariableDeclaration') {
|
|
596
|
+
const declarations = node.declaration.declarations.filter(
|
|
597
|
+
(declarationNode: AnyNode) =>
|
|
598
|
+
!omittedExportedVariableDeclarators.has(declarationNode)
|
|
599
|
+
);
|
|
600
|
+
return declarations.length > 0
|
|
601
|
+
? {
|
|
602
|
+
...node,
|
|
603
|
+
declaration: { ...node.declaration, declarations },
|
|
604
|
+
}
|
|
605
|
+
: null;
|
|
606
|
+
}
|
|
607
|
+
if (
|
|
608
|
+
node.declaration?.type === 'FunctionDeclaration' ||
|
|
609
|
+
node.declaration?.type === 'ClassDeclaration'
|
|
610
|
+
) {
|
|
611
|
+
return isOmitted(node.declaration.id.name) ? null : node;
|
|
612
|
+
}
|
|
613
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
614
|
+
const specifiers = node.specifiers.filter((specifier: AnyNode) => {
|
|
615
|
+
const exportedName = getExportedName(specifier.exported);
|
|
616
|
+
return !isOmitted(exportedName);
|
|
617
|
+
});
|
|
618
|
+
return specifiers.length > 0 || node.declaration
|
|
619
|
+
? { ...node, specifiers }
|
|
620
|
+
: null;
|
|
621
|
+
}
|
|
622
|
+
throw new Error('Unknown node type');
|
|
623
|
+
})
|
|
624
|
+
.filter(Boolean) as AnyNode[];
|
|
625
|
+
|
|
626
|
+
return generateCode({ ...program, body });
|
|
627
|
+
}
|
|
628
|
+
);
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
const precomputeChunkedExports = (
|
|
632
|
+
code: string,
|
|
633
|
+
cache: RouteChunkCache,
|
|
634
|
+
cacheKey: string
|
|
635
|
+
) => {
|
|
636
|
+
const chunkableExportMap = getChunkableExportMap(code, cache, cacheKey);
|
|
637
|
+
for (const exportName of routeChunkExportNames) {
|
|
638
|
+
if (!chunkableExportMap[exportName]) {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
if (!hasCachedChunkedExport(code, exportName, cache, cacheKey)) {
|
|
642
|
+
getChunkedExport(code, exportName, cache, cacheKey);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
export const detectRouteChunks = (
|
|
648
|
+
code: string,
|
|
649
|
+
cache: RouteChunkCache | undefined,
|
|
650
|
+
cacheKey: string
|
|
651
|
+
): RouteChunkInfo => {
|
|
652
|
+
const analysisCache = cache ?? new Map();
|
|
653
|
+
const exportDependencies = getExportDependencies(
|
|
654
|
+
code,
|
|
655
|
+
analysisCache,
|
|
656
|
+
cacheKey
|
|
657
|
+
);
|
|
658
|
+
const hasRouteChunkByExportName = getChunkableExportMap(
|
|
659
|
+
code,
|
|
660
|
+
analysisCache,
|
|
661
|
+
cacheKey
|
|
662
|
+
);
|
|
663
|
+
const chunkedExports = Object.entries(hasRouteChunkByExportName)
|
|
664
|
+
.filter(([, isChunked]) => isChunked)
|
|
665
|
+
.map(([exportName]) => exportName as RouteChunkExportName);
|
|
666
|
+
const hasRouteChunks = chunkedExports.length > 0;
|
|
667
|
+
return {
|
|
668
|
+
exportNames: Array.from(exportDependencies.keys()),
|
|
669
|
+
hasRouteChunks,
|
|
670
|
+
hasRouteChunkByExportName,
|
|
671
|
+
chunkedExports,
|
|
672
|
+
};
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
export const getRouteChunkCode: (
|
|
676
|
+
code: string,
|
|
677
|
+
chunkName: RouteChunkName,
|
|
678
|
+
cache: RouteChunkCache | undefined,
|
|
679
|
+
cacheKey: string
|
|
680
|
+
) => string | undefined = (
|
|
681
|
+
code: string,
|
|
682
|
+
chunkName: RouteChunkName,
|
|
683
|
+
cache: RouteChunkCache | undefined,
|
|
684
|
+
cacheKey: string
|
|
685
|
+
) => {
|
|
686
|
+
const analysisCache = cache ?? new Map();
|
|
687
|
+
if (chunkName === 'main') {
|
|
688
|
+
return omitChunkedExports(
|
|
689
|
+
code,
|
|
690
|
+
routeChunkExportNames,
|
|
691
|
+
analysisCache,
|
|
692
|
+
cacheKey
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
if (!hasCachedChunkedExport(code, chunkName, analysisCache, cacheKey)) {
|
|
696
|
+
precomputeChunkedExports(code, analysisCache, cacheKey);
|
|
697
|
+
}
|
|
698
|
+
return getChunkedExport(code, chunkName, analysisCache, cacheKey);
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
export const getRouteChunkModuleId = (
|
|
702
|
+
filePath: string,
|
|
703
|
+
chunkName: RouteChunkName
|
|
704
|
+
) => `${filePath}${routeChunkQueryStrings[chunkName]}`;
|
|
705
|
+
|
|
706
|
+
export const isRouteChunkModuleId: (id: string) => boolean = (id: string) =>
|
|
707
|
+
getRouteChunkNameFromModuleId(id) !== null;
|
|
708
|
+
|
|
709
|
+
const isRouteChunkName = (name: string): name is RouteChunkName =>
|
|
710
|
+
name === 'main' || (routeChunkExportNames as string[]).includes(name);
|
|
711
|
+
|
|
712
|
+
export const getRouteChunkNameFromModuleId = (
|
|
713
|
+
id: string
|
|
714
|
+
): RouteChunkName | null => {
|
|
715
|
+
const queryIndex = id.indexOf(routeChunkQueryStringPrefix);
|
|
716
|
+
if (queryIndex === -1) {
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
const chunkNameStart = queryIndex + routeChunkQueryStringPrefix.length;
|
|
720
|
+
const chunkNameEnd = id.indexOf('&', chunkNameStart);
|
|
721
|
+
const chunkName = id.slice(
|
|
722
|
+
chunkNameStart,
|
|
723
|
+
chunkNameEnd === -1 ? undefined : chunkNameEnd
|
|
724
|
+
);
|
|
725
|
+
if (!isRouteChunkName(chunkName)) {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
return chunkName;
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
const normalizeRelativeFilePath = (file: string, appDirectory: string) => {
|
|
732
|
+
const fullPath = resolve(appDirectory, file);
|
|
733
|
+
const relativePath = relative(appDirectory, fullPath);
|
|
734
|
+
return normalize(relativePath).split('?')[0];
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
const isRootRouteModuleId = (config: RouteChunkConfig, id: string) =>
|
|
738
|
+
normalizeRelativeFilePath(id, config.appDirectory) === config.rootRouteFile;
|
|
739
|
+
|
|
740
|
+
export const shouldAnalyzeRouteChunks = (
|
|
741
|
+
config: RouteChunkConfig,
|
|
742
|
+
id: string,
|
|
743
|
+
code: string
|
|
744
|
+
): boolean =>
|
|
745
|
+
Boolean(config.splitRouteModules) &&
|
|
746
|
+
mightContainRouteChunkExportName(code) &&
|
|
747
|
+
!isRootRouteModuleId(config, id);
|
|
748
|
+
|
|
749
|
+
export const createEmptyRouteChunkByExportName = (): Record<
|
|
750
|
+
RouteChunkExportName,
|
|
751
|
+
boolean
|
|
752
|
+
> => createRouteChunkExportMap(() => false);
|
|
753
|
+
|
|
754
|
+
export const buildEnforceChunkValidity = (
|
|
755
|
+
exportNames: readonly string[]
|
|
756
|
+
): Record<RouteChunkExportName, boolean> => {
|
|
757
|
+
const exportNameSet = new Set(exportNames);
|
|
758
|
+
return createRouteChunkExportMap(
|
|
759
|
+
exportName => !exportNameSet.has(exportName)
|
|
760
|
+
);
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
export const buildManifestChunkValidity = (
|
|
764
|
+
exportNames: ReadonlySet<string>,
|
|
765
|
+
hasRouteChunkByExportName: Readonly<Record<RouteChunkExportName, boolean>>
|
|
766
|
+
): Record<RouteChunkExportName, boolean> =>
|
|
767
|
+
createRouteChunkExportMap(
|
|
768
|
+
exportName =>
|
|
769
|
+
!exportNames.has(exportName) || hasRouteChunkByExportName[exportName]
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
export const detectRouteChunksIfEnabled: (
|
|
773
|
+
cache: RouteChunkCache | undefined,
|
|
774
|
+
config: RouteChunkConfig,
|
|
775
|
+
id: string,
|
|
776
|
+
code: string
|
|
777
|
+
) => Promise<RouteChunkInfo> = async (
|
|
778
|
+
cache: RouteChunkCache | undefined,
|
|
779
|
+
config: RouteChunkConfig,
|
|
780
|
+
id: string,
|
|
781
|
+
code: string
|
|
782
|
+
) => {
|
|
783
|
+
const noRouteChunks = (): RouteChunkInfo => ({
|
|
784
|
+
exportNames: [],
|
|
785
|
+
chunkedExports: [] as RouteChunkExportName[],
|
|
786
|
+
hasRouteChunks: false,
|
|
787
|
+
hasRouteChunkByExportName: createEmptyRouteChunkByExportName(),
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
if (!shouldAnalyzeRouteChunks(config, id, code)) {
|
|
791
|
+
return noRouteChunks();
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const cacheKey = normalizeRelativeFilePath(id, config.appDirectory);
|
|
795
|
+
return detectRouteChunks(code, cache, cacheKey);
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
export const getRouteChunkIfEnabled: (
|
|
799
|
+
cache: RouteChunkCache | undefined,
|
|
800
|
+
config: RouteChunkConfig,
|
|
801
|
+
id: string,
|
|
802
|
+
chunkName: RouteChunkName,
|
|
803
|
+
code: string
|
|
804
|
+
) => Promise<string | null> = async (
|
|
805
|
+
cache: RouteChunkCache | undefined,
|
|
806
|
+
config: RouteChunkConfig,
|
|
807
|
+
id: string,
|
|
808
|
+
chunkName: RouteChunkName,
|
|
809
|
+
code: string
|
|
810
|
+
) => {
|
|
811
|
+
if (!config.splitRouteModules) {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
if (chunkName === 'main') {
|
|
815
|
+
if (!mightContainRouteChunkExportName(code)) {
|
|
816
|
+
return code;
|
|
817
|
+
}
|
|
818
|
+
} else if (!code.includes(chunkName)) {
|
|
819
|
+
return null;
|
|
820
|
+
}
|
|
821
|
+
const cacheKey = normalizeRelativeFilePath(id, config.appDirectory);
|
|
822
|
+
return getRouteChunkCode(code, chunkName, cache, cacheKey) ?? null;
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
export const validateRouteChunks: (args: {
|
|
826
|
+
config: RouteChunkConfig;
|
|
827
|
+
id: string;
|
|
828
|
+
valid: Record<RouteChunkExportName, boolean>;
|
|
829
|
+
}) => void = ({ config, id, valid }) => {
|
|
830
|
+
if (isRootRouteModuleId(config, id)) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const invalidChunks = Object.entries(valid)
|
|
834
|
+
.filter(([, isValid]) => !isValid)
|
|
835
|
+
.map(([chunkName]) => chunkName);
|
|
836
|
+
if (invalidChunks.length === 0) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
const plural = invalidChunks.length > 1;
|
|
840
|
+
throw new Error(
|
|
841
|
+
[
|
|
842
|
+
`Error splitting route module: ${normalizeRelativeFilePath(
|
|
843
|
+
id,
|
|
844
|
+
config.appDirectory
|
|
845
|
+
)}`,
|
|
846
|
+
invalidChunks.map(name => `- ${name}`).join('\n'),
|
|
847
|
+
`${plural ? 'These exports' : 'This export'} could not be split into ${
|
|
848
|
+
plural ? 'their own chunks' : 'its own chunk'
|
|
849
|
+
} because ${plural ? 'they share' : 'it shares'} code with other exports. You should extract any shared code into its own module and then import it within the route module.`,
|
|
850
|
+
].join('\n\n')
|
|
851
|
+
);
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
export const getRouteChunkEntryName = (
|
|
855
|
+
routeId: string,
|
|
856
|
+
chunkName: RouteChunkExportName
|
|
857
|
+
) => `${routeId}-${routeChunkEntrySuffix[chunkName]}`;
|