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.
Files changed (99) hide show
  1. package/README.md +185 -204
  2. package/dist/451.js +1087 -0
  3. package/dist/bounded-cache.d.ts +1 -0
  4. package/dist/build-manifest.d.ts +1 -1
  5. package/dist/build-output-transforms.d.ts +30 -0
  6. package/dist/concurrency.d.ts +2 -0
  7. package/dist/config-imports.d.ts +3 -0
  8. package/dist/constants.d.ts +3 -0
  9. package/dist/dev-generation.d.ts +25 -0
  10. package/dist/dev-runtime-artifacts.d.ts +39 -0
  11. package/dist/dev-runtime-compilation.d.ts +32 -0
  12. package/dist/dev-runtime-controller.d.ts +14 -0
  13. package/dist/dev-runtime-session.d.ts +34 -0
  14. package/dist/dev-server.d.ts +11 -2
  15. package/dist/export-utils.d.ts +15 -7
  16. package/dist/index.cjs +3085 -1272
  17. package/dist/index.d.ts +4 -1
  18. package/dist/index.js +2039 -1299
  19. package/dist/lazy-compilation.d.ts +5 -0
  20. package/dist/manifest.d.ts +32 -9
  21. package/dist/modify-browser-manifest.d.ts +30 -13
  22. package/dist/parallel-route-transform-protocol.d.ts +25 -0
  23. package/dist/parallel-route-transform-worker.d.ts +1 -0
  24. package/dist/parallel-route-transform-worker.js +38 -0
  25. package/dist/parallel-route-transforms.d.ts +14 -0
  26. package/dist/performance.d.ts +26 -0
  27. package/dist/plugin-utils.d.ts +2 -12
  28. package/dist/prerender-build.d.ts +32 -0
  29. package/dist/prerender.d.ts +28 -2
  30. package/dist/react-router-config.d.ts +8 -1
  31. package/dist/route-artifacts.d.ts +33 -0
  32. package/dist/route-ast.d.ts +21 -0
  33. package/dist/route-chunks.d.ts +9 -1
  34. package/dist/route-component-transform.d.ts +5 -0
  35. package/dist/route-export-pruning.d.ts +6 -0
  36. package/dist/route-export-resolution.d.ts +5 -0
  37. package/dist/route-transform-tasks.d.ts +47 -0
  38. package/dist/route-watch.d.ts +27 -0
  39. package/dist/server-build-plan.d.ts +22 -0
  40. package/dist/server-utils.d.ts +3 -2
  41. package/dist/templates/entry.client.js +3 -3
  42. package/dist/templates/entry.server.cjs +11 -8
  43. package/dist/templates/entry.server.js +5 -5
  44. package/dist/typegen.d.ts +2 -0
  45. package/dist/types.d.ts +30 -12
  46. package/dist/virtual-modules.d.ts +2 -0
  47. package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
  48. package/dist/yuku.d.ts +15 -0
  49. package/package.json +26 -22
  50. package/src/bounded-cache.ts +18 -0
  51. package/src/build-manifest.ts +168 -0
  52. package/src/build-output-transforms.ts +273 -0
  53. package/src/concurrency.ts +34 -0
  54. package/src/config-imports.ts +45 -0
  55. package/src/constants.ts +91 -0
  56. package/src/dev-generation.ts +700 -0
  57. package/src/dev-runtime-artifacts.ts +207 -0
  58. package/src/dev-runtime-compilation.ts +92 -0
  59. package/src/dev-runtime-controller.ts +462 -0
  60. package/src/dev-runtime-session.ts +184 -0
  61. package/src/dev-server.ts +58 -0
  62. package/src/export-utils.ts +219 -0
  63. package/src/index.ts +1025 -0
  64. package/src/lazy-compilation.ts +94 -0
  65. package/src/manifest.ts +480 -0
  66. package/src/modify-browser-manifest.ts +245 -0
  67. package/src/parallel-route-transform-protocol.ts +35 -0
  68. package/src/parallel-route-transform-worker.ts +82 -0
  69. package/src/parallel-route-transforms.ts +332 -0
  70. package/src/performance.ts +254 -0
  71. package/src/plugin-utils.ts +82 -0
  72. package/src/prerender-build.ts +623 -0
  73. package/src/prerender.ts +367 -0
  74. package/src/react-router-config.ts +220 -0
  75. package/src/route-artifacts.ts +155 -0
  76. package/src/route-ast.ts +163 -0
  77. package/src/route-chunks.ts +857 -0
  78. package/src/route-component-transform.ts +314 -0
  79. package/src/route-config.ts +106 -0
  80. package/src/route-export-pruning.ts +668 -0
  81. package/src/route-export-resolution.ts +329 -0
  82. package/src/route-transform-tasks.ts +249 -0
  83. package/src/route-watch.ts +322 -0
  84. package/src/server-build-plan.ts +91 -0
  85. package/src/server-utils.ts +210 -0
  86. package/src/ssr-externals.ts +59 -0
  87. package/src/templates/context.ts +12 -0
  88. package/src/templates/entry.client.tsx +12 -0
  89. package/src/templates/entry.server.tsx +76 -0
  90. package/src/typegen.ts +49 -0
  91. package/src/types.ts +82 -0
  92. package/src/validation/validate-plugin-order.ts +76 -0
  93. package/src/virtual-modules.ts +30 -0
  94. package/src/warnings/warn-on-client-source-maps.ts +96 -0
  95. package/src/yuku.ts +67 -0
  96. package/dist/906.js +0 -1
  97. package/dist/946.js +0 -1
  98. package/dist/babel.d.ts +0 -8
  99. package/dist/rslib-runtime.js +0 -23
