rsbuild-plugin-react-router 0.2.0 → 0.3.1

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 (105) hide show
  1. package/README.md +213 -201
  2. package/dist/451.js +1103 -0
  3. package/dist/bounded-cache.d.ts +1 -0
  4. package/dist/build-manifest.d.ts +7 -4
  5. package/dist/build-output-transforms.d.ts +30 -0
  6. package/dist/concurrency.d.ts +3 -0
  7. package/dist/config-imports.d.ts +10 -0
  8. package/dist/constants.d.ts +3 -0
  9. package/dist/dev-background-resources.d.ts +38 -0
  10. package/dist/dev-generation.d.ts +25 -0
  11. package/dist/dev-runtime-artifacts.d.ts +47 -0
  12. package/dist/dev-runtime-compilation.d.ts +47 -0
  13. package/dist/dev-runtime-controller.d.ts +14 -0
  14. package/dist/dev-runtime-session.d.ts +34 -0
  15. package/dist/dev-server.d.ts +16 -2
  16. package/dist/effect-runtime.d.ts +18 -0
  17. package/dist/export-utils.d.ts +15 -7
  18. package/dist/index.cjs +13775 -1412
  19. package/dist/index.d.ts +8 -1
  20. package/dist/index.js +9429 -1501
  21. package/dist/lazy-compilation-prewarm.d.ts +25 -0
  22. package/dist/lazy-compilation.d.ts +6 -0
  23. package/dist/manifest.d.ts +48 -10
  24. package/dist/modify-browser-manifest.d.ts +30 -13
  25. package/dist/parallel-route-transform-protocol.d.ts +25 -0
  26. package/dist/parallel-route-transform-worker.d.ts +1 -0
  27. package/dist/parallel-route-transform-worker.js +38 -0
  28. package/dist/parallel-route-transforms.d.ts +29 -0
  29. package/dist/performance.d.ts +26 -0
  30. package/dist/plugin-utils.d.ts +2 -12
  31. package/dist/prerender-build.d.ts +36 -0
  32. package/dist/prerender.d.ts +27 -2
  33. package/dist/react-router-config.d.ts +15 -5
  34. package/dist/route-artifacts.d.ts +33 -0
  35. package/dist/route-ast.d.ts +21 -0
  36. package/dist/route-chunks.d.ts +9 -1
  37. package/dist/route-component-transform.d.ts +5 -0
  38. package/dist/route-export-pruning.d.ts +6 -0
  39. package/dist/route-export-resolution.d.ts +5 -0
  40. package/dist/route-transform-tasks.d.ts +47 -0
  41. package/dist/route-watch.d.ts +27 -0
  42. package/dist/server-build-plan.d.ts +22 -0
  43. package/dist/server-build-resolution.d.ts +3 -0
  44. package/dist/server-utils.d.ts +3 -2
  45. package/dist/ssr-externals.d.ts +1 -0
  46. package/dist/templates/entry.server.cjs +3 -3
  47. package/dist/templates/entry.server.js +3 -3
  48. package/dist/typegen.d.ts +15 -0
  49. package/dist/types.d.ts +41 -14
  50. package/dist/virtual-modules.d.ts +2 -0
  51. package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
  52. package/dist/yuku.d.ts +15 -0
  53. package/package.json +24 -19
  54. package/src/bounded-cache.ts +18 -0
  55. package/src/build-manifest.ts +205 -0
  56. package/src/build-output-transforms.ts +273 -0
  57. package/src/concurrency.ts +15 -0
  58. package/src/config-imports.ts +83 -0
  59. package/src/constants.ts +91 -0
  60. package/src/dev-background-resources.ts +255 -0
  61. package/src/dev-generation.ts +690 -0
  62. package/src/dev-runtime-artifacts.ts +239 -0
  63. package/src/dev-runtime-compilation.ts +171 -0
  64. package/src/dev-runtime-controller.ts +542 -0
  65. package/src/dev-runtime-session.ts +191 -0
  66. package/src/dev-server.ts +88 -0
  67. package/src/effect-runtime.ts +130 -0
  68. package/src/export-utils.ts +278 -0
  69. package/src/index.ts +990 -0
  70. package/src/lazy-compilation-prewarm.ts +279 -0
  71. package/src/lazy-compilation.ts +101 -0
  72. package/src/manifest.ts +591 -0
  73. package/src/modify-browser-manifest.ts +246 -0
  74. package/src/parallel-route-transform-protocol.ts +35 -0
  75. package/src/parallel-route-transform-worker.ts +82 -0
  76. package/src/parallel-route-transforms.ts +458 -0
  77. package/src/performance.ts +254 -0
  78. package/src/plugin-utils.ts +82 -0
  79. package/src/prerender-build.ts +687 -0
  80. package/src/prerender.ts +349 -0
  81. package/src/react-router-config.ts +245 -0
  82. package/src/route-artifacts.ts +155 -0
  83. package/src/route-ast.ts +163 -0
  84. package/src/route-chunks.ts +857 -0
  85. package/src/route-component-transform.ts +314 -0
  86. package/src/route-config.ts +106 -0
  87. package/src/route-export-pruning.ts +668 -0
  88. package/src/route-export-resolution.ts +329 -0
  89. package/src/route-transform-tasks.ts +249 -0
  90. package/src/route-watch.ts +357 -0
  91. package/src/server-build-plan.ts +91 -0
  92. package/src/server-build-resolution.ts +131 -0
  93. package/src/server-utils.ts +111 -0
  94. package/src/ssr-externals.ts +59 -0
  95. package/src/templates/context.ts +12 -0
  96. package/src/templates/entry.client.tsx +12 -0
  97. package/src/templates/entry.server.tsx +76 -0
  98. package/src/typegen.ts +178 -0
  99. package/src/types.ts +92 -0
  100. package/src/validation/validate-plugin-order.ts +76 -0
  101. package/src/virtual-modules.ts +30 -0
  102. package/src/warnings/warn-on-client-source-maps.ts +96 -0
  103. package/src/yuku.ts +67 -0
  104. package/dist/0~rslib-runtime.js +0 -16
  105. package/dist/babel.d.ts +0 -8
