rsbuild-plugin-react-router 0.4.0 → 0.5.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 +17 -35
- package/dist/{451.js → 511.js} +92 -1
- package/dist/build-output-transforms.d.ts +4 -3
- package/dist/dev-background-resources.d.ts +1 -3
- package/dist/federation.d.ts +2 -0
- package/dist/index.cjs +153 -335
- package/dist/index.js +129 -407
- package/dist/performance.d.ts +4 -1
- package/dist/route-module-transform-loader.d.ts +14 -0
- package/dist/route-module-transform-loader.js +44 -0
- package/dist/route-module-transform-rules.d.ts +14 -0
- package/dist/route-transform-tasks.d.ts +1 -0
- package/dist/types.d.ts +4 -5
- package/package.json +13 -14
- package/src/build-output-transforms.ts +28 -24
- package/src/dev-background-resources.ts +1 -16
- package/src/federation.ts +38 -0
- package/src/index.ts +38 -57
- package/src/performance.ts +11 -2
- package/src/route-module-transform-loader.ts +149 -0
- package/src/route-module-transform-rules.ts +115 -0
- package/src/route-transform-tasks.ts +5 -4
- package/src/types.ts +4 -5
- package/dist/parallel-route-transform-protocol.d.ts +0 -25
- package/dist/parallel-route-transform-worker.d.ts +0 -1
- package/dist/parallel-route-transform-worker.js +0 -38
- package/dist/parallel-route-transforms.d.ts +0 -29
- package/src/parallel-route-transform-protocol.ts +0 -35
- package/src/parallel-route-transform-worker.ts +0 -82
- package/src/parallel-route-transforms.ts +0 -458
package/README.md
CHANGED
|
@@ -77,16 +77,16 @@ pluginReactRouter({
|
|
|
77
77
|
});
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
| Option | Default | Description
|
|
81
|
-
| -------------------------------- | ----------- |
|
|
82
|
-
| `customServer` | `false` | Disables the built-in development SSR middleware. Enable this when an app owns the server with `createDevServer()` or an adapter.
|
|
83
|
-
| `serverOutput` | Derived | Emitted Rsbuild server format: `'module'` or `'commonjs'`. When omitted, React Router's `serverModuleFormat` selects the format (`'esm'` -> `'module'`, `'cjs'` -> `'commonjs'`); setting `serverOutput` overrides it.
|
|
84
|
-
| `lazyCompilation` | `true` | Optional Rsbuild dev lazy-compilation config. When enabled here or through `dev.lazyCompilation`, React Router hydration-critical modules stay eager so the browser manifest and route modules are not replaced by lazy proxies.
|
|
85
|
-
| `unstableLazyCompilationPrewarm` | `false` | Experimental prewarm for emitted Rspack lazy-compilation proxy modules after dev compiles. Enable with `true` when route JS proxy startup should happen shortly after compiler readiness.
|
|
86
|
-
| `logPerformance` | `false` | Logs structured React Router plugin timing information
|
|
87
|
-
| `parallelRouteTransform` | `undefined` | Controls worker-thread route transforms. `undefined`
|
|
88
|
-
| `onRouteTopologyChange` | `undefined` | Notification for programmatic/custom dev servers. Recreate the Rsbuild server when route files are added, removed, or moved. The callback is not awaited.
|
|
89
|
-
| `federation` | `false` | Enables the plugin's experimental Module Federation integration.
|
|
80
|
+
| Option | Default | Description |
|
|
81
|
+
| -------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| `customServer` | `false` | Disables the built-in development SSR middleware. Enable this when an app owns the server with `createDevServer()` or an adapter. |
|
|
83
|
+
| `serverOutput` | Derived | Emitted Rsbuild server format: `'module'` or `'commonjs'`. When omitted, React Router's `serverModuleFormat` selects the format (`'esm'` -> `'module'`, `'cjs'` -> `'commonjs'`); setting `serverOutput` overrides it. |
|
|
84
|
+
| `lazyCompilation` | `true` | Optional Rsbuild dev lazy-compilation config. When enabled here or through `dev.lazyCompilation`, React Router hydration-critical modules stay eager so the browser manifest and route modules are not replaced by lazy proxies. |
|
|
85
|
+
| `unstableLazyCompilationPrewarm` | `false` | Experimental prewarm for emitted Rspack lazy-compilation proxy modules after dev compiles. Enable with `true` when route JS proxy startup should happen shortly after compiler readiness. |
|
|
86
|
+
| `logPerformance` | `false` | Logs structured React Router plugin timing information. |
|
|
87
|
+
| `parallelRouteTransform` | `undefined` | Controls worker-thread route transforms. `undefined` and `false` keep transforms inline, `true` uses Rspack's default worker count, and a positive integer sets the maximum worker count. |
|
|
88
|
+
| `onRouteTopologyChange` | `undefined` | Notification for programmatic/custom dev servers. Recreate the Rsbuild server when route files are added, removed, or moved. The callback is not awaited. |
|
|
89
|
+
| `federation` | `false` | Enables the plugin's experimental Module Federation integration. |
|
|
90
90
|
|
|
91
91
|
When `federation` is enabled, configure the Module Federation plugin with
|
|
92
92
|
`experiments.asyncStartup: true`. The dev server resolves async server build
|
|
@@ -655,35 +655,17 @@ The plugin automatically:
|
|
|
655
655
|
|
|
656
656
|
### Benchmarking
|
|
657
657
|
|
|
658
|
-
|
|
659
|
-
regression checks. `pnpm bench:synthetic-app` runs the embedded complex Rsbuild
|
|
660
|
-
app under `benchmarks/synthetic-web-bundler-benchmark`, which adds heavier
|
|
661
|
-
loader and transform contention for benchmark coverage closer to a large
|
|
662
|
-
real-world application.
|
|
658
|
+
Run the focused local suite for plugin regression checks:
|
|
663
659
|
|
|
664
660
|
```bash
|
|
665
|
-
pnpm bench
|
|
666
|
-
pnpm bench:
|
|
661
|
+
pnpm bench
|
|
662
|
+
pnpm bench:smoke
|
|
663
|
+
pnpm bench:codspeed
|
|
667
664
|
```
|
|
668
665
|
|
|
669
|
-
|
|
670
|
-
and
|
|
671
|
-
|
|
672
|
-
counterbalances which side runs first, and excludes one warmup iteration. Small
|
|
673
|
-
fixtures use five measured iterations; expensive large fixtures use three.
|
|
674
|
-
|
|
675
|
-
Every raw median delta remains visible. The comment also reports each side's
|
|
676
|
-
relative median absolute deviation (rMAD), a conservative noise band, and a
|
|
677
|
-
signal label:
|
|
678
|
-
|
|
679
|
-
- `regression` or `improvement` means the median delta exceeds the observed
|
|
680
|
-
run-to-run noise band.
|
|
681
|
-
- `inconclusive` means the raw delta is not clearly separated from that noise.
|
|
682
|
-
- `insufficient data` means either side has fewer than three finite samples.
|
|
683
|
-
|
|
684
|
-
The labels are triage aids, not pass/fail gates. Use the uploaded diagnostics
|
|
685
|
-
and raw per-run samples to investigate important changes, and rerun an
|
|
686
|
-
inconclusive comparison before treating it as a performance result.
|
|
666
|
+
See the [benchmark guide](./benchmarks/README.md) for JSON output, pull-request
|
|
667
|
+
comparisons and comments, `BENCHMARK_PLUGIN_ROOT`, and optional CodSpeed
|
|
668
|
+
publication.
|
|
687
669
|
|
|
688
670
|
## React Router Framework Mode
|
|
689
671
|
|
package/dist/{451.js → 511.js}
RENAMED
|
@@ -1217,5 +1217,96 @@ if (import.meta.webpackHot) {
|
|
|
1217
1217
|
case 'routeModule':
|
|
1218
1218
|
return transformRouteModule(task);
|
|
1219
1219
|
}
|
|
1220
|
+
}, roundMs = (value)=>Math.round(10 * value) / 10, createReactRouterPerformanceProfiler = ({ enabled, log })=>{
|
|
1221
|
+
let timingsByEnvironment = new Map(), recordDuration = (environment, operation, resource, startMs, endMs)=>{
|
|
1222
|
+
let timings, timing, duration = endMs - startMs, timing1 = ((timings = timingsByEnvironment.get(environment)) || (timings = new Map(), timingsByEnvironment.set(environment, timings)), (timing = timings.get(operation)) || (timing = {
|
|
1223
|
+
count: 0,
|
|
1224
|
+
totalMs: 0,
|
|
1225
|
+
maxMs: 0,
|
|
1226
|
+
slowest: [],
|
|
1227
|
+
intervals: []
|
|
1228
|
+
}, timings.set(operation, timing)), timing);
|
|
1229
|
+
timing1.count += 1, timing1.totalMs += duration, timing1.maxMs = Math.max(timing1.maxMs, duration), timing1.intervals.push({
|
|
1230
|
+
startMs,
|
|
1231
|
+
endMs
|
|
1232
|
+
}), ((slowest, entry)=>{
|
|
1233
|
+
if (5 === slowest.length && entry.durationMs <= slowest[slowest.length - 1].durationMs) return;
|
|
1234
|
+
let insertIndex = slowest.length;
|
|
1235
|
+
for(; insertIndex > 0 && entry.durationMs > slowest[insertIndex - 1].durationMs;)insertIndex -= 1;
|
|
1236
|
+
slowest.splice(insertIndex, 0, entry), slowest.length > 5 && slowest.pop();
|
|
1237
|
+
})(timing1.slowest, {
|
|
1238
|
+
durationMs: duration,
|
|
1239
|
+
resource
|
|
1240
|
+
});
|
|
1241
|
+
};
|
|
1242
|
+
return {
|
|
1243
|
+
record (environment, operation, resource, callback) {
|
|
1244
|
+
if (!enabled) try {
|
|
1245
|
+
return Promise.resolve(callback());
|
|
1246
|
+
} catch (error) {
|
|
1247
|
+
return Promise.reject(error);
|
|
1248
|
+
}
|
|
1249
|
+
let resolvedEnvironment = environment ?? 'unknown', start = performance.now();
|
|
1250
|
+
try {
|
|
1251
|
+
return callback().then((result)=>{
|
|
1252
|
+
let end = performance.now();
|
|
1253
|
+
return recordDuration(resolvedEnvironment, operation, resource, start, end), result;
|
|
1254
|
+
}, (error)=>{
|
|
1255
|
+
let end = performance.now();
|
|
1256
|
+
throw recordDuration(resolvedEnvironment, operation, resource, start, end), error;
|
|
1257
|
+
});
|
|
1258
|
+
} catch (error) {
|
|
1259
|
+
return recordDuration(resolvedEnvironment, operation, resource, start, performance.now()), Promise.reject(error);
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
recordSync (environment, operation, resource, callback) {
|
|
1263
|
+
if (!enabled) return callback();
|
|
1264
|
+
let start = performance.now();
|
|
1265
|
+
try {
|
|
1266
|
+
return callback();
|
|
1267
|
+
} finally{
|
|
1268
|
+
recordDuration(environment ?? 'unknown', operation, resource, start, performance.now());
|
|
1269
|
+
}
|
|
1270
|
+
},
|
|
1271
|
+
flush (environment, details = {}) {
|
|
1272
|
+
let report;
|
|
1273
|
+
if (!enabled) return;
|
|
1274
|
+
let resolvedEnvironment = environment ?? 'unknown', timings = timingsByEnvironment.get(resolvedEnvironment);
|
|
1275
|
+
if (!timings || 0 === timings.size) return;
|
|
1276
|
+
let operations = Object.fromEntries([
|
|
1277
|
+
...timings.entries()
|
|
1278
|
+
].map(([operation, timing])=>[
|
|
1279
|
+
operation,
|
|
1280
|
+
{
|
|
1281
|
+
count: timing.count,
|
|
1282
|
+
totalMs: roundMs(timing.totalMs),
|
|
1283
|
+
wallMs: ((intervals)=>{
|
|
1284
|
+
if (0 === intervals.length) return 0;
|
|
1285
|
+
let sortedIntervals = [
|
|
1286
|
+
...intervals
|
|
1287
|
+
].sort((a, b)=>a.startMs - b.startMs || a.endMs - b.endMs), mergedStart = sortedIntervals[0].startMs, mergedEnd = sortedIntervals[0].endMs, wallMs = 0;
|
|
1288
|
+
for (let interval of sortedIntervals.slice(1)){
|
|
1289
|
+
if (interval.startMs <= mergedEnd) {
|
|
1290
|
+
mergedEnd = Math.max(mergedEnd, interval.endMs);
|
|
1291
|
+
continue;
|
|
1292
|
+
}
|
|
1293
|
+
wallMs += mergedEnd - mergedStart, mergedStart = interval.startMs, mergedEnd = interval.endMs;
|
|
1294
|
+
}
|
|
1295
|
+
return roundMs(wallMs += mergedEnd - mergedStart);
|
|
1296
|
+
})(timing.intervals),
|
|
1297
|
+
maxMs: roundMs(timing.maxMs),
|
|
1298
|
+
slowest: timing.slowest.map((entry)=>({
|
|
1299
|
+
durationMs: roundMs(entry.durationMs),
|
|
1300
|
+
resource: entry.resource
|
|
1301
|
+
}))
|
|
1302
|
+
}
|
|
1303
|
+
]));
|
|
1304
|
+
log((report = {
|
|
1305
|
+
environment: resolvedEnvironment,
|
|
1306
|
+
...details,
|
|
1307
|
+
operations
|
|
1308
|
+
}, `[react-router:performance] ${JSON.stringify(report)}`)), timingsByEnvironment.delete(resolvedEnvironment);
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1220
1311
|
};
|
|
1221
|
-
export { BUILD_CLIENT_ROUTE_QUERY_STRING, CLIENT_EXPORTS, HMR_PATCHABLE_ROUTE_FLAGS, JS_EXTENSIONS, PLUGIN_NAME, SERVER_EXPORTS, buildManifestChunkValidity, combineURLs, createBundlerRouteExportResolver, createEmptyRouteChunkByExportName, createRouteId, detectRouteChunksIfEnabled, executeRouteTransformTask, findEntryFile, generateWithProps, getRouteChunkEntryName, getRouteChunkModuleId, getRouteModuleAnalysis, normalizeAssetPrefix,
|
|
1312
|
+
export { BUILD_CLIENT_ROUTE_QUERY_STRING, CLIENT_EXPORTS, HMR_PATCHABLE_ROUTE_FLAGS, JS_EXTENSIONS, PLUGIN_NAME, SERVER_EXPORTS, buildManifestChunkValidity, combineURLs, createBundlerRouteExportResolver, createEmptyRouteChunkByExportName, createReactRouterPerformanceProfiler, createRouteId, detectRouteChunksIfEnabled, executeRouteTransformTask, findEntryFile, generateWithProps, getRouteChunkEntryName, getRouteChunkModuleId, getRouteModuleAnalysis, normalizeAssetPrefix, roundMs, routeChunkExportNames, validateRouteChunks };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { RsbuildPluginAPI } from '@rsbuild/core';
|
|
2
2
|
import { getReactRouterManifestForDev, type ReactRouterManifestStats } from './manifest.js';
|
|
3
|
-
import type { RouteTransformExecutor } from './parallel-route-transforms.js';
|
|
4
3
|
import type { ReactRouterPerformanceProfiler } from './performance.js';
|
|
5
4
|
import type { RouteChunkConfig } from './route-chunks.js';
|
|
5
|
+
import type { RouteTransformRunner } from './route-transform-tasks.js';
|
|
6
6
|
import type { PluginOptions, Route } from './types.js';
|
|
7
7
|
type ReactRouterManifest = Awaited<ReturnType<typeof getReactRouterManifestForDev>>;
|
|
8
8
|
type RegisterBuildOutputTransformsOptions = {
|
|
@@ -17,15 +17,16 @@ type RegisterBuildOutputTransformsOptions = {
|
|
|
17
17
|
appDirectory: string;
|
|
18
18
|
getAssetPrefix: () => string;
|
|
19
19
|
routeChunkOptions: Parameters<typeof getReactRouterManifestForDev>[5];
|
|
20
|
-
|
|
20
|
+
routeTransformRunner: RouteTransformRunner;
|
|
21
21
|
routeByFilePath: Map<string, Route>;
|
|
22
22
|
routeChunkConfig: RouteChunkConfig;
|
|
23
23
|
isBuild: boolean;
|
|
24
24
|
splitRouteModules: boolean;
|
|
25
|
+
useRouteModuleTransformApi: boolean;
|
|
25
26
|
ssr: boolean;
|
|
26
27
|
isSpaMode: boolean;
|
|
27
28
|
rootRoutePath: string;
|
|
28
29
|
isDevHmrEnabled?: () => boolean;
|
|
29
30
|
};
|
|
30
|
-
export declare const registerBuildOutputTransforms: ({ api, resolvedServerOutput, performanceProfiler, getLatestServerManifest, getLatestServerManifestByBundleId, routes, pluginOptions, getClientStats, appDirectory, getAssetPrefix, routeChunkOptions,
|
|
31
|
+
export declare const registerBuildOutputTransforms: ({ api, resolvedServerOutput, performanceProfiler, getLatestServerManifest, getLatestServerManifestByBundleId, routes, pluginOptions, getClientStats, appDirectory, getAssetPrefix, routeChunkOptions, routeTransformRunner, routeByFilePath, routeChunkConfig, isBuild, splitRouteModules, useRouteModuleTransformApi, ssr, isSpaMode, rootRoutePath, isDevHmrEnabled, }: RegisterBuildOutputTransformsOptions) => void;
|
|
31
32
|
export {};
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { RsbuildPluginAPI } from '@rsbuild/core';
|
|
2
2
|
import type { RouteConfigEntry } from '@react-router/dev/routes';
|
|
3
3
|
import { type ReactRouterManifestForDev } from './manifest.js';
|
|
4
|
-
import type { RouteTransformExecutor } from './parallel-route-transforms.js';
|
|
5
4
|
import { type WatchFileConfig } from './route-watch.js';
|
|
6
5
|
import type { PluginOptions } from './types.js';
|
|
7
6
|
type RegisterReactRouterDevBackgroundResourcesOptions = {
|
|
8
7
|
api: RsbuildPluginAPI;
|
|
9
8
|
isBuild: boolean;
|
|
10
9
|
lazyCompilationPrewarm: PluginOptions['unstableLazyCompilationPrewarm'];
|
|
11
|
-
routeTransformExecutor: RouteTransformExecutor;
|
|
12
10
|
routeRestartMarkerPath: string;
|
|
13
11
|
watchDirectory: string;
|
|
14
12
|
getRouteTopology: () => Promise<Set<string>>;
|
|
@@ -34,5 +32,5 @@ export declare const createReactRouterRouteWatchFiles: ({ configWatchPaths, rout
|
|
|
34
32
|
routeRestartMarkerPath: string;
|
|
35
33
|
onRouteTopologyChange: PluginOptions["onRouteTopologyChange"];
|
|
36
34
|
}) => WatchFileConfig[];
|
|
37
|
-
export declare const registerReactRouterDevBackgroundResources: ({ api, isBuild, lazyCompilationPrewarm,
|
|
35
|
+
export declare const registerReactRouterDevBackgroundResources: ({ api, isBuild, lazyCompilationPrewarm, routeRestartMarkerPath, watchDirectory, getRouteTopology, initialRouteTopology, onRouteTopologyChange, }: RegisterReactRouterDevBackgroundResourcesOptions) => ReactRouterDevBackgroundResources;
|
|
38
36
|
export {};
|