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,239 @@
1
+ import { isAbsolute, relative } from 'node:path';
2
+ import type { RsbuildDevServer, Rspack } from '@rsbuild/core';
3
+ import * as Effect from 'effect/Effect';
4
+ import type { ServerBuild } from 'react-router';
5
+ import type { ReactRouterManifestForDev } from './manifest.js';
6
+ import { getCappedPluginConcurrency } from './concurrency.js';
7
+ import { runPluginEffect, tryPluginPromise } from './effect-runtime.js';
8
+ import { resolveServerBuildModuleEffect } from './server-build-resolution.js';
9
+
10
+ export type ReactRouterDevManifest = ReactRouterManifestForDev;
11
+
12
+ export type ReactRouterDevBuildPlan = {
13
+ defaultEntryName: string;
14
+ entryNames: readonly string[];
15
+ };
16
+
17
+ export type ReactRouterDevManifestSet = Readonly<
18
+ Record<string, ReactRouterDevManifest>
19
+ >;
20
+
21
+ export type ReactRouterServerBuilds = Readonly<Record<string, ServerBuild>>;
22
+
23
+ export type PairedDevStats = {
24
+ web: Rspack.Stats;
25
+ node: Rspack.Stats;
26
+ };
27
+
28
+ export type DevRuntimeStats = Rspack.Stats | Rspack.MultiStats | PairedDevStats;
29
+
30
+ export type DependencySnapshot = {
31
+ files: ReadonlySet<string>;
32
+ contexts: ReadonlySet<string>;
33
+ missing: ReadonlySet<string>;
34
+ };
35
+
36
+ export type DevChangedFiles = {
37
+ known: boolean;
38
+ files: ReadonlySet<string>;
39
+ };
40
+
41
+ export type DevGraphChanges = {
42
+ web: DevChangedFiles;
43
+ node: DevChangedFiles;
44
+ };
45
+
46
+ export type DevCompilationIdentity = symbol;
47
+ export type DevCompileAttemptIdentity = symbol;
48
+
49
+ export type DevGraphIdentity = {
50
+ web: DevCompilationIdentity | undefined;
51
+ node: DevCompilationIdentity | undefined;
52
+ nodeWeb: DevCompilationIdentity | undefined;
53
+ attempt: DevCompileAttemptIdentity | undefined;
54
+ };
55
+
56
+ export type WebArtifact = {
57
+ manifestsByEntryName: ReactRouterDevManifestSet;
58
+ dependencies: DependencySnapshot;
59
+ };
60
+
61
+ export const snapshotDevChangedFiles = (
62
+ compiler: Pick<Rspack.Compiler, 'modifiedFiles' | 'removedFiles'> | undefined
63
+ ): DevChangedFiles => {
64
+ if (!compiler) {
65
+ return { known: false, files: new Set() };
66
+ }
67
+ return {
68
+ known:
69
+ compiler.modifiedFiles !== undefined ||
70
+ compiler.removedFiles !== undefined,
71
+ files: new Set([
72
+ ...(compiler.modifiedFiles ?? []),
73
+ ...(compiler.removedFiles ?? []),
74
+ ]),
75
+ };
76
+ };
77
+
78
+ export const snapshotDependencies = (
79
+ compilation: Rspack.Compilation
80
+ ): DependencySnapshot => ({
81
+ files: new Set([
82
+ ...compilation.fileDependencies,
83
+ ...(compilation.buildDependencies ?? []),
84
+ ]),
85
+ contexts: new Set(compilation.contextDependencies),
86
+ missing: new Set(compilation.missingDependencies),
87
+ });
88
+
89
+ const isWithinDirectory = (directory: string, file: string): boolean => {
90
+ const relativePath = relative(directory, file);
91
+ return (
92
+ relativePath === '' ||
93
+ (!relativePath.startsWith('..') && !isAbsolute(relativePath))
94
+ );
95
+ };
96
+
97
+ export const isSafeOneSidedChange = (
98
+ changes: DevChangedFiles,
99
+ dependencies: DependencySnapshot
100
+ ): boolean => {
101
+ if (!changes.known || changes.files.size === 0) {
102
+ return false;
103
+ }
104
+ for (const file of changes.files) {
105
+ if (dependencies.files.has(file) || dependencies.missing.has(file)) {
106
+ return false;
107
+ }
108
+ for (const directory of dependencies.contexts) {
109
+ if (isWithinDirectory(directory, file)) {
110
+ return false;
111
+ }
112
+ }
113
+ }
114
+ return true;
115
+ };
116
+
117
+ export const isPairedDevStats = (
118
+ stats: DevRuntimeStats
119
+ ): stats is PairedDevStats => 'web' in stats && 'node' in stats;
120
+
121
+ export const getEnvironmentStats = (
122
+ stats: DevRuntimeStats,
123
+ name: 'web' | 'node'
124
+ ): Rspack.Stats | undefined => {
125
+ if (isPairedDevStats(stats)) {
126
+ return stats[name];
127
+ }
128
+ const children = Array.isArray((stats as Rspack.MultiStats).stats)
129
+ ? (stats as Rspack.MultiStats).stats
130
+ : [stats as Rspack.Stats];
131
+ return children.find(child => {
132
+ const compilation = child.compilation;
133
+ return compilation.name === name || compilation.compiler?.name === name;
134
+ });
135
+ };
136
+
137
+ const startServerBuildEvaluationEffect = (
138
+ server: RsbuildDevServer,
139
+ entryName: string
140
+ ): Effect.Effect<ServerBuild, Error, never> =>
141
+ tryPluginPromise(() => server.environments.node.loadBundle(entryName)).pipe(
142
+ Effect.flatMap(buildModule =>
143
+ resolveServerBuildModuleEffect(
144
+ buildModule,
145
+ `Server entry ${JSON.stringify(entryName)}`
146
+ )
147
+ )
148
+ );
149
+
150
+ const evaluateServerBuildsEffect = (
151
+ server: RsbuildDevServer,
152
+ entryNames: readonly string[]
153
+ ): Effect.Effect<ReactRouterServerBuilds, Error, never> =>
154
+ Effect.forEach(
155
+ entryNames.map(entryName =>
156
+ startServerBuildEvaluationEffect(server, entryName).pipe(
157
+ Effect.map(build => [entryName, build] as const)
158
+ )
159
+ ),
160
+ evaluation => evaluation,
161
+ { concurrency: getCappedPluginConcurrency() }
162
+ ).pipe(
163
+ Effect.map(
164
+ evaluated => Object.fromEntries(evaluated) as Record<string, ServerBuild>
165
+ )
166
+ );
167
+
168
+ export const evaluateServerBuilds = (
169
+ server: RsbuildDevServer,
170
+ entryNames: readonly string[]
171
+ ): Promise<ReactRouterServerBuilds> =>
172
+ runPluginEffect(evaluateServerBuildsEffect(server, entryNames));
173
+
174
+ const assertBuildMatchesManifest = (
175
+ entryName: string,
176
+ build: ServerBuild,
177
+ manifest: ReactRouterDevManifest
178
+ ): void => {
179
+ for (const [routeId, manifestRoute] of Object.entries(manifest.routes)) {
180
+ const routeModule = build.routes[routeId]?.module;
181
+ if (!routeModule) {
182
+ throw new Error(
183
+ `[rsbuild-plugin-react-router] Server build ${JSON.stringify(entryName)} route ${JSON.stringify(routeId)} is missing from the evaluated server build.`
184
+ );
185
+ }
186
+ if (
187
+ Boolean(manifestRoute.hasLoader) !==
188
+ (typeof routeModule.loader === 'function')
189
+ ) {
190
+ throw new Error(
191
+ `[rsbuild-plugin-react-router] Server build ${JSON.stringify(entryName)} route ${JSON.stringify(routeId)} loader export does not match its web manifest.`
192
+ );
193
+ }
194
+ if (
195
+ Boolean(manifestRoute.hasAction) !==
196
+ (typeof routeModule.action === 'function')
197
+ ) {
198
+ throw new Error(
199
+ `[rsbuild-plugin-react-router] Server build ${JSON.stringify(entryName)} route ${JSON.stringify(routeId)} action export does not match its web manifest.`
200
+ );
201
+ }
202
+ }
203
+ };
204
+
205
+ const pinBuildToManifest = (
206
+ entryName: string,
207
+ build: ServerBuild,
208
+ manifest: ReactRouterDevManifest
209
+ ): ServerBuild => {
210
+ assertBuildMatchesManifest(entryName, build, manifest);
211
+ return {
212
+ ...build,
213
+ assets: structuredClone(manifest) as ServerBuild['assets'],
214
+ };
215
+ };
216
+
217
+ export const pinServerBuildsToManifests = (
218
+ builds: ReactRouterServerBuilds,
219
+ entryNames: readonly string[],
220
+ manifestsByEntryName: ReactRouterDevManifestSet
221
+ ): ReactRouterServerBuilds => {
222
+ const pinned: Record<string, ServerBuild> = {};
223
+ for (const entryName of entryNames) {
224
+ const build = builds[entryName];
225
+ if (!build) {
226
+ throw new Error(
227
+ `[rsbuild-plugin-react-router] Expected server build ${JSON.stringify(entryName)} was not evaluated.`
228
+ );
229
+ }
230
+ const manifest = manifestsByEntryName[entryName];
231
+ if (!manifest) {
232
+ throw new Error(
233
+ `[rsbuild-plugin-react-router] Server build ${JSON.stringify(entryName)} has no matching web manifest.`
234
+ );
235
+ }
236
+ pinned[entryName] = pinBuildToManifest(entryName, build, manifest);
237
+ }
238
+ return pinned;
239
+ };
@@ -0,0 +1,171 @@
1
+ import type { Rspack } from '@rsbuild/core';
2
+ import type {
3
+ DevCompileAttemptIdentity,
4
+ DevCompilationIdentity,
5
+ DevRuntimeStats,
6
+ DevGraphChanges,
7
+ DevGraphIdentity,
8
+ } from './dev-runtime-artifacts.js';
9
+
10
+ export type DevCompilerPair = {
11
+ web: Rspack.Compiler;
12
+ node: Rspack.Compiler;
13
+ settledCompilations: WeakSet<Rspack.Compilation>;
14
+ pendingAttempt?: PendingDevCompilation;
15
+ currentAttemptIdentity?: DevCompileAttemptIdentity;
16
+ latestCompletedWebIdentity?: DevCompilationIdentity;
17
+ latestCompletedWebStats?: Rspack.Stats;
18
+ latestCompletedNodeStats?: Rspack.Stats;
19
+ latestWebStart?: CompilationStart;
20
+ latestNodeStart?: CompilationStart;
21
+ };
22
+
23
+ export type PendingDevCompilation = {
24
+ stats: DevRuntimeStats;
25
+ changes: DevGraphChanges;
26
+ identity: DevGraphIdentity;
27
+ webCompilation: Rspack.Compilation;
28
+ nodeCompilation: Rspack.Compilation;
29
+ };
30
+
31
+ export type CompilationStart =
32
+ | { status: 'pending' }
33
+ | { status: 'started'; identity: DevCompilationIdentity };
34
+
35
+ type CompilerPairStartSide = 'latestWebStart' | 'latestNodeStart';
36
+
37
+ export const createDevCompilerPair = ({
38
+ web,
39
+ node,
40
+ }: {
41
+ web: Rspack.Compiler;
42
+ node: Rspack.Compiler;
43
+ }): DevCompilerPair => ({
44
+ web,
45
+ node,
46
+ settledCompilations: new WeakSet(),
47
+ });
48
+
49
+ export const resetDevCompilerPair = (pair: DevCompilerPair): void => {
50
+ pair.pendingAttempt = undefined;
51
+ pair.currentAttemptIdentity = undefined;
52
+ pair.latestCompletedWebIdentity = undefined;
53
+ pair.latestCompletedWebStats = undefined;
54
+ pair.latestCompletedNodeStats = undefined;
55
+ pair.latestWebStart = undefined;
56
+ pair.latestNodeStart = undefined;
57
+ };
58
+
59
+ export const isLatestStartedCompilation = (
60
+ identity: DevCompilationIdentity | undefined,
61
+ start: CompilationStart | undefined
62
+ ): boolean =>
63
+ !identity || (start?.status === 'started' && start.identity === identity);
64
+
65
+ export const hasPendingCompilation = (pair: DevCompilerPair): boolean =>
66
+ pair.latestWebStart?.status === 'pending' ||
67
+ pair.latestNodeStart?.status === 'pending';
68
+
69
+ export const beginDevCompilerAttempt = (pair: DevCompilerPair): void => {
70
+ pair.pendingAttempt = undefined;
71
+ pair.currentAttemptIdentity = Symbol();
72
+ };
73
+
74
+ export const markDevCompilerPending = (
75
+ pair: DevCompilerPair,
76
+ side: CompilerPairStartSide
77
+ ): boolean => {
78
+ const attemptAlreadyPending = hasPendingCompilation(pair);
79
+ pair[side] = { status: 'pending' };
80
+ pair.pendingAttempt = undefined;
81
+ if (!attemptAlreadyPending) {
82
+ pair.currentAttemptIdentity = Symbol();
83
+ }
84
+ return !attemptAlreadyPending;
85
+ };
86
+
87
+ export const clearDevCompilerStart = (
88
+ pair: DevCompilerPair,
89
+ side: CompilerPairStartSide
90
+ ): void => {
91
+ pair[side] = undefined;
92
+ pair.pendingAttempt = undefined;
93
+ };
94
+
95
+ export type CompilationIdentityTracker = {
96
+ getCompilationIdentity(
97
+ compilation: Rspack.Compilation
98
+ ): DevCompilationIdentity;
99
+ getWebIdentityForNodeCompilation(
100
+ compilation: Rspack.Compilation
101
+ ): DevCompilationIdentity | undefined;
102
+ getAttemptIdentityForCompilation(
103
+ compilation: Rspack.Compilation
104
+ ): DevCompileAttemptIdentity | undefined;
105
+ setAttemptIdentityForCompilation(
106
+ compilation: Rspack.Compilation,
107
+ identity: DevCompileAttemptIdentity
108
+ ): void;
109
+ setWebIdentityForNodeCompilation(
110
+ compilation: Rspack.Compilation,
111
+ identity: DevCompilationIdentity
112
+ ): void;
113
+ };
114
+
115
+ export const createCompilationIdentityTracker =
116
+ (): CompilationIdentityTracker => {
117
+ const identityByCompilation = new WeakMap<
118
+ Rspack.Compilation,
119
+ DevCompilationIdentity
120
+ >();
121
+ const webIdentityByNodeCompilation = new WeakMap<
122
+ Rspack.Compilation,
123
+ DevCompilationIdentity
124
+ >();
125
+ const attemptIdentityByCompilation = new WeakMap<
126
+ Rspack.Compilation,
127
+ DevCompileAttemptIdentity
128
+ >();
129
+
130
+ return {
131
+ getCompilationIdentity(
132
+ compilation: Rspack.Compilation
133
+ ): DevCompilationIdentity {
134
+ const existing = identityByCompilation.get(compilation);
135
+ if (existing) {
136
+ return existing;
137
+ }
138
+ const identity = Symbol();
139
+ // Keep compact lineage tokens in committed state without retaining entire
140
+ // Rspack compilation graphs across failed rebuilds.
141
+ identityByCompilation.set(compilation, identity);
142
+ return identity;
143
+ },
144
+
145
+ getWebIdentityForNodeCompilation(
146
+ compilation: Rspack.Compilation
147
+ ): DevCompilationIdentity | undefined {
148
+ return webIdentityByNodeCompilation.get(compilation);
149
+ },
150
+
151
+ getAttemptIdentityForCompilation(
152
+ compilation: Rspack.Compilation
153
+ ): DevCompileAttemptIdentity | undefined {
154
+ return attemptIdentityByCompilation.get(compilation);
155
+ },
156
+
157
+ setAttemptIdentityForCompilation(
158
+ compilation: Rspack.Compilation,
159
+ identity: DevCompileAttemptIdentity
160
+ ): void {
161
+ attemptIdentityByCompilation.set(compilation, identity);
162
+ },
163
+
164
+ setWebIdentityForNodeCompilation(
165
+ compilation: Rspack.Compilation,
166
+ identity: DevCompilationIdentity
167
+ ): void {
168
+ webIdentityByNodeCompilation.set(compilation, identity);
169
+ },
170
+ };
171
+ };