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.
@@ -12,12 +12,15 @@ export declare const roundMs: (value: number) => number;
12
12
  export type ReactRouterPerformanceReport = {
13
13
  environment: string;
14
14
  compilerLifecycleMs?: number;
15
+ partial?: boolean;
16
+ workerId?: string;
15
17
  operations: Record<string, OperationTiming>;
16
18
  };
19
+ export declare const formatReactRouterPerformanceReport: (report: ReactRouterPerformanceReport) => string;
17
20
  export type ReactRouterPerformanceProfiler = {
18
21
  record<T>(environment: string | undefined, operation: string, resource: string, callback: () => Promise<T>): Promise<T>;
19
22
  recordSync<T>(environment: string | undefined, operation: string, resource: string, callback: () => T): T;
20
- flush(environment: string | undefined, details?: Pick<ReactRouterPerformanceReport, 'compilerLifecycleMs'>): void;
23
+ flush(environment: string | undefined, details?: Pick<ReactRouterPerformanceReport, 'compilerLifecycleMs' | 'partial' | 'workerId'>): void;
21
24
  };
22
25
  export declare const createReactRouterPerformanceProfiler: ({ enabled, log, }: {
23
26
  enabled: boolean;
@@ -0,0 +1,14 @@
1
+ import type { LoaderDefinition } from '@rspack/core';
2
+ export type RouteModuleTransformLoaderOptions = {
3
+ environmentName: string;
4
+ performanceScopeId: string;
5
+ logPerformance: boolean;
6
+ ssr: boolean;
7
+ isBuild: boolean;
8
+ isSpaMode: boolean;
9
+ rootRoutePath: string | null;
10
+ devHmr: boolean;
11
+ };
12
+ export declare const flushRouteModuleTransformLoaderPerformance: () => void;
13
+ declare const routeModuleTransformLoader: LoaderDefinition<RouteModuleTransformLoaderOptions>;
14
+ export default routeModuleTransformLoader;
@@ -0,0 +1,44 @@
1
+ let performanceFlushTimer;
2
+ import { threadId } from "node:worker_threads";
3
+ import remapping from "@jridgewell/remapping";
4
+ import { createReactRouterPerformanceProfiler, executeRouteTransformTask } from "./511.js";
5
+ let performanceWorkerId = `process-${process.pid}:thread-${threadId}`, performanceProfilersByScope = new Map(), flushRouteModuleTransformLoaderPerformance = ()=>{
6
+ for (let profilers of (performanceFlushTimer && (clearTimeout(performanceFlushTimer), performanceFlushTimer = void 0), performanceProfilersByScope.values()))for (let [environment, profiler] of profilers)profiler.flush('unknown' === environment ? void 0 : environment, {
7
+ partial: !0,
8
+ workerId: performanceWorkerId
9
+ });
10
+ performanceProfilersByScope.clear();
11
+ };
12
+ process.once('beforeExit', flushRouteModuleTransformLoaderPerformance);
13
+ let route_module_transform_loader_routeModuleTransformLoader = async function(source, inputSourceMap) {
14
+ let callback = this.async(), options = this.getOptions(), transform = ()=>executeRouteTransformTask({
15
+ kind: 'routeModule',
16
+ code: String(source),
17
+ resource: this.resource,
18
+ resourcePath: this.resourcePath,
19
+ environmentName: options.environmentName,
20
+ sourceMaps: !!this.sourceMap,
21
+ ssr: options.ssr,
22
+ isBuild: options.isBuild,
23
+ isSpaMode: options.isSpaMode,
24
+ rootRoutePath: options.rootRoutePath,
25
+ devHmr: options.devHmr
26
+ });
27
+ try {
28
+ var scopeId, environment;
29
+ let profilers, environmentKey, profiler, generatedMap, result = options.logPerformance ? await (scopeId = options.performanceScopeId, environment = options.environmentName, !(profilers = performanceProfilersByScope.get(scopeId)) && (profilers = new Map(), performanceProfilersByScope.set(scopeId, profilers)), environmentKey = environment ?? 'unknown', !(profiler = profilers.get(environmentKey)) && (profiler = createReactRouterPerformanceProfiler({
30
+ enabled: !0,
31
+ log: (message)=>console.info(message)
32
+ }), profilers.set(environmentKey, profiler)), profiler).record(options.environmentName, 'route:module', this.resource, transform) : await transform(), outputSourceMap = result.map && inputSourceMap ? (generatedMap = result.map, JSON.parse(remapping([
33
+ generatedMap,
34
+ inputSourceMap
35
+ ], ()=>null).toString())) : result.map;
36
+ callback(null, result.code, outputSourceMap ?? void 0);
37
+ } catch (error) {
38
+ callback(error instanceof Error ? error : Error(String(error)));
39
+ } finally{
40
+ options.logPerformance && (performanceFlushTimer && clearTimeout(performanceFlushTimer), performanceFlushTimer = setTimeout(flushRouteModuleTransformLoaderPerformance, 50));
41
+ }
42
+ };
43
+ export default route_module_transform_loader_routeModuleTransformLoader;
44
+ export { flushRouteModuleTransformLoaderPerformance };
@@ -0,0 +1,14 @@
1
+ import type { Rspack } from '@rsbuild/core';
2
+ import type { PluginOptions, Route } from './types.js';
3
+ export declare const shouldUseRouteModuleTransformLoader: (parallelRouteTransform: PluginOptions["parallelRouteTransform"]) => boolean;
4
+ export declare const registerRouteModuleTransformRules: (rspackConfig: Rspack.Configuration, { environmentName, ssr, isBuild, isSpaMode, rootRoutePath, devHmr, logPerformance, routeByFilePath, parallelRouteTransform, }: {
5
+ environmentName: string;
6
+ ssr: boolean;
7
+ isBuild: boolean;
8
+ isSpaMode: boolean;
9
+ rootRoutePath: string | null;
10
+ devHmr: boolean;
11
+ logPerformance: boolean;
12
+ routeByFilePath: Map<string, Route>;
13
+ parallelRouteTransform: PluginOptions["parallelRouteTransform"];
14
+ }) => void;
@@ -46,5 +46,6 @@ export type RouteTransformTask = RouteClientEntryTransformTask | RouteChunkTrans
46
46
  export type RouteTransformTaskOptions = {
47
47
  routeChunkCache?: RouteChunkCache;
48
48
  };
49
+ export type RouteTransformRunner = (task: RouteTransformTask) => Promise<RouteTransformResult>;
49
50
  export declare const executeRouteTransformTask: (task: RouteTransformTask, options?: RouteTransformTaskOptions) => Promise<RouteTransformResult>;
50
51
  export {};
package/dist/types.d.ts CHANGED
@@ -49,11 +49,10 @@ export type PluginOptions = {
49
49
  */
50
50
  logPerformance?: boolean;
51
51
  /**
52
- * Run route transforms in a worker-thread pool.
53
- * Pass `true` to force the default worker count, a positive integer to set
54
- * the worker count, or `false` to disable.
55
- * @default Automatically enabled for 256+ resolved routes. The automatic
56
- * pool uses available CPU cores minus 2.
52
+ * Run route module transforms with Rspack's parallel loader workers.
53
+ * Pass `true` to use Rspack's default worker count, a positive integer to set
54
+ * the maximum worker count, or `false` to disable.
55
+ * @default false
57
56
  */
58
57
  parallelRouteTransform?: boolean | number;
59
58
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsbuild-plugin-react-router",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "React Router plugin for Rsbuild",
5
5
  "repository": {
6
6
  "type": "git",
@@ -49,6 +49,7 @@
49
49
  "ignoreMissingDts": true
50
50
  },
51
51
  "dependencies": {
52
+ "@jridgewell/remapping": "^2.3.5",
52
53
  "@react-router/node": "^7.13.0",
53
54
  "@remix-run/node-fetch-server": "^0.13.0",
54
55
  "@rspack/plugin-react-refresh": "^2.0.2",
@@ -65,13 +66,15 @@
65
66
  },
66
67
  "devDependencies": {
67
68
  "@changesets/cli": "^2.29.8",
69
+ "@codspeed/vitest-plugin": "^5.7.1",
70
+ "@jridgewell/trace-mapping": "^0.3.31",
68
71
  "@react-router/dev": "^8.0.1",
69
- "@rsbuild/core": "2.1.0",
72
+ "@rsbuild/core": "2.1.5",
70
73
  "@rsbuild/plugin-react": "2.1.0",
71
- "@rslib/core": "^0.22.1",
72
- "@rspack/core": "2.1.0",
73
- "@rstest/core": "^0.8.1",
74
- "@rstest/coverage-istanbul": "^0.2.0",
74
+ "@rslib/core": "^0.23.2",
75
+ "@rspack/core": "2.1.3",
76
+ "@rstest/core": "^0.11.0",
77
+ "@rstest/coverage-istanbul": "^0.11.0",
75
78
  "@swc/helpers": "^0.5.23",
76
79
  "@types/fs-extra": "11.0.4",
77
80
  "@types/jsesc": "^3.0.3",
@@ -89,6 +92,7 @@
89
92
  "react-router": "^7.13.0",
90
93
  "react-router-dom": "^7.13.0",
91
94
  "typescript": "^5.9.3",
95
+ "vitest": "^4.1.10",
92
96
  "@rsbuild/config": "1.0.1"
93
97
  },
94
98
  "peerDependencies": {
@@ -107,14 +111,9 @@
107
111
  },
108
112
  "scripts": {
109
113
  "build": "rslib build",
110
- "bench": "node scripts/bench-builds.mts",
111
- "bench:ci-report": "node scripts/report-benchmark-ci.mts",
112
- "bench:compare": "node scripts/compare-benchmarks.mts",
113
- "bench:smoke": "node scripts/bench-builds.mts --profile smoke --iterations 1 --warmup 0 --format both --out .benchmark/results/smoke",
114
- "bench:baseline": "node scripts/bench-builds.mts --profile default --iterations 5 --warmup 1 --clean build --format both --out .benchmark/results/baseline",
115
- "bench:full": "node scripts/bench-builds.mts --profile full --iterations 5 --warmup 1 --clean build --format both --out .benchmark/results/full",
116
- "bench:large": "node scripts/bench-builds.mts --profile large --iterations 1 --warmup 0 --clean cold --format both --out .benchmark/results/large",
117
- "bench:synthetic-app": "node scripts/bench-synthetic-app.mjs",
114
+ "bench": "pnpm build && node benchmarks/run.mts",
115
+ "bench:smoke": "pnpm build && node benchmarks/run.mts --iterations 1 --warmup 0",
116
+ "bench:codspeed": "pnpm build && vitest bench --run --config vitest.benchmark.config.mts",
118
117
  "e2e": "pnpm build && pnpm test:package-interop && pnpm --filter './examples/{default-template,spa-mode,prerender,custom-node-server,cloudflare,client-only}' test:e2e",
119
118
  "dev": "rslib build --watch",
120
119
  "test": "rstest run",
@@ -6,10 +6,10 @@ import {
6
6
  getReactRouterManifestForDev,
7
7
  type ReactRouterManifestStats,
8
8
  } from './manifest.js';
9
- import type { RouteTransformExecutor } from './parallel-route-transforms.js';
10
9
  import type { ReactRouterPerformanceProfiler } from './performance.js';
11
10
  import { createBundlerRouteExportResolver } from './route-export-resolution.js';
12
11
  import type { RouteChunkConfig } from './route-chunks.js';
12
+ import type { RouteTransformRunner } from './route-transform-tasks.js';
13
13
  import type { PluginOptions, Route } from './types.js';
14
14
  import { isSourceMapEnabled } from './warnings/warn-on-client-source-maps.js';
15
15
 
@@ -31,11 +31,12 @@ type RegisterBuildOutputTransformsOptions = {
31
31
  appDirectory: string;
32
32
  getAssetPrefix: () => string;
33
33
  routeChunkOptions: Parameters<typeof getReactRouterManifestForDev>[5];
34
- routeTransformExecutor: RouteTransformExecutor;
34
+ routeTransformRunner: RouteTransformRunner;
35
35
  routeByFilePath: Map<string, Route>;
36
36
  routeChunkConfig: RouteChunkConfig;
37
37
  isBuild: boolean;
38
38
  splitRouteModules: boolean;
39
+ useRouteModuleTransformApi: boolean;
39
40
  ssr: boolean;
40
41
  isSpaMode: boolean;
41
42
  rootRoutePath: string;
@@ -54,11 +55,12 @@ export const registerBuildOutputTransforms = ({
54
55
  appDirectory,
55
56
  getAssetPrefix,
56
57
  routeChunkOptions,
57
- routeTransformExecutor,
58
+ routeTransformRunner,
58
59
  routeByFilePath,
59
60
  routeChunkConfig,
60
61
  isBuild,
61
62
  splitRouteModules,
63
+ useRouteModuleTransformApi,
62
64
  ssr,
63
65
  isSpaMode,
64
66
  rootRoutePath,
@@ -70,7 +72,7 @@ export const registerBuildOutputTransforms = ({
70
72
  'route:module',
71
73
  args.resource,
72
74
  async () =>
73
- routeTransformExecutor.run({
75
+ routeTransformRunner({
74
76
  kind: 'routeModule',
75
77
  code: args.code,
76
78
  resource: args.resource,
@@ -154,7 +156,7 @@ export const registerBuildOutputTransforms = ({
154
156
  'route:client-entry',
155
157
  args.resource,
156
158
  async () =>
157
- routeTransformExecutor.run({
159
+ routeTransformRunner({
158
160
  kind: 'routeClientEntry',
159
161
  code: args.code,
160
162
  resourcePath: args.resourcePath,
@@ -178,7 +180,7 @@ export const registerBuildOutputTransforms = ({
178
180
  'route:chunk',
179
181
  args.resource,
180
182
  async () =>
181
- routeTransformExecutor.run({
183
+ routeTransformRunner({
182
184
  kind: 'routeChunk',
183
185
  code: args.code,
184
186
  resource: args.resource,
@@ -204,7 +206,7 @@ export const registerBuildOutputTransforms = ({
204
206
  'route:split-exports',
205
207
  args.resource,
206
208
  async () =>
207
- routeTransformExecutor.run({
209
+ routeTransformRunner({
208
210
  kind: 'splitRouteExports',
209
211
  code: args.code,
210
212
  resourcePath: args.resourcePath,
@@ -244,7 +246,7 @@ export const registerBuildOutputTransforms = ({
244
246
  'module:client-only-stub',
245
247
  args.resource,
246
248
  async () => {
247
- return routeTransformExecutor.run({
249
+ return routeTransformRunner({
248
250
  kind: 'clientOnlyStub',
249
251
  code: args.code,
250
252
  resourcePath: args.resourcePath,
@@ -257,22 +259,24 @@ export const registerBuildOutputTransforms = ({
257
259
  )
258
260
  );
259
261
 
260
- api.transform(
261
- {
262
- resourceQuery: /\?react-router-route/,
263
- order: 'post',
264
- },
265
- transformRouteModule
266
- );
262
+ if (useRouteModuleTransformApi) {
263
+ api.transform(
264
+ {
265
+ resourceQuery: /\?react-router-route/,
266
+ order: 'post',
267
+ },
268
+ transformRouteModule
269
+ );
267
270
 
268
- api.transform(
269
- {
270
- test: path => routeByFilePath.has(path),
271
- resourceQuery: {
272
- not: /__react-router-build-client-route|react-router-route|route-chunk=/,
271
+ api.transform(
272
+ {
273
+ test: path => routeByFilePath.has(path),
274
+ resourceQuery: {
275
+ not: /__react-router-build-client-route|react-router-route|route-chunk=/,
276
+ },
277
+ order: 'post',
273
278
  },
274
- order: 'post',
275
- },
276
- transformRouteModule
277
- );
279
+ transformRouteModule
280
+ );
281
+ }
278
282
  };
@@ -18,7 +18,6 @@ import {
18
18
  configRoutesToRouteManifestEntries,
19
19
  type ReactRouterManifestForDev,
20
20
  } from './manifest.js';
21
- import type { RouteTransformExecutor } from './parallel-route-transforms.js';
22
21
  import {
23
22
  createRouteManifestSnapshot,
24
23
  createRouteTopologyWatcher,
@@ -31,7 +30,6 @@ type RegisterReactRouterDevBackgroundResourcesOptions = {
31
30
  api: RsbuildPluginAPI;
32
31
  isBuild: boolean;
33
32
  lazyCompilationPrewarm: PluginOptions['unstableLazyCompilationPrewarm'];
34
- routeTransformExecutor: RouteTransformExecutor;
35
33
  routeRestartMarkerPath: string;
36
34
  watchDirectory: string;
37
35
  getRouteTopology: () => Promise<Set<string>>;
@@ -135,7 +133,6 @@ export const registerReactRouterDevBackgroundResources = ({
135
133
  api,
136
134
  isBuild,
137
135
  lazyCompilationPrewarm,
138
- routeTransformExecutor,
139
136
  routeRestartMarkerPath,
140
137
  watchDirectory,
141
138
  getRouteTopology,
@@ -213,10 +210,6 @@ export const registerReactRouterDevBackgroundResources = ({
213
210
  scheduleRouteTopologyWatcher();
214
211
  lazyCompilationPrewarmController?.schedule();
215
212
  });
216
-
217
- // Spawn transform workers now so thread startup overlaps Rsbuild's own
218
- // compiler creation instead of delaying the first route transform.
219
- routeTransformExecutor.prewarm();
220
213
  }
221
214
 
222
215
  const closeRouteTopologyWatcher = async (): Promise<void> => {
@@ -232,20 +225,12 @@ export const registerReactRouterDevBackgroundResources = ({
232
225
  );
233
226
  };
234
227
 
235
- const closeRouteTransformExecutor = (): Promise<void> =>
236
- routeTransformExecutor.close();
237
-
238
228
  api.onCloseDevServer(() =>
239
229
  closeAll(
240
230
  '[rsbuild-plugin-react-router] Failed to close dev server resources.',
241
- [
242
- closeRouteTopologyWatcher,
243
- closeLazyCompilationPrewarm,
244
- closeRouteTransformExecutor,
245
- ]
231
+ [closeRouteTopologyWatcher, closeLazyCompilationPrewarm]
246
232
  )
247
233
  );
248
- api.onCloseBuild(closeRouteTransformExecutor);
249
234
 
250
235
  return {
251
236
  setManifest(manifest) {
@@ -0,0 +1,38 @@
1
+ import type { Rspack } from '@rsbuild/core';
2
+
3
+ type ModuleFederationPluginLike = {
4
+ name?: string;
5
+ _options?: { experiments?: { asyncStartup?: boolean } };
6
+ options?: { experiments?: { asyncStartup?: boolean } };
7
+ };
8
+
9
+ export const ensureFederationAsyncStartup = (
10
+ rspackConfig: Rspack.Configuration | undefined
11
+ ): void => {
12
+ if (!rspackConfig?.plugins?.length) {
13
+ return;
14
+ }
15
+
16
+ for (const plugin of rspackConfig.plugins) {
17
+ if (!plugin || typeof plugin !== 'object') {
18
+ continue;
19
+ }
20
+ const federationPlugin = plugin as ModuleFederationPluginLike;
21
+ if (
22
+ federationPlugin.name !== 'ModuleFederationPlugin' &&
23
+ federationPlugin.name !== 'RspackModuleFederationPlugin'
24
+ ) {
25
+ continue;
26
+ }
27
+
28
+ const pluginOptions = federationPlugin._options ?? federationPlugin.options;
29
+ if (!pluginOptions) {
30
+ continue;
31
+ }
32
+
33
+ pluginOptions.experiments = {
34
+ ...pluginOptions.experiments,
35
+ asyncStartup: true,
36
+ };
37
+ }
38
+ };
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  PLUGIN_NAME,
19
19
  } from './constants.js';
20
20
  import { guardReactRouterLazyCompilation } from './lazy-compilation.js';
21
+ import { ensureFederationAsyncStartup } from './federation.js';
21
22
  import { createReactRouterDevServerSetup } from './dev-server.js';
22
23
  import {
23
24
  generateWithProps,
@@ -52,9 +53,13 @@ import {
52
53
  type RouteChunkConfig,
53
54
  } from './route-chunks.js';
54
55
  import {
55
- createRouteTransformExecutor,
56
- shouldParallelizeRouteTransforms,
57
- } from './parallel-route-transforms.js';
56
+ registerRouteModuleTransformRules,
57
+ shouldUseRouteModuleTransformLoader,
58
+ } from './route-module-transform-rules.js';
59
+ import {
60
+ executeRouteTransformTask,
61
+ type RouteTransformRunner,
62
+ } from './route-transform-tasks.js';
58
63
  import { getRouteRestartMarkerPath, mergeWatchFiles } from './route-watch.js';
59
64
  import { validateRouteConfig } from './route-config.js';
60
65
  import {
@@ -106,42 +111,6 @@ export const shouldParallelizeEnvironmentBuilds = ({
106
111
  }): boolean =>
107
112
  !isBuild && spareCoreCount >= MIN_PARALLEL_ENVIRONMENT_BUILD_SPARE_CORES;
108
113
 
109
- type ModuleFederationPluginLike = {
110
- name?: string;
111
- _options?: { experiments?: { asyncStartup?: boolean } };
112
- options?: { experiments?: { asyncStartup?: boolean } };
113
- };
114
-
115
- const ensureFederationAsyncStartup = (
116
- rspackConfig: Rspack.Configuration | undefined
117
- ): void => {
118
- if (!rspackConfig?.plugins?.length) {
119
- return;
120
- }
121
-
122
- for (const plugin of rspackConfig.plugins) {
123
- if (!plugin || typeof plugin !== 'object') {
124
- continue;
125
- }
126
- const pluginName = (plugin as ModuleFederationPluginLike).name;
127
- if (pluginName !== 'ModuleFederationPlugin') {
128
- continue;
129
- }
130
-
131
- const pluginOptions =
132
- (plugin as ModuleFederationPluginLike)._options ??
133
- (plugin as ModuleFederationPluginLike).options;
134
- if (!pluginOptions) {
135
- continue;
136
- }
137
-
138
- pluginOptions.experiments = {
139
- ...pluginOptions.experiments,
140
- asyncStartup: true,
141
- };
142
- }
143
- };
144
-
145
114
  const cssUrlAssetExtensions =
146
115
  /\.(?:css|less|sass|scss|styl|stylus|pcss|postcss|sss)$/;
147
116
  const urlAssetResourceQuery =
@@ -429,14 +398,11 @@ export const pluginReactRouter = (
429
398
  rootRouteFile,
430
399
  };
431
400
  const routeChunkCache: RouteChunkCache = new Map();
432
- const routeTransformExecutor = createRouteTransformExecutor({
433
- parallelRouteTransform:
434
- pluginOptions.parallelRouteTransform ??
435
- shouldParallelizeRouteTransforms(routeCount),
436
- routeChunkCache,
437
- splitRouteModules: Boolean(splitRouteModules),
438
- isBuild,
439
- });
401
+ const useRouteModuleTransformLoader = shouldUseRouteModuleTransformLoader(
402
+ pluginOptions.parallelRouteTransform
403
+ );
404
+ const routeTransformRunner: RouteTransformRunner = task =>
405
+ executeRouteTransformTask(task, { routeChunkCache });
440
406
  const routeChunkOptions = {
441
407
  splitRouteModules,
442
408
  rootRouteFile,
@@ -457,7 +423,6 @@ export const pluginReactRouter = (
457
423
  api,
458
424
  isBuild,
459
425
  lazyCompilationPrewarm: pluginOptions.unstableLazyCompilationPrewarm,
460
- routeTransformExecutor,
461
426
  routeRestartMarkerPath,
462
427
  watchDirectory,
463
428
  getRouteTopology: routeTopology.getRouteTopology,
@@ -783,7 +748,6 @@ export const pluginReactRouter = (
783
748
  routeCount >= 256 &&
784
749
  (config.performance?.printFileSize === undefined ||
785
750
  config.performance.printFileSize === true);
786
-
787
751
  return mergeRsbuildConfig(config, {
788
752
  ...(shouldCompactFileSizeReport
789
753
  ? {
@@ -800,7 +764,6 @@ export const pluginReactRouter = (
800
764
  assetPrefix: config.output?.assetPrefix || '/',
801
765
  },
802
766
  dev: {
803
- writeToDisk: true,
804
767
  ...lazyCompilation,
805
768
  watchFiles: mergeWatchFiles(config.dev?.watchFiles, routeWatchFiles),
806
769
  },
@@ -944,17 +907,34 @@ export const pluginReactRouter = (
944
907
  return mergeEnvironmentConfig(config, {
945
908
  tools: {
946
909
  rspack: rspackConfig => {
910
+ const environmentDevHmrEnabled =
911
+ name === 'web' &&
912
+ !isBuild &&
913
+ devHmrRefreshRuntimePath !== undefined &&
914
+ config.mode === 'development' &&
915
+ config.dev?.hmr !== false &&
916
+ isRspackSwcReactRefreshEnabled(rspackConfig);
917
+
918
+ if (useRouteModuleTransformLoader) {
919
+ registerRouteModuleTransformRules(rspackConfig, {
920
+ environmentName: name,
921
+ ssr,
922
+ isBuild,
923
+ isSpaMode,
924
+ rootRoutePath,
925
+ devHmr: environmentDevHmrEnabled,
926
+ logPerformance,
927
+ routeByFilePath,
928
+ parallelRouteTransform: pluginOptions.parallelRouteTransform,
929
+ });
930
+ }
931
+
947
932
  if (pluginOptions.federation) {
948
933
  ensureFederationAsyncStartup(rspackConfig);
949
934
  }
950
935
 
951
936
  if (name === 'web') {
952
- devHmrEnabled =
953
- !isBuild &&
954
- devHmrRefreshRuntimePath !== undefined &&
955
- config.mode === 'development' &&
956
- config.dev?.hmr !== false &&
957
- isRspackSwcReactRefreshEnabled(rspackConfig);
937
+ devHmrEnabled = environmentDevHmrEnabled;
958
938
  if (devHmrEnabled) {
959
939
  devHdrSignal?.ensure();
960
940
  }
@@ -1024,11 +1004,12 @@ export const pluginReactRouter = (
1024
1004
  appDirectory,
1025
1005
  getAssetPrefix: () => assetPrefix,
1026
1006
  routeChunkOptions,
1027
- routeTransformExecutor,
1007
+ routeTransformRunner,
1028
1008
  routeByFilePath,
1029
1009
  routeChunkConfig,
1030
1010
  isBuild,
1031
1011
  splitRouteModules: Boolean(splitRouteModules),
1012
+ useRouteModuleTransformApi: !useRouteModuleTransformLoader,
1032
1013
  ssr,
1033
1014
  isSpaMode,
1034
1015
  rootRoutePath,
@@ -54,9 +54,15 @@ export const roundMs = (value: number): number => Math.round(value * 10) / 10;
54
54
  export type ReactRouterPerformanceReport = {
55
55
  environment: string;
56
56
  compilerLifecycleMs?: number;
57
+ partial?: boolean;
58
+ workerId?: string;
57
59
  operations: Record<string, OperationTiming>;
58
60
  };
59
61
 
62
+ export const formatReactRouterPerformanceReport = (
63
+ report: ReactRouterPerformanceReport
64
+ ): string => `[react-router:performance] ${JSON.stringify(report)}`;
65
+
60
66
  export type ReactRouterPerformanceProfiler = {
61
67
  record<T>(
62
68
  environment: string | undefined,
@@ -72,7 +78,10 @@ export type ReactRouterPerformanceProfiler = {
72
78
  ): T;
73
79
  flush(
74
80
  environment: string | undefined,
75
- details?: Pick<ReactRouterPerformanceReport, 'compilerLifecycleMs'>
81
+ details?: Pick<
82
+ ReactRouterPerformanceReport,
83
+ 'compilerLifecycleMs' | 'partial' | 'workerId'
84
+ >
76
85
  ): void;
77
86
  };
78
87
 
@@ -247,7 +256,7 @@ export const createReactRouterPerformanceProfiler = ({
247
256
  ...details,
248
257
  operations,
249
258
  };
250
- log(`[react-router:performance] ${JSON.stringify(report)}`);
259
+ log(formatReactRouterPerformanceReport(report));
251
260
  timingsByEnvironment.delete(resolvedEnvironment);
252
261
  },
253
262
  };