rsbuild-plugin-react-router 0.7.2 → 0.8.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.
Files changed (53) hide show
  1. package/README.md +14 -2
  2. package/dist/468.js +48 -0
  3. package/dist/511.js +60 -86
  4. package/dist/819.js +64 -0
  5. package/dist/build-output-transforms.d.ts +3 -1
  6. package/dist/constants.d.ts +1 -0
  7. package/dist/dev-hdr-channel.d.ts +9 -0
  8. package/dist/dev-hmr.d.ts +1 -22
  9. package/dist/dev-runtime-controller.d.ts +1 -6
  10. package/dist/dev-server.d.ts +3 -1
  11. package/dist/index.cjs +5417 -5080
  12. package/dist/index.js +1701 -1441
  13. package/dist/manifest-assets.d.ts +34 -0
  14. package/dist/manifest-snapshot.d.ts +17 -0
  15. package/dist/manifest-state.d.ts +12 -0
  16. package/dist/manifest.d.ts +2 -22
  17. package/dist/modify-browser-manifest.d.ts +2 -0
  18. package/dist/node-only-manifest.d.ts +8 -0
  19. package/dist/plugin-utils.d.ts +1 -1
  20. package/dist/rsc-prerender.d.ts +3 -2
  21. package/dist/server-build-worker-client.d.ts +20 -0
  22. package/dist/server-build-worker-protocol.d.ts +84 -0
  23. package/dist/server-build-worker.d.ts +1 -0
  24. package/dist/server-build-worker.js +123 -0
  25. package/dist/server-utils.d.ts +1 -2
  26. package/dist/types.d.ts +6 -0
  27. package/package.json +4 -4
  28. package/src/build-output-transforms.ts +22 -1
  29. package/src/classic-mode.ts +0 -1
  30. package/src/constants.ts +3 -0
  31. package/src/dev-hdr-channel.ts +38 -0
  32. package/src/dev-hmr.ts +57 -100
  33. package/src/dev-runtime-controller.ts +23 -18
  34. package/src/dev-server.ts +24 -4
  35. package/src/index.ts +229 -144
  36. package/src/lazy-compilation.ts +7 -2
  37. package/src/manifest-assets.ts +228 -0
  38. package/src/manifest-snapshot.ts +80 -0
  39. package/src/manifest-state.ts +71 -0
  40. package/src/manifest.ts +23 -161
  41. package/src/mode-plan.ts +12 -4
  42. package/src/modify-browser-manifest.ts +47 -18
  43. package/src/node-only-manifest.ts +52 -0
  44. package/src/plugin-utils.ts +6 -2
  45. package/src/prerender-build.ts +76 -86
  46. package/src/route-chunks.ts +152 -63
  47. package/src/rsc-prerender.ts +7 -35
  48. package/src/server-build-resolution.ts +1 -2
  49. package/src/server-build-worker-client.ts +221 -0
  50. package/src/server-build-worker-protocol.ts +69 -0
  51. package/src/server-build-worker.ts +192 -0
  52. package/src/server-utils.ts +0 -2
  53. package/src/types.ts +7 -0
package/README.md CHANGED
@@ -76,6 +76,16 @@ rsbuild.config.ts
76
76
 
77
77
  ## Configuration
78
78
 
79
+ This plugin requires Rsbuild 2.2.8 or newer. Development hot data revalidation
80
+ uses its custom-event connection API and no longer writes an HDR revision file.
81
+
82
+ For server-only changes, `rsbuild build --environment node` can reuse the
83
+ finalized browser manifest from a previous full build in the same project.
84
+ Keep the browser output and build cache. Run a full build after changing routes
85
+ or browser assets, or adding or removing a route's `loader` or `action` export.
86
+ Node-only builds check the compiled exports against the cached manifest. If the
87
+ manifest is missing or incompatible, the build fails and asks for a full build.
88
+
79
89
  React Router application settings live in `react-router.config.*`. The Rsbuild
80
90
  plugin only needs options for Rsbuild-specific behavior.
81
91
 
@@ -83,6 +93,7 @@ plugin only needs options for Rsbuild-specific behavior.
83
93
 
84
94
  ```ts
85
95
  pluginReactRouter({
96
+ typegen: true,
86
97
  customServer: false,
87
98
  lazyCompilation: true,
88
99
  unstableLazyCompilationPrewarm: false,
@@ -93,12 +104,13 @@ pluginReactRouter({
93
104
 
94
105
  | Option | Default | Description |
95
106
  | -------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
107
+ | `typegen` | `true` | Generates React Router route types during development and builds. Set to `false` when type generation is managed separately. |
96
108
  | `customServer` | `false` | Disables the built-in development SSR middleware. Enable this when an app owns the server with `createDevServer()` or an adapter. |
97
109
  | `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. |