@@ -0,0 +1,279 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import type { ReactRouterManifestForDev } from './manifest.js';
3
+ import type { RouteManifestItem } from './types.js';
4
+ import { createDelayedPluginTask, tryPluginPromise } from './effect-runtime.js';
5
+
6
+ const DEFAULT_LAZY_COMPILATION_TRIGGER_PREFIX = '/_rspack/lazy/trigger';
7
+ const DEFAULT_PREWARM_DELAY_MS = 0;
8
+ const DEFAULT_ROUTE_PREWARM_LIMIT = 8;
9
+ const PREWARM_FETCH_CONCURRENCY = 8;
10
+ const PREWARM_TRIGGER_CANDIDATES = 4;
11
+
12
+ type LazyCompilationPrewarmConfig = {
13
+ entry: boolean;
14
+ routeLimit: number;
15
+ delayMs: number;
16
+ };
17
+
18
+ type LazyCompilationPrewarmController = {
19
+ setServerOrigin(origin: string): void;
20
+ setManifest(manifest: ReactRouterManifestForDev | null): void;
21
+ schedule(): void;
22
+ cancelEffect(): Effect.Effect<void, Error, never>;
23
+ };
24
+
25
+ export type RspackLazyCompilationTriggerClient = {
26
+ extractModuleKeys(source: string): string[];
27
+ trigger(
28
+ origin: string,
29
+ keys: readonly string[]
30
+ ): Effect.Effect<void, Error, never>;
31
+ };
32
+
33
+ export const normalizeLazyCompilationPrewarmOptions = (
34
+ options: boolean | undefined
35
+ ): LazyCompilationPrewarmConfig | null => {
36
+ if (!options) {
37
+ return null;
38
+ }
39
+
40
+ return {
41
+ entry: true,
42
+ routeLimit: DEFAULT_ROUTE_PREWARM_LIMIT,
43
+ delayMs: DEFAULT_PREWARM_DELAY_MS,
44
+ };
45
+ };
46
+
47
+ const collectRouteAssets = (
48
+ routes: Record<string, RouteManifestItem>,
49
+ config: LazyCompilationPrewarmConfig
50
+ ): string[] => {
51
+ if (config.routeLimit < 1) {
52
+ return [];
53
+ }
54
+
55
+ const assets: string[] = [];
56
+ for (const routeId in routes) {
57
+ const route = routes[routeId];
58
+ if (route.module) {
59
+ assets.push(route.module);
60
+ }
61
+ if (route.clientActionModule) {
62
+ assets.push(route.clientActionModule);
63
+ }
64
+ if (route.clientLoaderModule) {
65
+ assets.push(route.clientLoaderModule);
66
+ }
67
+ if (route.clientMiddlewareModule) {
68
+ assets.push(route.clientMiddlewareModule);
69
+ }
70
+ if (route.hydrateFallbackModule) {
71
+ assets.push(route.hydrateFallbackModule);
72
+ }
73
+ if (assets.length >= config.routeLimit) {
74
+ break;
75
+ }
76
+ }
77
+
78
+ return assets;
79
+ };
80
+
81
+ export const collectLazyCompilationPrewarmAssets = (
82
+ manifest: ReactRouterManifestForDev,
83
+ config: LazyCompilationPrewarmConfig
84
+ ): string[] => {
85
+ const assets = [
86
+ ...(config.entry ? [manifest.entry.module, ...manifest.entry.imports] : []),
87
+ ...collectRouteAssets(manifest.routes, config),
88
+ ].filter(Boolean);
89
+
90
+ return Array.from(new Set(assets));
91
+ };
92
+
93
+ const toAbsoluteUrl = (origin: string, asset: string): string =>
94
+ new URL(asset, origin).toString();
95
+
96
+ const parseJsonStringLiteral = (value: string): string | null => {
97
+ try {
98
+ const parsed = JSON.parse(value);
99
+ return typeof parsed === 'string' ? parsed : null;
100
+ } catch {
101
+ return null;
102
+ }
103
+ };
104
+
105
+ const extractLazyCompilationModuleKeys = (source: string): string[] => {
106
+ const keys = new Set<string>();
107
+ const pattern = /activate\(\{\s*data:\s*("(?:\\.|[^"\\])*")/g;
108
+ let match: RegExpExecArray | null;
109
+
110
+ while ((match = pattern.exec(source))) {
111
+ const key = parseJsonStringLiteral(match[1]);
112
+ if (key) {
113
+ keys.add(key);
114
+ }
115
+ }
116
+
117
+ return Array.from(keys);
118
+ };
119
+
120
+ export const createRspackLazyCompilationTriggerClient = (
121
+ triggerPrefix: string = DEFAULT_LAZY_COMPILATION_TRIGGER_PREFIX
122
+ ): RspackLazyCompilationTriggerClient => ({
123
+ extractModuleKeys: extractLazyCompilationModuleKeys,
124
+ trigger(origin, keys) {
125
+ return postLazyCompilationKeys(origin, triggerPrefix, keys);
126
+ },
127
+ });
128
+
129
+ const fetchLazyCompilationKeys = (
130
+ origin: string,
131
+ assets: readonly string[],
132
+ triggerClient: RspackLazyCompilationTriggerClient
133
+ ): Effect.Effect<string[], Error, never> =>
134
+ Effect.forEach(
135
+ assets,
136
+ asset =>
137
+ tryPluginPromise(async () => {
138
+ const response = await fetch(toAbsoluteUrl(origin, asset));
139
+ if (!response.ok) {
140
+ return [];
141
+ }
142
+ return triggerClient.extractModuleKeys(await response.text());
143
+ }),
144
+ { concurrency: PREWARM_FETCH_CONCURRENCY }
145
+ ).pipe(Effect.map(results => Array.from(new Set(results.flat()))));
146
+
147
+ const getTriggerCandidates = (
148
+ origin: string,
149
+ triggerPrefix: string
150
+ ): string[] => {
151
+ const candidates = [triggerPrefix];
152
+ for (let index = 0; index < PREWARM_TRIGGER_CANDIDATES; index += 1) {
153
+ candidates.push(`${triggerPrefix}__${index}`);
154
+ }
155
+ return candidates.map(candidate => toAbsoluteUrl(origin, candidate));
156
+ };
157
+
158
+ const postLazyCompilationKeys = (
159
+ origin: string,
160
+ triggerPrefix: string,
161
+ keys: readonly string[]
162
+ ): Effect.Effect<void, Error, never> => {
163
+ if (keys.length === 0) {
164
+ return Effect.void;
165
+ }
166
+
167
+ return Effect.gen(function* () {
168
+ const body = keys.join('\n');
169
+ let lastError: Error | undefined;
170
+
171
+ for (const url of getTriggerCandidates(origin, triggerPrefix)) {
172
+ const accepted = yield* tryPluginPromise(async () => {
173
+ const response = await fetch(url, {
174
+ method: 'POST',
175
+ headers: {
176
+ 'Content-Type': 'text/plain',
177
+ },
178
+ body,
179
+ });
180
+ return response.ok;
181
+ }).pipe(
182
+ Effect.catchAll(error => {
183
+ lastError = error;
184
+ return Effect.succeed(false);
185
+ })
186
+ );
187
+
188
+ if (accepted) {
189
+ return;
190
+ }
191
+ }
192
+
193
+ yield* Effect.fail(
194
+ lastError ??
195
+ new Error(
196
+ '[rsbuild-plugin-react-router] Lazy compilation prewarm trigger was not accepted.'
197
+ )
198
+ );
199
+ });
200
+ };
201
+
202
+ const prewarmLazyCompilation = ({
203
+ manifest,
204
+ serverOrigin,
205
+ config,
206
+ triggerClient = createRspackLazyCompilationTriggerClient(),
207
+ }: {
208
+ manifest: ReactRouterManifestForDev;
209
+ serverOrigin: string;
210
+ config: LazyCompilationPrewarmConfig;
211
+ triggerClient?: RspackLazyCompilationTriggerClient;
212
+ }): Effect.Effect<void, Error, never> =>
213
+ Effect.gen(function* () {
214
+ const assets = collectLazyCompilationPrewarmAssets(manifest, config);
215
+ const keys = yield* fetchLazyCompilationKeys(
216
+ serverOrigin,
217
+ assets,
218
+ triggerClient
219
+ );
220
+ yield* triggerClient.trigger(serverOrigin, keys);
221
+ });
222
+
223
+ export const createLazyCompilationPrewarmController = ({
224
+ config,
225
+ onError,
226
+ }: {
227
+ config: LazyCompilationPrewarmConfig;
228
+ onError: (error: Error) => void;
229
+ }): LazyCompilationPrewarmController => {
230
+ let serverOrigin: string | undefined;
231
+ let manifest: ReactRouterManifestForDev | null = null;
232
+ let lastPrewarmAssetsKey: string | undefined;
233
+ const task = createDelayedPluginTask({
234
+ delayMs: config.delayMs,
235
+ run: () =>
236
+ Effect.gen(function* () {
237
+ if (!serverOrigin || !manifest) {
238
+ return;
239
+ }
240
+ yield* prewarmLazyCompilation({
241
+ manifest,
242
+ serverOrigin,
243
+ config,
244
+ });
245
+ }),
246
+ onError,
247
+ });
248
+
249
+ return {
250
+ setServerOrigin(origin) {
251
+ serverOrigin = origin;
252
+ },
253
+ setManifest(nextManifest) {
254
+ manifest = nextManifest;
255
+ if (!nextManifest) {
256
+ lastPrewarmAssetsKey = undefined;
257
+ return;
258
+ }
259
+ const assetsKey = collectLazyCompilationPrewarmAssets(
260
+ nextManifest,
261
+ config
262
+ ).join('\n');
263
+ if (assetsKey === lastPrewarmAssetsKey) {
264
+ return;
265
+ }
266
+ lastPrewarmAssetsKey = assetsKey;
267
+ task.reschedule();
268
+ },
269
+ schedule() {
270
+ task.schedule();
271
+ },
272
+ cancelEffect() {
273
+ manifest = null;
274
+ serverOrigin = undefined;
275
+ lastPrewarmAssetsKey = undefined;
276
+ return task.cancelEffect();
277
+ },
278
+ };
279
+ };
@@ -0,0 +1,101 @@
1
+ import { BUILD_CLIENT_ROUTE_QUERY_STRING } from './constants.js';
2
+ import type { PluginOptions } from './types.js';
3
+
4
+ type LazyCompilationOptions = Exclude<
5
+ NonNullable<PluginOptions['lazyCompilation']>,
6
+ boolean
7
+ >;
8
+
9
+ type LazyCompilationModule = {
10
+ request?: string;
11
+ userRequest?: string;
12
+ rawRequest?: string;
13
+ resource?: string;
14
+ identifier?: () => string;
15
+ nameForCondition?: () => string | null;
16
+ };
17
+
18
+ const normalizeSlashes = (value: string): string => value.replace(/\\/g, '/');
19
+
20
+ const getLazyCompilationModuleValues = (
21
+ module: LazyCompilationModule
22
+ ): string[] =>
23
+ [
24
+ module.request,
25
+ module.userRequest,
26
+ module.rawRequest,
27
+ module.resource,
28
+ module.identifier?.(),
29
+ module.nameForCondition?.(),
30
+ ].filter((value): value is string => Boolean(value));
31
+
32
+ const matchesLazyCompilationTest = (
33
+ test: LazyCompilationOptions['test'] | undefined,
34
+ module: LazyCompilationModule
35
+ ): boolean => {
36
+ if (!test) {
37
+ return true;
38
+ }
39
+ if (typeof test === 'function') {
40
+ return test(module as Parameters<typeof test>[0]);
41
+ }
42
+ const conditionName = module.nameForCondition?.();
43
+ if (!conditionName) {
44
+ return false;
45
+ }
46
+ test.lastIndex = 0;
47
+ return test.test(conditionName);
48
+ };
49
+
50
+ const createReactRouterHydrationModuleTest = (entryClientPath: string) => {
51
+ const eagerPatterns = [
52
+ 'virtual/react-router/browser-manifest',
53
+ ...(entryClientPath
54
+ ? [
55
+ normalizeSlashes(entryClientPath),
56
+ BUILD_CLIENT_ROUTE_QUERY_STRING,
57
+ '?react-router-route',
58
+ ]
59
+ : []),
60
+ ];
61
+
62
+ return (module: LazyCompilationModule): boolean =>
63
+ getLazyCompilationModuleValues(module).some(value => {
64
+ const normalizedValue = normalizeSlashes(value);
65
+ return eagerPatterns.some(pattern => normalizedValue.includes(pattern));
66
+ });
67
+ };
68
+
69
+ export const guardReactRouterLazyCompilation = ({
70
+ lazyCompilation,
71
+ entryClientPath,
72
+ prewarmReactRouterModules = false,
73
+ }: {
74
+ lazyCompilation: PluginOptions['lazyCompilation'] | undefined;
75
+ entryClientPath: string;
76
+ prewarmReactRouterModules?: boolean;
77
+ }): PluginOptions['lazyCompilation'] | undefined => {
78
+ if (lazyCompilation === undefined || lazyCompilation === false) {
79
+ return lazyCompilation;
80
+ }
81
+
82
+ const options: LazyCompilationOptions =
83
+ lazyCompilation === true
84
+ ? { entries: true, imports: true }
85
+ : lazyCompilation;
86
+ const userTest = options.test;
87
+ const isReactRouterHydrationModule = prewarmReactRouterModules
88
+ ? createReactRouterHydrationModuleTest('')
89
+ : createReactRouterHydrationModuleTest(entryClientPath);
90
+
91
+ return {
92
+ ...options,
93
+ test(module) {
94
+ const lazyModule = module as LazyCompilationModule;
95
+ if (isReactRouterHydrationModule(lazyModule)) {
96
+ return false;
97
+ }
98
+ return matchesLazyCompilationTest(userTest, lazyModule);
99
+ },
100
+ };
101
+ };