@@ -0,0 +1,314 @@
1
+ import {
2
+ NAMED_COMPONENT_EXPORTS,
3
+ NAMED_COMPONENT_EXPORTS_SET,
4
+ } from './constants.js';
5
+ import type { ParseResult } from 'yuku-parser';
6
+ import {
7
+ callExpression,
8
+ exportNamedDeclaration,
9
+ exportSpecifier,
10
+ getExportedName,
11
+ getProgram,
12
+ identifier,
13
+ importDeclaration,
14
+ patternIncludesName,
15
+ variableDeclaration,
16
+ type AnyNode,
17
+ } from './route-ast.js';
18
+
19
+ export function toFunctionExpression(decl: AnyNode): AnyNode {
20
+ return {
21
+ ...decl,
22
+ type: 'FunctionExpression',
23
+ declare: undefined,
24
+ };
25
+ }
26
+
27
+ export function toClassExpression(decl: AnyNode): AnyNode {
28
+ return {
29
+ ...decl,
30
+ type: 'ClassExpression',
31
+ declare: undefined,
32
+ };
33
+ }
34
+
35
+ const getComponentExportName = (exportedName: string): string | null => {
36
+ if (exportedName === 'default') {
37
+ return 'Component';
38
+ }
39
+ return isNamedComponentExport(exportedName) ? exportedName : null;
40
+ };
41
+
42
+ const getImportInsertionIndex = (program: AnyNode): number => {
43
+ let index = 0;
44
+ for (const statement of program.body ?? []) {
45
+ if (
46
+ statement.type !== 'ExpressionStatement' ||
47
+ (statement.directive === undefined &&
48
+ statement.expression?.type !== 'Literal')
49
+ ) {
50
+ break;
51
+ }
52
+ index += 1;
53
+ }
54
+ return index;
55
+ };
56
+
57
+ const declarationIncludesName = (
58
+ declaration: AnyNode,
59
+ name: string
60
+ ): boolean => {
61
+ if (declaration.type === 'VariableDeclaration') {
62
+ return (declaration.declarations ?? []).some((declarator: AnyNode) =>
63
+ patternIncludesName(declarator.id, name)
64
+ );
65
+ }
66
+ if (
67
+ (declaration.type === 'FunctionDeclaration' ||
68
+ declaration.type === 'ClassDeclaration' ||
69
+ declaration.type === 'TSEnumDeclaration') &&
70
+ declaration.id?.name
71
+ ) {
72
+ return declaration.id.name === name;
73
+ }
74
+ if (declaration.type === 'ImportDeclaration') {
75
+ return (declaration.specifiers ?? []).some(
76
+ (specifier: AnyNode) => specifier.local?.name === name
77
+ );
78
+ }
79
+ return false;
80
+ };
81
+
82
+ const hasTopLevelBindingName = (program: AnyNode, name: string): boolean => {
83
+ for (const statement of program.body ?? []) {
84
+ if (statement.type === 'ImportDeclaration') {
85
+ if (declarationIncludesName(statement, name)) {
86
+ return true;
87
+ }
88
+ continue;
89
+ }
90
+
91
+ if (statement.type === 'ExportDefaultDeclaration') {
92
+ if (statement.declaration?.id?.name === name) {
93
+ return true;
94
+ }
95
+ continue;
96
+ }
97
+
98
+ const declaration =
99
+ statement.type === 'ExportNamedDeclaration'
100
+ ? statement.declaration
101
+ : statement;
102
+ if (declaration && declarationIncludesName(declaration, name)) {
103
+ return true;
104
+ }
105
+ }
106
+ return false;
107
+ };
108
+
109
+ export const transformRoute = (ast: ParseResult | AnyNode): void => {
110
+ const program = getProgram(ast);
111
+ const usedNames = new Set<string>();
112
+ const hocs: Array<[string, string]> = [];
113
+ const componentWrapperDeclarations: AnyNode[] = [];
114
+
115
+ function getUid(name: string) {
116
+ let uid = `_${name}`;
117
+ let index = 2;
118
+ while (usedNames.has(uid) || hasTopLevelBindingName(program, uid)) {
119
+ uid = `_${name}${index++}`;
120
+ }
121
+ usedNames.add(uid);
122
+ return uid;
123
+ }
124
+
125
+ function getHocUid(hocName: string) {
126
+ const uid = getUid(hocName);
127
+ hocs.push([hocName, uid]);
128
+ return identifier(uid);
129
+ }
130
+
131
+ function wrapNamedComponentDeclaration(name: string, declaration: AnyNode) {
132
+ const uid = getHocUid(`with${name}Props`);
133
+ const expression =
134
+ declaration.type === 'FunctionDeclaration'
135
+ ? toFunctionExpression(declaration)
136
+ : declaration.type === 'ClassDeclaration'
137
+ ? toClassExpression(declaration)
138
+ : declaration;
139
+ return variableDeclaration(name, callExpression(uid, [expression]));
140
+ }
141
+
142
+ for (const statement of [...(program.body ?? [])]) {
143
+ if (statement.type === 'ExportDefaultDeclaration') {
144
+ const declaration = statement.declaration;
145
+ if (!declaration) {
146
+ continue;
147
+ }
148
+ if (
149
+ declaration.declare === true ||
150
+ declaration.type === 'TSInterfaceDeclaration'
151
+ ) {
152
+ continue;
153
+ }
154
+ const uid = getHocUid('withComponentProps');
155
+ if (
156
+ (declaration.type === 'FunctionDeclaration' ||
157
+ declaration.type === 'ClassDeclaration') &&
158
+ declaration.id?.name
159
+ ) {
160
+ const statementIndex = program.body.indexOf(statement);
161
+ program.body.splice(statementIndex, 0, declaration);
162
+ statement.declaration = callExpression(uid, [
163
+ identifier(declaration.id.name),
164
+ ]);
165
+ continue;
166
+ }
167
+ const expression =
168
+ declaration.type === 'FunctionDeclaration'
169
+ ? toFunctionExpression(declaration)
170
+ : declaration.type === 'ClassDeclaration'
171
+ ? toClassExpression(declaration)
172
+ : declaration;
173
+ statement.declaration = callExpression(uid, [expression]);
174
+ continue;
175
+ }
176
+
177
+ if (statement.type !== 'ExportNamedDeclaration') {
178
+ continue;
179
+ }
180
+ if (statement.exportKind === 'type') {
181
+ continue;
182
+ }
183
+ const declaration = statement.declaration;
184
+ if (declaration?.type === 'VariableDeclaration') {
185
+ for (const declarator of declaration.declarations ?? []) {
186
+ if (
187
+ declarator.id?.type !== 'Identifier' ||
188
+ !declarator.init ||
189
+ !isNamedComponentExport(declarator.id.name)
190
+ ) {
191
+ continue;
192
+ }
193
+ const uid = getHocUid(`with${declarator.id.name}Props`);
194
+ declarator.init = callExpression(uid, [declarator.init]);
195
+ }
196
+ continue;
197
+ }
198
+
199
+ if (
200
+ (declaration?.type === 'FunctionDeclaration' ||
201
+ declaration?.type === 'ClassDeclaration') &&
202
+ declaration.id?.name &&
203
+ isNamedComponentExport(declaration.id.name)
204
+ ) {
205
+ const name = declaration.id.name;
206
+ statement.declaration = wrapNamedComponentDeclaration(name, declaration);
207
+ continue;
208
+ }
209
+
210
+ if (statement.source) {
211
+ const importSpecifiers: Array<{ local: string; imported: string }> = [];
212
+ const sourceWrapperDeclarations: AnyNode[] = [];
213
+ const wrappedExportSpecifiers: AnyNode[] = [];
214
+ statement.specifiers = (statement.specifiers ?? []).filter(
215
+ (specifier: AnyNode) => {
216
+ if (
217
+ specifier.type !== 'ExportSpecifier' ||
218
+ specifier.exportKind === 'type'
219
+ ) {
220
+ return true;
221
+ }
222
+ const exportedName = getExportedName(specifier);
223
+ const importedName = getExportedName(specifier.local);
224
+ const componentExportName = exportedName
225
+ ? getComponentExportName(exportedName)
226
+ : null;
227
+ if (!exportedName || !importedName || !componentExportName) {
228
+ return true;
229
+ }
230
+ const sourceLocalName = getUid(`${exportedName}Source`);
231
+ const wrappedLocalName = getUid(exportedName);
232
+ const uid = getHocUid(`with${componentExportName}Props`);
233
+ importSpecifiers.push({
234
+ imported: importedName,
235
+ local: sourceLocalName,
236
+ });
237
+ sourceWrapperDeclarations.push(
238
+ variableDeclaration(
239
+ wrappedLocalName,
240
+ callExpression(uid, [identifier(sourceLocalName)])
241
+ )
242
+ );
243
+ wrappedExportSpecifiers.push(
244
+ exportSpecifier(wrappedLocalName, exportedName)
245
+ );
246
+ return false;
247
+ }
248
+ );
249
+ if (importSpecifiers.length > 0) {
250
+ const statementIndex = program.body.indexOf(statement);
251
+ const replacementStatements = [
252
+ importDeclaration(importSpecifiers, String(statement.source.value)),
253
+ ];
254
+ if (statement.specifiers.length > 0) {
255
+ replacementStatements.push(statement);
256
+ }
257
+ replacementStatements.push(...sourceWrapperDeclarations);
258
+ replacementStatements.push(
259
+ exportNamedDeclaration(wrappedExportSpecifiers)
260
+ );
261
+ program.body.splice(statementIndex, 1, ...replacementStatements);
262
+ }
263
+ continue;
264
+ }
265
+
266
+ for (const specifier of statement.specifiers ?? []) {
267
+ if (
268
+ specifier.type !== 'ExportSpecifier' ||
269
+ specifier.exportKind === 'type'
270
+ ) {
271
+ continue;
272
+ }
273
+ const exportedName = getExportedName(specifier);
274
+ const componentExportName = exportedName
275
+ ? getComponentExportName(exportedName)
276
+ : null;
277
+ if (!exportedName || !componentExportName) {
278
+ continue;
279
+ }
280
+ const localName = specifier.local?.name;
281
+ if (!localName) {
282
+ continue;
283
+ }
284
+ const wrappedLocalName = getUid(exportedName);
285
+ const uid = getHocUid(`with${componentExportName}Props`);
286
+ componentWrapperDeclarations.push(
287
+ variableDeclaration(
288
+ wrappedLocalName,
289
+ callExpression(uid, [identifier(localName)])
290
+ )
291
+ );
292
+ specifier.local = identifier(wrappedLocalName);
293
+ }
294
+ }
295
+
296
+ program.body.push(...componentWrapperDeclarations);
297
+
298
+ if (hocs.length > 0) {
299
+ program.body.splice(
300
+ getImportInsertionIndex(program),
301
+ 0,
302
+ importDeclaration(
303
+ hocs.map(([name, local]) => ({ imported: name, local })),
304
+ 'virtual/react-router/with-props'
305
+ )
306
+ );
307
+ }
308
+ };
309
+
310
+ function isNamedComponentExport(
311
+ name: string
312
+ ): name is (typeof NAMED_COMPONENT_EXPORTS)[number] {
313
+ return NAMED_COMPONENT_EXPORTS_SET.has(name);
314
+ }
@@ -0,0 +1,106 @@
1
+ import type { RouteConfigEntry } from '@react-router/dev/routes';
2
+
3
+ type ValidationResult =
4
+ | { valid: true; routeConfig: RouteConfigEntry[] }
5
+ | { valid: false; message: string };
6
+
7
+ const isPlainObject = (value: unknown): value is Record<string, unknown> =>
8
+ typeof value === 'object' && value !== null;
9
+
10
+ const isThenable = (value: unknown): value is Promise<unknown> =>
11
+ isPlainObject(value) && 'then' in value && 'catch' in value;
12
+
13
+ const validateEntry = (
14
+ entry: unknown,
15
+ path: string,
16
+ issues: string[]
17
+ ): entry is RouteConfigEntry => {
18
+ if (isThenable(entry)) {
19
+ issues.push(
20
+ `${path}\nInvalid type: Expected object but received a promise. Did you forget to await?`
21
+ );
22
+ return false;
23
+ }
24
+ if (!isPlainObject(entry)) {
25
+ issues.push(`${path}\nInvalid type: Expected object.`);
26
+ return false;
27
+ }
28
+ if (typeof entry.file !== 'string') {
29
+ issues.push(`${path}.file\nInvalid type: Expected string.`);
30
+ }
31
+ if ('id' in entry && entry.id === 'root') {
32
+ issues.push(`${path}.id\nA route cannot use the reserved id 'root'.`);
33
+ }
34
+ if (
35
+ 'path' in entry &&
36
+ entry.path !== undefined &&
37
+ typeof entry.path !== 'string'
38
+ ) {
39
+ issues.push(`${path}.path\nInvalid type: Expected string.`);
40
+ }
41
+ if (
42
+ 'index' in entry &&
43
+ entry.index !== undefined &&
44
+ typeof entry.index !== 'boolean'
45
+ ) {
46
+ issues.push(`${path}.index\nInvalid type: Expected boolean.`);
47
+ }
48
+ if (
49
+ 'caseSensitive' in entry &&
50
+ entry.caseSensitive !== undefined &&
51
+ typeof entry.caseSensitive !== 'boolean'
52
+ ) {
53
+ issues.push(`${path}.caseSensitive\nInvalid type: Expected boolean.`);
54
+ }
55
+ if ('children' in entry && entry.children !== undefined) {
56
+ if (!Array.isArray(entry.children)) {
57
+ issues.push(`${path}.children\nInvalid type: Expected array.`);
58
+ } else {
59
+ entry.children.forEach((child, index) =>
60
+ validateEntry(child, `${path}.children.${index}`, issues)
61
+ );
62
+ }
63
+ }
64
+ return issues.length === 0;
65
+ };
66
+
67
+ export const validateRouteConfig = ({
68
+ routeConfigFile,
69
+ routeConfig,
70
+ }: {
71
+ routeConfigFile: string;
72
+ routeConfig: unknown;
73
+ }): ValidationResult => {
74
+ if (!routeConfig) {
75
+ return {
76
+ valid: false,
77
+ message: `Route config must be the default export in "${routeConfigFile}".`,
78
+ };
79
+ }
80
+ if (!Array.isArray(routeConfig)) {
81
+ return {
82
+ valid: false,
83
+ message: `Route config in "${routeConfigFile}" must be an array.`,
84
+ };
85
+ }
86
+
87
+ const issues: string[] = [];
88
+ routeConfig.forEach((entry, index) =>
89
+ validateEntry(entry, `routes.${index}`, issues)
90
+ );
91
+
92
+ if (issues.length > 0) {
93
+ return {
94
+ valid: false,
95
+ message: [
96
+ `Route config in "${routeConfigFile}" is invalid.`,
97
+ issues.join('\n\n'),
98
+ ].join('\n\n'),
99
+ };
100
+ }
101
+
102
+ return {
103
+ valid: true,
104
+ routeConfig: routeConfig as RouteConfigEntry[],
105
+ };
106
+ };