98
110
  | `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. |
99
111
  | `unstableLazyCompilationPrewarm` | `false` | Experimental prewarm for emitted lazy-compilation proxy modules after dev compiles. Enable with `true` when route JS proxy startup should happen shortly after compiler readiness. |
100
112
  | `logPerformance` | `false` | Logs structured React Router plugin timing information. |
101
- | `parallelRouteTransform` | `undefined` | Controls worker-thread route transforms. `undefined` and `false` keep transforms inline, `true` uses an automatic worker count, and a positive integer sets the maximum worker count. |
113
+ | `parallelRouteTransform` | `undefined` | Controls worker-thread route transforms. `undefined` and `false` keep transforms inline, `true` uses an automatic worker count, and a positive integer sets the maximum worker count. |
102
114
  | `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. |
103
115
  | `federation` | `false` | Enables the plugin's experimental Module Federation integration. |
104
116
 
@@ -185,7 +197,7 @@ React Router's SPA Mode still requires a build-time server render of the root ro
185
197
  When `ssr: false`:
186
198
 
187
199
  - The plugin builds both `web` and `node` internally.
188
- - It generates `build/client/index.html` by running the server build once (requesting `basename` with the `X-React-Router-SPA-Mode: yes` header).
200
+ - It generates `build/client/index.html` by running the server build once (requesting `basename` with the `X-React-Router-SPA-Mode: yes` header). The server bundle is evaluated in a worker thread that is terminated afterwards, with `process.env.IS_RR_BUILD_REQUEST === 'yes'` set, so module-scope side effects in your root route's import graph run at build time but cannot keep `rsbuild build` alive. The same applies to prerendering.
189
201
  - It removes `build/server` after generating `index.html`, so the output is deployable as static assets.
190
202
 
191
203
  **Important:** In SPA mode, use `clientLoader` instead of `loader` for data loading since there's no server at runtime.
