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,246 @@
1
+ import type { Route, PluginOptions } from './types.js';
2
+ import type { RsbuildPluginAPI, Rspack } from '@rsbuild/core';
3
+ import {
4
+ createReactRouterManifestStats,
5
+ generateReactRouterManifestForDev,
6
+ getReactRouterManifestChunkNames,
7
+ getReactRouterManifestForDev,
8
+ getReactRouterManifestPath,
9
+ } from './manifest.js';
10
+ import { combineURLs } from './plugin-utils.js';
11
+ import jsesc from 'jsesc';
12
+
13
+ type StatsAssetWithIntegrity = {
14
+ name?: string;
15
+ integrity?: unknown;
16
+ };
17
+
18
+ type StatsWithIntegrity = {
19
+ assets?: StatsAssetWithIntegrity[];
20
+ };
21
+
22
+ type CompilationAssetWithIntegrity = {
23
+ name: string;
24
+ info?: {
25
+ integrity?: unknown;
26
+ };
27
+ };
28
+
29
+ type CompilationWithIntegrityAssets =
30
+ | {
31
+ getAssets?: () => readonly CompilationAssetWithIntegrity[];
32
+ }
33
+ | Pick<Rspack.Compilation, 'getAssets'>;
34
+
35
+ type ModifyBrowserManifestOptions = {
36
+ future?: { unstable_subResourceIntegrity?: boolean };
37
+ subResourceIntegrity?: boolean;
38
+ manifestChunkNames?: ReadonlySet<string>;
39
+ onManifest?: (
40
+ manifest: Awaited<ReturnType<typeof getReactRouterManifestForDev>>,
41
+ sri: Record<string, string> | true | undefined,
42
+ moduleExportsByRouteId: Awaited<
43
+ ReturnType<typeof generateReactRouterManifestForDev>
44
+ >['moduleExportsByRouteId'],
45
+ context: {
46
+ compilation: Rspack.Compilation;
47
+ manifestStats: ReturnType<typeof createReactRouterManifestStats>;
48
+ }
49
+ ) => void;
50
+ };
51
+
52
+ type ProcessAssetsApi = Pick<RsbuildPluginAPI, 'processAssets'>;
53
+ type AssetPrefixInput = string | (() => string);
54
+ type ReactRouterManifest = Awaited<
55
+ ReturnType<typeof getReactRouterManifestForDev>
56
+ >;
57
+ type RouteManifestModuleExports = Awaited<
58
+ ReturnType<typeof generateReactRouterManifestForDev>
59
+ >['moduleExportsByRouteId'];
60
+ type GeneratedManifest = {
61
+ manifest: ReactRouterManifest;
62
+ moduleExportsByRouteId: RouteManifestModuleExports;
63
+ manifestStats: ReturnType<typeof createReactRouterManifestStats>;
64
+ assetPrefix: string;
65
+ };
66
+
67
+ const BROWSER_MANIFEST_ASSET =
68
+ 'static/js/virtual/react-router/browser-manifest.js';
69
+ const ABSOLUTE_URL_RE = /^[a-zA-Z][a-zA-Z\d+\-.]*:/;
70
+
71
+ const toManifestAssetUrl = (assetPrefix: string, assetName: string) => {
72
+ if (
73
+ ABSOLUTE_URL_RE.test(assetName) ||
74
+ assetName.startsWith('//') ||
75
+ assetName.startsWith('/')
76
+ ) {
77
+ return assetName;
78
+ }
79
+ return combineURLs(assetPrefix, assetName);
80
+ };
81
+
82
+ const addIntegrity = (
83
+ sri: Record<string, string>,
84
+ assetPrefix: string,
85
+ assetName: unknown,
86
+ integrity: unknown
87
+ ) => {
88
+ if (typeof assetName !== 'string' || typeof integrity !== 'string') {
89
+ return;
90
+ }
91
+ sri[toManifestAssetUrl(assetPrefix, assetName)] = integrity;
92
+ };
93
+
94
+ export const collectSubresourceIntegrity = (
95
+ stats: StatsWithIntegrity | undefined,
96
+ compilation: CompilationWithIntegrityAssets | undefined,
97
+ assetPrefix = '/'
98
+ ): Record<string, string> | undefined => {
99
+ const sri: Record<string, string> = {};
100
+
101
+ for (const asset of stats?.assets ?? []) {
102
+ addIntegrity(sri, assetPrefix, asset.name, asset.integrity);
103
+ }
104
+
105
+ if (typeof compilation?.getAssets === 'function') {
106
+ const assets =
107
+ compilation.getAssets() as readonly CompilationAssetWithIntegrity[];
108
+ for (const asset of assets) {
109
+ addIntegrity(sri, assetPrefix, asset.name, asset.info?.integrity);
110
+ }
111
+ }
112
+
113
+ return Object.keys(sri).length > 0 ? sri : undefined;
114
+ };
115
+
116
+ export function registerModifyBrowserManifestAssets(
117
+ api: ProcessAssetsApi,
118
+ routes: Record<string, Route>,
119
+ pluginOptions: PluginOptions,
120
+ appDirectory: string,
121
+ assetPrefix: AssetPrefixInput = '/',
122
+ routeChunkOptions?: Parameters<typeof getReactRouterManifestForDev>[5],
123
+ options?: ModifyBrowserManifestOptions
124
+ ): void {
125
+ const getAssetPrefix =
126
+ typeof assetPrefix === 'function' ? assetPrefix : () => assetPrefix;
127
+ const manifestChunkNames =
128
+ options?.manifestChunkNames ??
129
+ getReactRouterManifestChunkNames(
130
+ routes,
131
+ routeChunkOptions?.splitRouteModules
132
+ );
133
+ const finalizeSri = Boolean(
134
+ routeChunkOptions?.isBuild &&
135
+ (options?.subResourceIntegrity ??
136
+ options?.future?.unstable_subResourceIntegrity)
137
+ );
138
+ const generatedManifests = finalizeSri
139
+ ? new WeakMap<Rspack.Compilation, GeneratedManifest>()
140
+ : undefined;
141
+
142
+ api.processAssets(
143
+ { stage: 'additions', environments: ['web'] },
144
+ async ({ assets, sources, compilation }) => {
145
+ const currentAssetPrefix = getAssetPrefix();
146
+ const stats = createReactRouterManifestStats(
147
+ compilation,
148
+ manifestChunkNames
149
+ );
150
+ const { manifest, moduleExportsByRouteId } =
151
+ await generateReactRouterManifestForDev(
152
+ routes,
153
+ pluginOptions,
154
+ stats,
155
+ appDirectory,
156
+ currentAssetPrefix,
157
+ routeChunkOptions
158
+ );
159
+ const manifestForBrowser = finalizeSri
160
+ ? { ...manifest, sri: true as const }
161
+ : manifest;
162
+
163
+ const browserManifestAsset = assets[BROWSER_MANIFEST_ASSET];
164
+ if (browserManifestAsset) {
165
+ const originalSource = browserManifestAsset.source().toString();
166
+ const serializedManifest = jsesc(manifestForBrowser, { es6: true });
167
+ const newSource = originalSource.replace(
168
+ /["'`]PLACEHOLDER["'`]/,
169
+ () => serializedManifest
170
+ );
171
+ compilation.updateAsset(
172
+ BROWSER_MANIFEST_ASSET,
173
+ new sources.RawSource(newSource)
174
+ );
175
+ }
176
+
177
+ if (routeChunkOptions?.isBuild) {
178
+ const entryAssets = stats?.assetsByChunkName?.['entry.client'];
179
+ const entryJsAssets =
180
+ entryAssets?.filter(asset => asset.endsWith('.js')) || [];
181
+ const manifestPath = getReactRouterManifestPath({
182
+ version: manifest.version,
183
+ isBuild: true,
184
+ entryModulePath: entryJsAssets[0],
185
+ });
186
+ const manifestSource = `window.__reactRouterManifest=${jsesc(
187
+ manifestForBrowser,
188
+ { es6: true }
189
+ )};`;
190
+ const source = new sources.RawSource(manifestSource);
191
+ if (compilation.getAsset(manifestPath)) {
192
+ compilation.updateAsset(manifestPath, source);
193
+ } else {
194
+ compilation.emitAsset(manifestPath, source);
195
+ }
196
+ }
197
+
198
+ if (generatedManifests) {
199
+ generatedManifests.set(compilation, {
200
+ manifest,
201
+ moduleExportsByRouteId,
202
+ manifestStats: stats,
203
+ assetPrefix: currentAssetPrefix,
204
+ });
205
+ return;
206
+ }
207
+
208
+ options?.onManifest?.(manifest, undefined, moduleExportsByRouteId, {
209
+ compilation,
210
+ manifestStats: stats,
211
+ });
212
+ }
213
+ );
214
+
215
+ if (generatedManifests) {
216
+ api.processAssets(
217
+ { stage: 'report', environments: ['web'] },
218
+ ({ compilation }) => {
219
+ const generatedManifest = generatedManifests.get(compilation);
220
+ if (!generatedManifest) {
221
+ return;
222
+ }
223
+
224
+ generatedManifests.delete(compilation);
225
+ const sri =
226
+ collectSubresourceIntegrity(
227
+ undefined,
228
+ compilation,
229
+ generatedManifest.assetPrefix
230
+ ) ?? true;
231
+ options?.onManifest?.(
232
+ {
233
+ ...generatedManifest.manifest,
234
+ sri,
235
+ },
236
+ sri,
237
+ generatedManifest.moduleExportsByRouteId,
238
+ {
239
+ compilation,
240
+ manifestStats: generatedManifest.manifestStats,
241
+ }
242
+ );
243
+ }
244
+ );
245
+ }
246
+ }
@@ -0,0 +1,35 @@
1
+ import type {
2
+ RouteTransformResult,
3
+ RouteTransformTask,
4
+ } from './route-transform-tasks.js';
5
+
6
+ type WithoutRequiredSource<Task> = Task extends RouteTransformTask
7
+ ? Omit<Task, 'code'> & { code?: string }
8
+ : never;
9
+
10
+ export type CachedRouteTransformTask =
11
+ WithoutRequiredSource<RouteTransformTask>;
12
+
13
+ export type WorkerRequest = {
14
+ id: number;
15
+ task: RouteTransformTask | CachedRouteTransformTask;
16
+ sourceCacheKey?: string;
17
+ };
18
+
19
+ export type WorkerErrorPayload = {
20
+ name?: string;
21
+ message: string;
22
+ stack?: string;
23
+ };
24
+
25
+ export type WorkerResponse =
26
+ | {
27
+ id: number;
28
+ ok: true;
29
+ result: RouteTransformResult;
30
+ }
31
+ | {
32
+ id: number;
33
+ ok: false;
34
+ error: WorkerErrorPayload;
35
+ };
@@ -0,0 +1,82 @@
1
+ import { parentPort } from 'node:worker_threads';
2
+ import { setBoundedCacheEntry } from './bounded-cache.js';
3
+ import {
4
+ executeRouteTransformTask,
5
+ type RouteTransformTask,
6
+ } from './route-transform-tasks.js';
7
+ import type {
8
+ WorkerErrorPayload,
9
+ WorkerRequest,
10
+ WorkerResponse,
11
+ } from './parallel-route-transform-protocol.js';
12
+
13
+ const serializeError = (error: unknown): WorkerErrorPayload => {
14
+ if (error instanceof Error) {
15
+ return {
16
+ name: error.name,
17
+ message: error.message,
18
+ stack: error.stack,
19
+ };
20
+ }
21
+ return {
22
+ message: String(error),
23
+ };
24
+ };
25
+
26
+ if (!parentPort) {
27
+ throw new Error('parallel route transform worker requires parentPort');
28
+ }
29
+
30
+ const MAX_SOURCE_CACHE_ENTRIES = 2048;
31
+ const sourceCache = new Map<string, string>();
32
+
33
+ const hydrateTaskSource = ({
34
+ task,
35
+ sourceCacheKey,
36
+ }: Pick<WorkerRequest, 'task' | 'sourceCacheKey'>): RouteTransformTask => {
37
+ if (!sourceCacheKey) {
38
+ return task as RouteTransformTask;
39
+ }
40
+
41
+ if (typeof task.code === 'string') {
42
+ setBoundedCacheEntry(
43
+ sourceCache,
44
+ sourceCacheKey,
45
+ task.code,
46
+ MAX_SOURCE_CACHE_ENTRIES
47
+ );
48
+ return task as RouteTransformTask;
49
+ }
50
+
51
+ const code = sourceCache.get(sourceCacheKey);
52
+ if (code === undefined) {
53
+ throw new Error(
54
+ `Missing cached route transform source for ${sourceCacheKey}.`
55
+ );
56
+ }
57
+ return {
58
+ ...task,
59
+ code,
60
+ } as RouteTransformTask;
61
+ };
62
+
63
+ parentPort.on(
64
+ 'message',
65
+ async ({ id, task, sourceCacheKey }: WorkerRequest) => {
66
+ try {
67
+ const hydratedTask = hydrateTaskSource({ task, sourceCacheKey });
68
+ const result = await executeRouteTransformTask(hydratedTask);
69
+ parentPort?.postMessage({
70
+ id,
71
+ ok: true,
72
+ result,
73
+ } satisfies WorkerResponse);
74
+ } catch (error) {
75
+ parentPort?.postMessage({
76
+ id,
77
+ ok: false,
78
+ error: serializeError(error),
79
+ } satisfies WorkerResponse);
80
+ }
81
+ }
82
+ );