package/dist/468.js ADDED
@@ -0,0 +1,48 @@
1
+ let PLUGIN_NAME = 'rsbuild:react-router', DEFAULT_JS_DIST_PATH = 'static/js', JS_EXTENSIONS = [
2
+ '.tsx',
3
+ '.ts',
4
+ '.jsx',
5
+ '.js',
6
+ '.mjs',
7
+ '.mts'
8
+ ], BUILD_CLIENT_ROUTE_QUERY_STRING = '?__react-router-build-client-route', SERVER_ONLY_ROUTE_EXPORTS = [
9
+ 'loader',
10
+ 'action',
11
+ 'middleware',
12
+ 'headers'
13
+ ], SERVER_ONLY_ROUTE_EXPORTS_SET = new Set(SERVER_ONLY_ROUTE_EXPORTS), CLIENT_NON_COMPONENT_EXPORTS = [
14
+ 'clientAction',
15
+ 'clientLoader',
16
+ 'clientMiddleware',
17
+ 'handle',
18
+ 'meta',
19
+ 'links',
20
+ 'shouldRevalidate'
21
+ ], CLIENT_ROUTE_EXPORTS_SET = new Set([
22
+ ...CLIENT_NON_COMPONENT_EXPORTS,
23
+ 'default',
24
+ 'ErrorBoundary',
25
+ 'HydrateFallback',
26
+ 'Layout'
27
+ ]), NAMED_COMPONENT_EXPORTS_SET = new Set([
28
+ 'HydrateFallback',
29
+ 'ErrorBoundary'
30
+ ]), SERVER_EXPORTS = {
31
+ loader: 'loader',
32
+ action: 'action',
33
+ middleware: 'middleware',
34
+ headers: 'headers'
35
+ }, CLIENT_EXPORTS = {
36
+ clientAction: 'clientAction',
37
+ clientLoader: 'clientLoader',
38
+ clientMiddleware: 'clientMiddleware',
39
+ default: 'default',
40
+ ErrorBoundary: 'ErrorBoundary',
41
+ handle: 'handle',
42
+ HydrateFallback: 'HydrateFallback',
43
+ Layout: 'Layout',
44
+ links: 'links',
45
+ meta: 'meta',
46
+ shouldRevalidate: 'shouldRevalidate'
47
+ }, SPA_FALLBACK_HTML_FILE = '__spa-fallback.html', BROWSER_MANIFEST_ENTRY_NAME = 'virtual/react-router/browser-manifest';
48
+ export { BROWSER_MANIFEST_ENTRY_NAME, BUILD_CLIENT_ROUTE_QUERY_STRING, CLIENT_EXPORTS, CLIENT_NON_COMPONENT_EXPORTS, CLIENT_ROUTE_EXPORTS_SET, DEFAULT_JS_DIST_PATH, JS_EXTENSIONS, NAMED_COMPONENT_EXPORTS_SET, PLUGIN_NAME, SERVER_EXPORTS, SERVER_ONLY_ROUTE_EXPORTS, SERVER_ONLY_ROUTE_EXPORTS_SET, SPA_FALLBACK_HTML_FILE };
package/dist/511.js CHANGED
@@ -2,57 +2,12 @@ import { basename, dirname, normalize, relative, resolve } from "pathe";
2
2
  import { existsSync, readFileSync, statSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import { langFromPath, parse, walk as external_yuku_parser_walk } from "yuku-parser";
5
- import { Analyzer } from "yuku-analyzer";
5
+ import { Analyzer, SymbolFlags } from "yuku-analyzer";
6
6
  import { print } from "yuku-codegen";
7
7
  import { readFile, stat } from "node:fs/promises";
8
8
  import { rspack } from "@rsbuild/core";
9
- let PLUGIN_NAME = 'rsbuild:react-router', DEFAULT_JS_DIST_PATH = 'static/js', JS_EXTENSIONS = [
10
- '.tsx',
11
- '.ts',
12
- '.jsx',
13
- '.js',
14
- '.mjs',
15
- '.mts'
16
- ], BUILD_CLIENT_ROUTE_QUERY_STRING = '?__react-router-build-client-route', SERVER_ONLY_ROUTE_EXPORTS = [
17
- 'loader',
18
- 'action',
19
- 'middleware',
20
- 'headers'
21
- ], SERVER_ONLY_ROUTE_EXPORTS_SET = new Set(SERVER_ONLY_ROUTE_EXPORTS), CLIENT_NON_COMPONENT_EXPORTS = [
22
- 'clientAction',
23
- 'clientLoader',
24
- 'clientMiddleware',
25
- 'handle',
26
- 'meta',
27
- 'links',
28
- 'shouldRevalidate'
29
- ], CLIENT_ROUTE_EXPORTS_SET = new Set([
30
- ...CLIENT_NON_COMPONENT_EXPORTS,
31
- 'default',
32
- 'ErrorBoundary',
33
- 'HydrateFallback',
34
- 'Layout'
35
- ]), NAMED_COMPONENT_EXPORTS_SET = new Set([
36
- 'HydrateFallback',
37
- 'ErrorBoundary'
38
- ]), SERVER_EXPORTS = {
39
- loader: 'loader',
40
- action: 'action',
41
- middleware: 'middleware',
42
- headers: 'headers'
43
- }, CLIENT_EXPORTS = {
44
- clientAction: 'clientAction',
45
- clientLoader: 'clientLoader',
46
- clientMiddleware: 'clientMiddleware',
47
- default: 'default',
48
- ErrorBoundary: 'ErrorBoundary',
49
- handle: 'handle',
50
- HydrateFallback: 'HydrateFallback',
51
- Layout: 'Layout',
52
- links: 'links',
53
- meta: 'meta',
54
- shouldRevalidate: 'shouldRevalidate'
55
- }, SPA_FALLBACK_HTML_FILE = '__spa-fallback.html', getProgram = (ast)=>ast.program ?? ast, getPatternIdentifierNames = (pattern, names = new Set())=>{
9
+ import { SERVER_ONLY_ROUTE_EXPORTS, SERVER_EXPORTS, SERVER_ONLY_ROUTE_EXPORTS_SET, JS_EXTENSIONS, CLIENT_EXPORTS, PLUGIN_NAME, NAMED_COMPONENT_EXPORTS_SET, CLIENT_ROUTE_EXPORTS_SET } from "./468.js";
10
+ let getProgram = (ast)=>ast.program ?? ast, getPatternIdentifierNames = (pattern, names = new Set())=>{
56
11
  if (!pattern) return names;
57
12
  if ('Identifier' === pattern.type) return names.add(pattern.name), names;
58
13
  if ('RestElement' === pattern.type) return getPatternIdentifierNames(pattern.argument, names);
@@ -345,9 +300,9 @@ let PLUGIN_NAME = 'rsbuild:react-router', DEFAULT_JS_DIST_PATH = 'static/js', JS
345
300
  if (declaration && declarationIncludesName(declaration, name)) return !0;
346
301
  }
347
302
  return !1;
348
- }, requireFromApp = createRequire(resolve(process.cwd(), 'package.json')), resolveAppPackagePath = (specifier)=>{
303
+ }, requireFromApp = createRequire(resolve(process.cwd(), 'package.json')), resolveAppPackagePath = (specifier, rootPath)=>{
349
304
  try {
350
- return requireFromApp.resolve(specifier);
305
+ return (rootPath ? createRequire(resolve(rootPath, 'package.json')) : requireFromApp).resolve(specifier);
351
306
  } catch {
352
307
  return;
353
308
  }
@@ -453,12 +408,7 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
453
408
  module,
454
409
  program: module.ast
455
410
  };
456
- }), isTopLevelExportedVariableDeclarator = (module, node)=>{
457
- let declaration = module.parentOf(node);
458
- if (declaration?.type !== 'VariableDeclaration') return !1;
459
- let statement = module.parentOf(declaration);
460
- return statement?.type === 'ExportNamedDeclaration';
461
- }, route_chunks_getExportedName = (exported)=>'Identifier' === exported.type ? exported.name : String(exported.value), setsIntersect = (set1, set2)=>{
411
+ }), route_chunks_getExportedName = (exported)=>'Identifier' === exported.type ? exported.name : String(exported.value), setsIntersect = (set1, set2)=>{
462
412
  let smallerSet = set1, largerSet = set2;
463
413
  for (let element of (set1.size > set2.size && (smallerSet = set2, largerSet = set1), smallerSet))if (largerSet.has(element)) return !0;
464
414
  return !1;
@@ -467,7 +417,13 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
467
417
  let resolved = normalize(resolve('/', dirname(importer), source));
468
418
  return /(?:^|\/)entry\.client(?:\.[cm]?[jt]sx?)?$/.test(resolved);
469
419
  }, getExportDependencies = (code, cache, cacheKey)=>getOrSetFromCache(cache, `${cacheKey}::getExportDependencies`, code, ()=>{
470
- let { module } = analyzeCode(code, cache, cacheKey), exportDependencies = new Map(), topLevelStatementCache = new Map(), variableDeclaratorCache = new Map(), getCachedTopLevelStatementForNode = (node)=>{
420
+ let { module } = analyzeCode(code, cache, cacheKey), namedExports = module.exports.filter((exp)=>null !== exp.name && !exp.typeOnly && !exp.isStar && !exp.isExportEquals), hasDecorators = !1;
421
+ external_yuku_parser_walk(module.ast, {
422
+ Decorator (_node, context) {
423
+ hasDecorators = !0, context.stop();
424
+ }
425
+ });
426
+ let exportDependencies = new Map(), topLevelStatementCache = new Map(), exportedVariableDeclaratorCache = new Map(), getCachedTopLevelStatementForNode = (node)=>{
471
427
  let cached = topLevelStatementCache.get(node);
472
428
  if (cached) return cached;
473
429
  let statement = ((module, node)=>{
@@ -476,17 +432,34 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
476
432
  return invariant(parent?.type === 'Program', 'Expected node to be within Program'), current;
477
433
  })(module, node);
478
434
  return topLevelStatementCache.set(node, statement), statement;
479
- }, getCachedVariableDeclaratorForNode = (node)=>{
480
- if (variableDeclaratorCache.has(node)) return variableDeclaratorCache.get(node) ?? null;
435
+ }, nonShareableExportedSymbols = new Set();
436
+ for (let { local } of namedExports){
437
+ if (!local?.has(SymbolFlags.ValueSpace | SymbolFlags.ValueImport)) continue;
438
+ let isImport = local.declarations.every((declaration)=>'ImportDeclaration' === getCachedTopLevelStatementForNode(declaration).type), hasSetup = isImport && local.references.some((reference)=>{
439
+ let statement = getCachedTopLevelStatementForNode(reference.node);
440
+ return 'value' === reference.kind && 'ImportDeclaration' !== statement.type && !statement.type.startsWith('Export');
441
+ });
442
+ (!isImport || hasSetup) && nonShareableExportedSymbols.add(local);
443
+ }
444
+ let isRuntimeRelevantReference = (reference)=>hasDecorators || 'value' === reference.kind || ((reference)=>{
445
+ let node = reference.node, parent = module.parentOf(node);
446
+ for(; parent?.type === 'TSQualifiedName';)node = parent, parent = module.parentOf(node);
447
+ return parent?.type === 'TSImportEqualsDeclaration' && parent.moduleReference === node && 'type' !== parent.importKind;
448
+ })(reference), getCachedExportedVariableDeclaratorForNode = (node)=>{
449
+ if (exportedVariableDeclaratorCache.has(node)) return exportedVariableDeclaratorCache.get(node) ?? null;
481
450
  let declarator = ((module, node)=>{
482
451
  let current = node;
483
- for(; current;){
484
- if ('VariableDeclarator' === current.type) return current;
485
- current = module.parentOf(current);
452
+ for(;;){
453
+ let parent = module.parentOf(current);
454
+ if (!parent || 'Program' === parent.type) return null;
455
+ if ('VariableDeclarator' === current.type && 'VariableDeclaration' === parent.type) {
456
+ let exported = module.parentOf(parent);
457
+ if (exported?.type === 'ExportNamedDeclaration' && module.parentOf(exported)?.type === 'Program') return current;
458
+ }
459
+ current = parent;
486
460
  }
487
- return null;
488
461
  })(module, node);
489
- return variableDeclaratorCache.set(node, declarator), declarator;
462
+ return exportedVariableDeclaratorCache.set(node, declarator), declarator;
490
463
  }, addCachedTopLevelStatement = (dependencies, node)=>{
491
464
  let statement = getCachedTopLevelStatementForNode(node);
492
465
  return dependencies.topLevelStatements.add(statement), 'ImportDeclaration' === statement.type || statement.type.startsWith('Export') || dependencies.topLevelNonModuleStatements.add(statement), statement;
@@ -496,46 +469,47 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
496
469
  topLevelNonModuleStatements: new Set(),
497
470
  importedIdentifierNames: new Set(),
498
471
  importSources: new Set(),
499
- exportedVariableDeclarators: new Set()
500
- }, visitedSymbols = new Set(), scannedNodes = new Set(), scanNode = (node)=>{
472
+ exportedVariableDeclarators: new Set(),
473
+ exportedLocalSymbols: new Set()
474
+ }, visitedSymbols = new Set(), scannedNodes = new Set(), visitIdentifier = (node)=>{
475
+ let reference = module.referenceOf(node);
476
+ if (reference) {
477
+ reference.symbol && isRuntimeRelevantReference(reference) && visitSymbol(reference.symbol);
478
+ return;
479
+ }
480
+ let symbol = module.symbolOf(node);
481
+ symbol?.scope === module.rootScope && symbol.has(SymbolFlags.ValueSpace | SymbolFlags.ValueImport) && dependencies.topLevelNonModuleStatements.has(getCachedTopLevelStatementForNode(node)) && visitSymbol(symbol);
482
+ }, scanNode = (node)=>{
501
483
  scannedNodes.has(node) || (scannedNodes.add(node), external_yuku_parser_walk(node, {
502
- Identifier (node) {
503
- let reference = module.referenceOf(node);
504
- reference?.symbol && visitSymbol(reference.symbol);
505
- }
484
+ Identifier: visitIdentifier,
485
+ JSXIdentifier: visitIdentifier
506
486
  }));
507
487
  }, visitSymbol = (symbol)=>{
508
488
  if (!visitedSymbols.has(symbol) && (visitedSymbols.add(symbol), 0 !== symbol.declarations.length)) {
509
- for (let declaration of symbol.declarations){
489
+ for (let declaration of (nonShareableExportedSymbols.has(symbol) && dependencies.exportedLocalSymbols.add(symbol), symbol.declarations)){
510
490
  let statement = addCachedTopLevelStatement(dependencies, declaration);
511
- if ('ImportDeclaration' === statement.type) {
512
- dependencies.importedIdentifierNames.add(symbol.name), 'string' == typeof statement.source?.value && dependencies.importSources.add(statement.source.value);
513
- return;
514
- }
515
- let declarator = getCachedVariableDeclaratorForNode(declaration);
516
- declarator && isTopLevelExportedVariableDeclarator(module, declarator) && dependencies.exportedVariableDeclarators.add(declarator), scanNode(declarator ?? statement);
491
+ if ('ImportDeclaration' === statement.type && (dependencies.importedIdentifierNames.add(symbol.name), 'string' == typeof statement.source?.value && dependencies.importSources.add(statement.source.value), symbol !== localSymbol)) return;
492
+ let declarator = getCachedExportedVariableDeclaratorForNode(declaration);
493
+ declarator && dependencies.exportedVariableDeclarators.add(declarator), scanNode(declarator ?? statement);
517
494
  }
518
495
  for (let reference of symbol.references){
496
+ if (!isRuntimeRelevantReference(reference)) continue;
519
497
  let statement = addCachedTopLevelStatement(dependencies, reference.node);
520
- scanNode(getCachedVariableDeclaratorForNode(reference.node) ?? statement);
498
+ scanNode(getCachedExportedVariableDeclaratorForNode(reference.node) ?? statement);
521
499
  }
522
500
  }
523
501
  };
524
502
  addCachedTopLevelStatement(dependencies, exportNode), localSymbol ? visitSymbol(localSymbol) : scanNode(getCachedTopLevelStatementForNode(exportNode)), exportDependencies.set(exportName, dependencies);
525
503
  };
526
- for (let exp of module.exports)exp.typeOnly || exp.isStar || exp.isExportEquals || handleExport(exp.name, exp.node, exp.local ?? null);
504
+ for (let exp of namedExports)handleExport(exp.name, exp.node, exp.local ?? null);
527
505
  return exportDependencies;
528
506
  }), isExportChunkable = (exportName, exportDependencies, importer)=>{
529
507
  let dependencies = exportDependencies.get(exportName);
530
- if (!dependencies || 'clientLoader' === exportName && hasHydrateAssignment(dependencies) || 'clientLoader' === exportName && ((dependencies, importer)=>{
508
+ if (!dependencies || dependencies.exportedVariableDeclarators.size > 1 || 'clientLoader' === exportName && hasHydrateAssignment(dependencies) || 'clientLoader' === exportName && ((dependencies, importer)=>{
531
509
  for (let source of dependencies.importSources)if (isEntryClientImport(source, importer)) return !0;
532
510
  return !1;
533
511
  })(dependencies, importer)) return !1;
534
- for (let [currentExportName, currentDependencies] of exportDependencies)if (currentExportName !== exportName && setsIntersect(currentDependencies.topLevelNonModuleStatements, dependencies.topLevelNonModuleStatements)) return !1;
535
- if (dependencies.exportedVariableDeclarators.size > 1) return !1;
536
- if (dependencies.exportedVariableDeclarators.size > 0) {
537
- for (let [currentExportName, currentDependencies] of exportDependencies)if (currentExportName !== exportName && setsIntersect(currentDependencies.exportedVariableDeclarators, dependencies.exportedVariableDeclarators)) return !1;
538
- }
512
+ for (let [currentExportName, currentDependencies] of exportDependencies)if (currentExportName !== exportName && (setsIntersect(currentDependencies.topLevelNonModuleStatements, dependencies.topLevelNonModuleStatements) || setsIntersect(currentDependencies.exportedVariableDeclarators, dependencies.exportedVariableDeclarators) || setsIntersect(currentDependencies.exportedLocalSymbols, dependencies.exportedLocalSymbols))) return !1;
539
513
  return !0;
540
514
  }, hasHydrateAssignment = (dependencies)=>Array.from(dependencies.topLevelNonModuleStatements).some((statement)=>{
541
515
  let expression = statement.expression, left = expression?.left;
@@ -1355,4 +1329,4 @@ if (import.meta.webpackHot) {
1355
1329
  }
1356
1330
  };
1357
1331
  };
1358
- export { BUILD_CLIENT_ROUTE_QUERY_STRING, CLIENT_EXPORTS, CLIENT_NON_COMPONENT_EXPORTS, DEFAULT_JS_DIST_PATH, HMR_PATCHABLE_ROUTE_FLAGS, JS_EXTENSIONS, PLUGIN_NAME, SERVER_EXPORTS, SERVER_ONLY_ROUTE_EXPORTS, SPA_FALLBACK_HTML_FILE, analyzeRouteModuleCode, buildManifestChunkValidity, collectReferencedNames, combineURLs, createBundlerRouteExportResolver, createEmptyRouteChunkByExportName, createReactRouterPerformanceProfiler, createRouteId, detectRouteChunks, detectRouteChunksIfEnabled, escapeHtml, executeRouteTransformTask, findEntryFile, generate, generateWithProps, getExportNames, getExportedName, getPackageVersion, getPatternIdentifierNames, getProgram, getRouteChunkEntryName, getRouteChunkModuleId, getRouteChunkNameFromModuleId, getRouteEntryBaseName, getRouteModuleAnalysis, normalizeAssetPrefix, parseVersionMajorMinor, removeExports, removeUnusedImports, resolveAppPackagePath, resolveEffectiveAssetPrefix, roundMs, routeChunkExportNames, validateRouteChunks, validateSpaModeRouteExports, yuku_parse };
1332
+ export { HMR_PATCHABLE_ROUTE_FLAGS, analyzeRouteModuleCode, buildManifestChunkValidity, collectReferencedNames, combineURLs, createBundlerRouteExportResolver, createEmptyRouteChunkByExportName, createReactRouterPerformanceProfiler, createRouteId, detectRouteChunks, detectRouteChunksIfEnabled, escapeHtml, executeRouteTransformTask, findEntryFile, generate, generateWithProps, getExportNames, getExportedName, getPackageVersion, getPatternIdentifierNames, getProgram, getRouteChunkEntryName, getRouteChunkModuleId, getRouteChunkNameFromModuleId, getRouteEntryBaseName, getRouteModuleAnalysis, normalizeAssetPrefix, parseVersionMajorMinor, removeExports, removeUnusedImports, resolveAppPackagePath, resolveEffectiveAssetPrefix, roundMs, routeChunkExportNames, validateRouteChunks, validateSpaModeRouteExports, yuku_parse };
package/dist/819.js ADDED
@@ -0,0 +1,64 @@
1
+ let RESOLVABLE_BUILD_EXPORTS = new Set([
2
+ 'allowedActionOrigins',
3
+ 'assets',
4
+ 'assetsBuildDirectory',
5
+ 'basename',
6
+ 'entry',
7
+ 'future',
8
+ 'isSpaMode',
9
+ 'prerender',
10
+ 'publicPath',
11
+ 'routeDiscovery',
12
+ 'routes',
13
+ 'ssr'
14
+ ]);
15
+ function isRecord(value) {
16
+ return 'object' == typeof value && null !== value && !Array.isArray(value);
17
+ }
18
+ function isPromiseLike(value) {
19
+ return isRecord(value) && 'function' == typeof value.then;
20
+ }
21
+ async function resolveBuildExports(build) {
22
+ let resolved = {
23
+ ...build
24
+ };
25
+ for (let key of Object.keys(build)){
26
+ if (!RESOLVABLE_BUILD_EXPORTS.has(key)) continue;
27
+ let value = build[key];
28
+ if ('function' == typeof value && 0 === value.length) {
29
+ let result = value();
30
+ resolved[key] = isPromiseLike(result) ? await result : result;
31
+ continue;
32
+ }
33
+ isPromiseLike(value) && (resolved[key] = await value);
34
+ }
35
+ return resolved;
36
+ }
37
+ async function resolveServerBuildCandidate(candidate) {
38
+ var value;
39
+ if (!isRecord(candidate)) return;
40
+ let resolved = await resolveBuildExports(candidate);
41
+ return isRecord(resolved) && isRecord(resolved.entry) && isRecord(resolved.entry.module) && 'function' == typeof resolved.entry.module.default && isRecord(resolved.routes) && isRecord(resolved.assets) && 'string' == typeof resolved.assetsBuildDirectory && (void 0 === resolved.basename || 'string' == typeof resolved.basename) && isRecord(resolved.future) && 'boolean' == typeof resolved.isSpaMode && Array.isArray(resolved.prerender) && 'string' == typeof resolved.publicPath && (void 0 === (value = resolved.routeDiscovery) || isRecord(value) && ('initial' === value.mode || 'lazy' === value.mode && (void 0 === value.manifestPath || 'string' == typeof value.manifestPath))) && 'boolean' == typeof resolved.ssr ? resolved : void 0;
42
+ }
43
+ async function resolveServerBuildModule(buildModule, source) {
44
+ try {
45
+ let moduleValue = isPromiseLike(buildModule) ? await buildModule : buildModule, candidates = [
46
+ ()=>moduleValue
47
+ ];
48
+ for (let getCandidate of (isRecord(moduleValue) && ('default' in moduleValue && candidates.push(()=>moduleValue.default), 'module.exports' in moduleValue && candidates.push(()=>moduleValue['module.exports'])), candidates)){
49
+ let candidate = await getCandidate(), serverBuild = await resolveServerBuildCandidate(candidate);
50
+ if (serverBuild) return serverBuild;
51
+ }
52
+ throw Error(`[rsbuild-plugin-react-router] ${source} did not contain a valid React Router ServerBuild.`);
53
+ } catch (cause) {
54
+ throw cause instanceof Error ? cause : Error(String(cause));
55
+ }
56
+ }
57
+ let headerEntries = (headers)=>{
58
+ let entries = [];
59
+ return headers.forEach((value, key)=>entries.push([
60
+ key,
61
+ value
62
+ ])), entries;
63
+ };
64
+ export { headerEntries, resolveServerBuildModule };
@@ -31,6 +31,8 @@ type RegisterBuildOutputTransformsOptions = {
31
31
  resolvedServerOutput: 'module' | 'commonjs';
32
32
  performanceProfiler: ReactRouterPerformanceProfiler;
33
33
  getLatestServerManifest: () => ReactRouterManifest | null;
34
+ /** File holding the captured manifests; a dependency of the server-manifest module. */
35
+ serverManifestStampPath: string;
34
36
  getLatestServerManifestByBundleId: (bundleId: string) => ReactRouterManifest | undefined;
35
37
  routes: Record<string, Route>;
36
38
  pluginOptions: PluginOptions;
@@ -52,5 +54,5 @@ type RegisterBuildOutputTransformsOptions = {
52
54
  isDevHmrEnabled?: () => boolean;
53
55
  onRouteModuleAnalysis?: (resourcePath: string, analysis: RouteModuleAnalysis) => void;
54
56
  };
55
- export declare const registerBuildOutputTransforms: ({ api, resolvedServerOutput, performanceProfiler, getLatestServerManifest, getLatestServerManifestByBundleId, routes, pluginOptions, getClientStats, appDirectory, getAssetPrefix, routeChunkOptions, routeModuleAnalysis, routeTransformRunner, routeByFilePath, routeChunkConfig, isBuild, splitRouteModules, useRouteModuleTransformApi, ssr, isSpaMode, rootRoutePath, outputClientPath, isDevHmrEnabled, onRouteModuleAnalysis, }: RegisterBuildOutputTransformsOptions) => void;
57
+ export declare const registerBuildOutputTransforms: ({ api, resolvedServerOutput, performanceProfiler, getLatestServerManifest, serverManifestStampPath, getLatestServerManifestByBundleId, routes, pluginOptions, getClientStats, appDirectory, getAssetPrefix, routeChunkOptions, routeModuleAnalysis, routeTransformRunner, routeByFilePath, routeChunkConfig, isBuild, splitRouteModules, useRouteModuleTransformApi, ssr, isSpaMode, rootRoutePath, outputClientPath, isDevHmrEnabled, onRouteModuleAnalysis, }: RegisterBuildOutputTransformsOptions) => void;
56
58
  export {};
@@ -39,3 +39,4 @@ export declare const CLIENT_EXPORTS: {
39
39
  readonly shouldRevalidate: "shouldRevalidate";
40
40
  };
41
41
  export declare const SPA_FALLBACK_HTML_FILE = "__spa-fallback.html";
42
+ export declare const BROWSER_MANIFEST_ENTRY_NAME = "virtual/react-router/browser-manifest";
@@ -0,0 +1,9 @@
1
+ import type { RsbuildDevServer } from '@rsbuild/core';
2
+ export declare const DEV_HDR_UPDATE_EVENT = "react-router:hdr-update";
3
+ export declare const createDevHdrChannel: ({ hot, isEnabled, }: {
4
+ hot: RsbuildDevServer["environments"][string]["hot"];
5
+ isEnabled: () => boolean;
6
+ }) => {
7
+ publish(): void;
8
+ close(): void;
9
+ };
package/dist/dev-hmr.d.ts CHANGED
@@ -4,7 +4,6 @@ export declare const DEV_MANIFEST_UPDATE_EVENT = "react-router:manifest-update";
4
4
  export type DevHmrPlanOptions = {
5
5
  isEnabled: () => boolean;
6
6
  runtimeModule: string;
7
- onNodeRebuildCommitted: () => void;
8
7
  };
9
8
  export declare const isRspackSwcReactRefreshEnabled: (rspackConfig: Rspack.Configuration) => boolean;
10
9
  /**
@@ -16,25 +15,6 @@ export declare const isRspackSwcReactRefreshEnabled: (rspackConfig: Rspack.Confi
16
15
  * dev HMR falls back to full reloads.
17
16
  */
18
17
  export declare const resolveReactRefreshRuntimePath: (rootPath: string) => string | undefined;
19
- /**
20
- * The HDR revision module is a real file (not a virtual module) because it
21
- * must wake the web compiler through the regular file watcher: the browser
22
- * HMR runtime imports it, so bumping the revision produces a web hot update
23
- * whenever server code changes, which the client answers by revalidating
24
- * React Router loader data.
25
- */
26
- export declare const getDevHdrRevisionFilePath: (rootPath: string) => string;
27
- export type DevHdrRevisionSignal = {
28
- filePath: string;
29
- /** Writes the initial revision module so the first compile can resolve it. */
30
- ensure: () => void;
31
- /** Increments the revision, signaling hot data revalidation to the client. */
32
- bump: () => void;
33
- };
34
- export declare const createDevHdrRevisionSignal: ({ filePath, onError, }: {
35
- filePath: string;
36
- onError?: (error: Error) => void;
37
- }) => DevHdrRevisionSignal;
38
18
  /**
39
19
  * Browser-side HMR runtime shared by all route client entries in development.
40
20
  *
@@ -45,7 +25,6 @@ export declare const createDevHdrRevisionSignal: ({ filePath, onError, }: {
45
25
  * recreating the client routes with revalidation opt-out, revalidating loader
46
26
  * data, and finally performing a React refresh.
47
27
  */
48
- export declare const generateDevHmrRuntimeModule: ({ reactRefreshRuntimePath, hdrRevisionFilePath, }: {
28
+ export declare const generateDevHmrRuntimeModule: ({ reactRefreshRuntimePath, }: {
49
29
  reactRefreshRuntimePath: string;
50
- hdrRevisionFilePath: string;
51
30
  }) => string;
@@ -14,11 +14,6 @@ type CreateControllerOptions = {
14
14
  * flags) in place, so metadata-only changes no longer need a full reload.
15
15
  */
16
16
  clientPatchesRouteMetadata?: boolean | (() => boolean);
17
- /**
18
- * Invoked after a development attempt commits a re-evaluated node build for
19
- * changed server files. Used to signal hot data revalidation to the client.
20
- */
21
- onNodeRebuildCommitted?: () => void;
22
17
  };
23
- export declare const createReactRouterDevRuntimeController: ({ api, isBuild, buildPlan, clientPatchesRouteMetadata, onNodeRebuildCommitted, }: CreateControllerOptions) => ReactRouterDevRuntimeController;
18
+ export declare const createReactRouterDevRuntimeController: ({ api, isBuild, buildPlan, clientPatchesRouteMetadata, }: CreateControllerOptions) => ReactRouterDevRuntimeController;
24
19
  export {};
@@ -6,12 +6,14 @@ export type DevServerMiddleware = (req: IncomingMessage, res: ServerResponse, ne
6
6
  type RequestHandler = (request: Request) => Response | Promise<Response>;
7
7
  type BuildProvider = () => Promise<ServerBuild>;
8
8
  export type DevServerMiddlewareDependencies = {
9
+ rootPath: string;
9
10
  loadBuild: BuildProvider;
10
11
  createRequestHandler?: (build: BuildProvider, mode: 'development') => RequestHandler;
11
12
  createRequestListener?: (handler: RequestHandler) => (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
12
13
  };
13
14
  export declare const createDevServerMiddleware: (dependencies: DevServerMiddlewareDependencies) => DevServerMiddleware;
14
- export declare const createReactRouterDevServerSetup: ({ loadBuild, }: {
15
+ export declare const createReactRouterDevServerSetup: ({ loadBuild, rootPath, }: {
15
16
  loadBuild: BuildProvider;
17
+ rootPath: string;
16
18
  }) => ServerSetup;
17
19
  export {};