rsbuild-plugin-react-router 0.3.1 → 0.4.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 +34 -12
- package/dist/451.js +128 -10
- package/dist/build-output-transforms.d.ts +2 -1
- package/dist/dev-hmr.d.ts +45 -0
- package/dist/dev-runtime-controller.d.ts +6 -1
- package/dist/index.cjs +476 -29
- package/dist/index.d.ts +1 -0
- package/dist/index.js +346 -22
- package/dist/route-artifacts.d.ts +10 -2
- package/dist/route-transform-tasks.d.ts +3 -0
- package/package.json +8 -2
- package/src/build-output-transforms.ts +5 -0
- package/src/dev-hmr.ts +431 -0
- package/src/dev-runtime-controller.ts +47 -3
- package/src/index.ts +48 -0
- package/src/prerender-build.ts +29 -9
- package/src/prerender.ts +1 -1
- package/src/route-artifacts.ts +120 -1
- package/src/route-transform-tasks.ts +173 -2
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ async exports before passing the build to React Router's request handler.
|
|
|
98
98
|
Put React Router framework settings in `react-router.config.*`:
|
|
99
99
|
|
|
100
100
|
```ts
|
|
101
|
-
import type {
|
|
101
|
+
import type { ReactRouterRsbuildConfig } from 'rsbuild-plugin-react-router';
|
|
102
102
|
|
|
103
103
|
export default {
|
|
104
104
|
ssr: true,
|
|
@@ -107,9 +107,15 @@ export default {
|
|
|
107
107
|
basename: '/',
|
|
108
108
|
splitRouteModules: true,
|
|
109
109
|
subResourceIntegrity: false,
|
|
110
|
-
} satisfies
|
|
110
|
+
} satisfies ReactRouterRsbuildConfig;
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
Use `ReactRouterRsbuildConfig` for Rsbuild projects so plugin-supported
|
|
114
|
+
configuration such as `splitRouteModules` stays typed. The underlying route
|
|
115
|
+
and config types come from `@react-router/dev`, which framework-mode apps
|
|
116
|
+
already install for `routes.ts` helpers and typegen; it is declared as an
|
|
117
|
+
optional peer dependency.
|
|
118
|
+
|
|
113
119
|
Commonly used options:
|
|
114
120
|
|
|
115
121
|
| Option | Default | Notes |
|
|
@@ -178,7 +184,7 @@ For static sites with multiple pages, you can prerender specific routes at build
|
|
|
178
184
|
|
|
179
185
|
```ts
|
|
180
186
|
// react-router.config.ts
|
|
181
|
-
import type {
|
|
187
|
+
import type { ReactRouterRsbuildConfig } from 'rsbuild-plugin-react-router';
|
|
182
188
|
|
|
183
189
|
export default {
|
|
184
190
|
ssr: false,
|
|
@@ -190,7 +196,7 @@ export default {
|
|
|
190
196
|
'/docs/advanced',
|
|
191
197
|
'/projects',
|
|
192
198
|
],
|
|
193
|
-
} satisfies
|
|
199
|
+
} satisfies ReactRouterRsbuildConfig;
|
|
194
200
|
```
|
|
195
201
|
|
|
196
202
|
When `prerender` is specified:
|
|
@@ -209,7 +215,7 @@ export default {
|
|
|
209
215
|
ssr: false,
|
|
210
216
|
prerender: ({ getStaticPaths }) =>
|
|
211
217
|
getStaticPaths().filter(path => path !== '/admin'),
|
|
212
|
-
} satisfies
|
|
218
|
+
} satisfies ReactRouterRsbuildConfig;
|
|
213
219
|
```
|
|
214
220
|
|
|
215
221
|
Prerendering defaults to one path at a time, matching React Router. Use
|
|
@@ -223,7 +229,7 @@ export default {
|
|
|
223
229
|
paths: ['/', '/about'],
|
|
224
230
|
concurrency: 4,
|
|
225
231
|
},
|
|
226
|
-
} satisfies
|
|
232
|
+
} satisfies ReactRouterRsbuildConfig;
|
|
227
233
|
```
|
|
228
234
|
|
|
229
235
|
For builds with 256+ routes, detailed file-size reporting is compacted to totals
|
|
@@ -584,14 +590,14 @@ export default {
|
|
|
584
590
|
```json
|
|
585
591
|
{
|
|
586
592
|
"dependencies": {
|
|
587
|
-
"@react-router/node": "^7.
|
|
588
|
-
"@react-router/serve": "^7.
|
|
589
|
-
"react-router": "^7.
|
|
593
|
+
"@react-router/node": "^7.13.0",
|
|
594
|
+
"@react-router/serve": "^7.13.0",
|
|
595
|
+
"react-router": "^7.13.0"
|
|
590
596
|
},
|
|
591
597
|
"devDependencies": {
|
|
592
598
|
"@cloudflare/workers-types": "^4.20241112.0",
|
|
593
|
-
"@react-router/cloudflare": "^7.
|
|
594
|
-
"@react-router/dev": "^7.
|
|
599
|
+
"@react-router/cloudflare": "^7.13.0",
|
|
600
|
+
"@react-router/dev": "^7.13.0",
|
|
595
601
|
"wrangler": "^3.106.0"
|
|
596
602
|
}
|
|
597
603
|
}
|
|
@@ -661,7 +667,23 @@ pnpm bench:synthetic-app -- --profile all --runs 2
|
|
|
661
667
|
```
|
|
662
668
|
|
|
663
669
|
The PR benchmark workflow reports production build, dev route-load, HMR/update,
|
|
664
|
-
and embedded synthetic app timings in the same benchmark comment.
|
|
670
|
+
and embedded synthetic app timings in the same benchmark comment. It measures
|
|
671
|
+
the PR and its base on the same runner instead of reusing cached timing data,
|
|
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.
|
|
665
687
|
|
|
666
688
|
## React Router Framework Mode
|
|
667
689
|
|
package/dist/451.js
CHANGED
|
@@ -757,17 +757,67 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
757
757
|
}
|
|
758
758
|
if (unresolvedExportAll.size > 0) throw Error(`[${PLUGIN_NAME}] Client-only module uses \`export * from\` with unresolvable specifier(s): ${Array.from(unresolvedExportAll).map((spec)=>`\`${spec}\``).join(', ')}. Please explicitly re-export named bindings in \`${relative(process.cwd(), resourcePath)}\`.`);
|
|
759
759
|
return exportNames;
|
|
760
|
-
},
|
|
760
|
+
}, HMR_PATCHABLE_ROUTE_FLAGS = [
|
|
761
|
+
'hasAction',
|
|
762
|
+
'hasClientAction',
|
|
763
|
+
'hasClientLoader',
|
|
764
|
+
'hasClientMiddleware',
|
|
765
|
+
'hasErrorBoundary',
|
|
766
|
+
'hasLoader'
|
|
767
|
+
], HMR_FLAG_EXPORT_NAME = {
|
|
768
|
+
hasAction: SERVER_EXPORTS.action,
|
|
769
|
+
hasClientAction: CLIENT_EXPORTS.clientAction,
|
|
770
|
+
hasClientLoader: CLIENT_EXPORTS.clientLoader,
|
|
771
|
+
hasClientMiddleware: CLIENT_EXPORTS.clientMiddleware,
|
|
772
|
+
hasErrorBoundary: CLIENT_EXPORTS.ErrorBoundary,
|
|
773
|
+
hasLoader: SERVER_EXPORTS.loader
|
|
774
|
+
}, createRouteClientEntryArtifact = async ({ code, resourcePath, environmentName, isBuild, routeChunkCache, routeChunkConfig, routeId, devHmr })=>{
|
|
761
775
|
let isServer = 'node' === environmentName, routeChunkInfo = !isServer && isBuild && shouldAnalyzeRouteChunks(routeChunkConfig, resourcePath, code) ? await detectRouteChunksIfEnabled(routeChunkCache, routeChunkConfig, resourcePath, code) : null;
|
|
762
776
|
return {
|
|
763
|
-
code: (({ exportNames, chunkedExports, isServer, resourcePath })=>{
|
|
764
|
-
let chunkedExportSet = chunkedExports.length > 0 ? new Set(chunkedExports) : void 0, reexports = exportNames.filter((exp)=>!chunkedExportSet?.has(exp) && (CLIENT_ROUTE_EXPORTS_SET.has(exp) || isServer && SERVER_ONLY_ROUTE_EXPORTS_SET.has(exp))).sort(), target = `${resourcePath}?react-router-route
|
|
765
|
-
return
|
|
777
|
+
code: (({ exportNames, chunkedExports, isServer, resourcePath, routeId, devHmr })=>{
|
|
778
|
+
let exports, flags, chunkedExportSet = chunkedExports.length > 0 ? new Set(chunkedExports) : void 0, reexports = exportNames.filter((exp)=>!chunkedExportSet?.has(exp) && (CLIENT_ROUTE_EXPORTS_SET.has(exp) || isServer && SERVER_ONLY_ROUTE_EXPORTS_SET.has(exp))).sort(), target = `${resourcePath}?react-router-route`, reexportCode = `export { ${reexports.join(', ')} } from ${JSON.stringify(target)};`;
|
|
779
|
+
return !devHmr || isServer || void 0 === routeId ? reexportCode : reexportCode + (({ routeId, target, acceptTarget, flags })=>{
|
|
780
|
+
let targetJson = JSON.stringify(target), acceptTargetJson = JSON.stringify(acceptTarget);
|
|
781
|
+
return `
|
|
782
|
+
import * as __rrm from ${targetJson};
|
|
783
|
+
import {
|
|
784
|
+
registerReactRouterRouteExports as __rrr,
|
|
785
|
+
scheduleReactRouterRouteUpdate as __rru,
|
|
786
|
+
} from "virtual/react-router/hmr-runtime";
|
|
787
|
+
|
|
788
|
+
const __rrid = ${JSON.stringify(routeId)};
|
|
789
|
+
const __rrf = ${flags};
|
|
790
|
+
const __rrg = () => __rrm;
|
|
791
|
+
const __rru0 = () => {
|
|
792
|
+
__rrr(__rrid, __rrm);
|
|
793
|
+
__rru(__rrid, __rrf, __rrg);
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
__rrr(__rrid, __rrm);
|
|
797
|
+
|
|
798
|
+
if (import.meta.webpackHot) {
|
|
799
|
+
const __rrh = import.meta.webpackHot;
|
|
800
|
+
__rrh.accept(${acceptTargetJson}, __rru0);
|
|
801
|
+
__rrh.accept();
|
|
802
|
+
__rrh.dispose(data => { data.__rr = true; });
|
|
803
|
+
if (__rrh.data && __rrh.data.__rr) __rru0();
|
|
804
|
+
}
|
|
805
|
+
`;
|
|
806
|
+
})({
|
|
807
|
+
routeId,
|
|
808
|
+
target,
|
|
809
|
+
acceptTarget: `./${basename(resourcePath)}?react-router-route`,
|
|
810
|
+
flags: (exports = new Set(exportNames), flags = 0, HMR_PATCHABLE_ROUTE_FLAGS.forEach((flag, index)=>{
|
|
811
|
+
exports.has(HMR_FLAG_EXPORT_NAME[flag]) && (flags |= 1 << index);
|
|
812
|
+
}), flags)
|
|
813
|
+
});
|
|
766
814
|
})({
|
|
767
815
|
exportNames: routeChunkInfo?.exportNames ?? await getExportNames(code, resourcePath),
|
|
768
816
|
chunkedExports: routeChunkInfo?.chunkedExports ?? [],
|
|
769
817
|
isServer,
|
|
770
|
-
resourcePath
|
|
818
|
+
resourcePath,
|
|
819
|
+
routeId,
|
|
820
|
+
devHmr: devHmr && !isBuild
|
|
771
821
|
})
|
|
772
822
|
};
|
|
773
823
|
}, createRouteChunkArtifact = async ({ code, resource, resourcePath, isBuild, routeChunkCache, routeChunkConfig })=>{
|
|
@@ -817,7 +867,50 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
817
867
|
}, createClientOnlyStub = async (task)=>({
|
|
818
868
|
code: Array.from(await collectClientOnlyStubExportNames(task.code, task.resourcePath, task.resolveExportAllModule)).map((name)=>'default' === name ? 'export default undefined;' : `export const ${name} = undefined;`).join('\n'),
|
|
819
869
|
map: null
|
|
820
|
-
}),
|
|
870
|
+
}), callResolvesToComponent = (node)=>{
|
|
871
|
+
let args = node.arguments ?? [];
|
|
872
|
+
if (0 === args.length) return !1;
|
|
873
|
+
let callee = node.callee;
|
|
874
|
+
if (!callee || 'Import' === callee.type) return !1;
|
|
875
|
+
if ('Identifier' === callee.type) {
|
|
876
|
+
let calleeName = callee.name ?? '';
|
|
877
|
+
if (calleeName.startsWith('require') || calleeName.startsWith('import')) return !1;
|
|
878
|
+
} else if ('MemberExpression' !== callee.type) return !1;
|
|
879
|
+
var node1 = args[0];
|
|
880
|
+
switch(node1?.type){
|
|
881
|
+
case 'FunctionExpression':
|
|
882
|
+
return !0;
|
|
883
|
+
case 'ArrowFunctionExpression':
|
|
884
|
+
return node1.body?.type !== 'ArrowFunctionExpression';
|
|
885
|
+
case 'Identifier':
|
|
886
|
+
let name;
|
|
887
|
+
return !!node1.name && (name = node1.name, /^[A-Z]/.test(name));
|
|
888
|
+
case 'CallExpression':
|
|
889
|
+
return callResolvesToComponent(node1);
|
|
890
|
+
default:
|
|
891
|
+
return !1;
|
|
892
|
+
}
|
|
893
|
+
}, collectDeclaredComponentNames = (declaration, names)=>{
|
|
894
|
+
let name, name1;
|
|
895
|
+
if ('FunctionDeclaration' === declaration.type && declaration.id?.name && (name = declaration.id.name, /^[A-Z]/.test(name))) return void names.add(declaration.id.name);
|
|
896
|
+
if ('VariableDeclaration' !== declaration.type) return;
|
|
897
|
+
let declarators = declaration.declarations ?? [];
|
|
898
|
+
if (1 !== declarators.length) return;
|
|
899
|
+
let [declarator] = declarators;
|
|
900
|
+
declarator?.id?.type === 'Identifier' && declarator.id.name && (name1 = declarator.id.name, /^[A-Z]/.test(name1)) && declarator.init && ((init)=>{
|
|
901
|
+
switch(init.type){
|
|
902
|
+
case 'FunctionExpression':
|
|
903
|
+
case 'TaggedTemplateExpression':
|
|
904
|
+
return !0;
|
|
905
|
+
case 'ArrowFunctionExpression':
|
|
906
|
+
return init.body?.type !== 'ArrowFunctionExpression';
|
|
907
|
+
case 'CallExpression':
|
|
908
|
+
return callResolvesToComponent(init);
|
|
909
|
+
default:
|
|
910
|
+
return !1;
|
|
911
|
+
}
|
|
912
|
+
})(declarator.init) && names.add(declarator.id.name);
|
|
913
|
+
}, transformRouteModule = async (task)=>{
|
|
821
914
|
let code = task.code, defaultExportMatch = code.match(/\n\s{0,}([\w\d_]+)\sas default,?/);
|
|
822
915
|
defaultExportMatch && 'number' == typeof defaultExportMatch.index && (code = code.slice(0, defaultExportMatch.index) + code.slice(defaultExportMatch.index + defaultExportMatch[0].length) + `\nexport default ${defaultExportMatch[1]};`);
|
|
823
916
|
let ast = ((code, options = {})=>{
|
|
@@ -940,7 +1033,7 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
940
1033
|
return !(!declaration || currentlyLive.has(declaration)) && (previouslyLive.has(declaration) || declarationReferencesName(declaration, removedExportReferencedNames, declarationGraph, removedReferenceCache));
|
|
941
1034
|
}, program.body = program.body.filter((statement)=>'VariableDeclaration' === statement.type ? (statement.declarations = (statement.declarations ?? []).filter((declarator)=>!isRemovableDeadDeclaration(declarator)), statement.declarations.length > 0) : !isRemovableDeadDeclaration(statement))), exportsChanged;
|
|
942
1035
|
})(ast, SERVER_ONLY_ROUTE_EXPORTS, SERVER_ONLY_ROUTE_EXPORTS_SET);
|
|
943
|
-
|
|
1036
|
+
((ast)=>{
|
|
944
1037
|
let program = ast.program ?? ast, usedNames = new Set(), hocs = [], componentWrapperDeclarations = [];
|
|
945
1038
|
function getUid(name) {
|
|
946
1039
|
let uid = `_${name}`, index = 2;
|
|
@@ -1044,7 +1137,8 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
1044
1137
|
for (let statement of [
|
|
1045
1138
|
...program.body
|
|
1046
1139
|
])'ImportDeclaration' === statement.type && 0 !== (statement.specifiers ?? []).length && (statement.specifiers = (statement.specifiers ?? []).filter((specifier)=>'type' !== specifier.importKind && (!specifier.local?.name || referenced.has(specifier.local.name))), 0 === statement.specifiers.length && removeFromArray(program.body, statement));
|
|
1047
|
-
})(ast)
|
|
1140
|
+
})(ast);
|
|
1141
|
+
let result = ((ast, options = {})=>{
|
|
1048
1142
|
let result = 'program' in ast ? ast : {
|
|
1049
1143
|
program: ast,
|
|
1050
1144
|
lineStarts: []
|
|
@@ -1072,6 +1166,28 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
1072
1166
|
filename: task.resource,
|
|
1073
1167
|
sourceFileName: task.resourcePath
|
|
1074
1168
|
});
|
|
1169
|
+
if (task.devHmr && 'web' === task.environmentName && !task.isBuild) {
|
|
1170
|
+
let registrations, unregisteredComponents = ((program)=>{
|
|
1171
|
+
let declared = new Set(), registered = new Set();
|
|
1172
|
+
for (let statement of program.body ?? []){
|
|
1173
|
+
if ('ExportNamedDeclaration' === statement.type && statement.declaration) {
|
|
1174
|
+
collectDeclaredComponentNames(statement.declaration, declared);
|
|
1175
|
+
continue;
|
|
1176
|
+
}
|
|
1177
|
+
if ('ExpressionStatement' === statement.type && statement.expression?.type === 'CallExpression' && statement.expression.callee?.type === 'Identifier' && '$RefreshReg$' === statement.expression.callee.name) {
|
|
1178
|
+
let nameArgument = statement.expression.arguments?.[1];
|
|
1179
|
+
'string' == typeof nameArgument?.value && registered.add(nameArgument.value);
|
|
1180
|
+
continue;
|
|
1181
|
+
}
|
|
1182
|
+
collectDeclaredComponentNames(statement, declared);
|
|
1183
|
+
}
|
|
1184
|
+
return [
|
|
1185
|
+
...declared
|
|
1186
|
+
].filter((name)=>!registered.has(name));
|
|
1187
|
+
})(ast.program ?? ast);
|
|
1188
|
+
unregisteredComponents.length > 0 && (result.code += (registrations = unregisteredComponents.map((name)=>` if (typeof ${name} === 'function' || (typeof ${name} === 'object' && ${name} !== null)) $RefreshReg$(${name}, ${JSON.stringify(name)});`).join('\n'), `\nif (typeof $RefreshReg$ === 'function') {\n${registrations}\n}\n`));
|
|
1189
|
+
}
|
|
1190
|
+
return result;
|
|
1075
1191
|
}, executeRouteTransformTask = async (task, options)=>{
|
|
1076
1192
|
switch(task.kind){
|
|
1077
1193
|
case 'routeClientEntry':
|
|
@@ -1081,7 +1197,9 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
1081
1197
|
environmentName: task.environmentName,
|
|
1082
1198
|
isBuild: task.isBuild,
|
|
1083
1199
|
routeChunkCache: getRouteChunkCache(options),
|
|
1084
|
-
routeChunkConfig: task.routeChunkConfig
|
|
1200
|
+
routeChunkConfig: task.routeChunkConfig,
|
|
1201
|
+
routeId: task.routeId,
|
|
1202
|
+
devHmr: task.devHmr
|
|
1085
1203
|
});
|
|
1086
1204
|
case 'routeChunk':
|
|
1087
1205
|
return createRouteChunkArtifact({
|
|
@@ -1100,4 +1218,4 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
1100
1218
|
return transformRouteModule(task);
|
|
1101
1219
|
}
|
|
1102
1220
|
};
|
|
1103
|
-
export { BUILD_CLIENT_ROUTE_QUERY_STRING, CLIENT_EXPORTS, JS_EXTENSIONS, PLUGIN_NAME, SERVER_EXPORTS, buildManifestChunkValidity, combineURLs, createBundlerRouteExportResolver, createEmptyRouteChunkByExportName, createRouteId, detectRouteChunksIfEnabled, executeRouteTransformTask, findEntryFile, generateWithProps, getRouteChunkEntryName, getRouteChunkModuleId, getRouteModuleAnalysis, normalizeAssetPrefix, routeChunkExportNames, setBoundedCacheEntry, validateRouteChunks };
|
|
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, routeChunkExportNames, setBoundedCacheEntry, validateRouteChunks };
|
|
@@ -25,6 +25,7 @@ type RegisterBuildOutputTransformsOptions = {
|
|
|
25
25
|
ssr: boolean;
|
|
26
26
|
isSpaMode: boolean;
|
|
27
27
|
rootRoutePath: string;
|
|
28
|
+
isDevHmrEnabled?: () => boolean;
|
|
28
29
|
};
|
|
29
|
-
export declare const registerBuildOutputTransforms: ({ api, resolvedServerOutput, performanceProfiler, getLatestServerManifest, getLatestServerManifestByBundleId, routes, pluginOptions, getClientStats, appDirectory, getAssetPrefix, routeChunkOptions, routeTransformExecutor, routeByFilePath, routeChunkConfig, isBuild, splitRouteModules, ssr, isSpaMode, rootRoutePath, }: RegisterBuildOutputTransformsOptions) => void;
|
|
30
|
+
export declare const registerBuildOutputTransforms: ({ api, resolvedServerOutput, performanceProfiler, getLatestServerManifest, getLatestServerManifestByBundleId, routes, pluginOptions, getClientStats, appDirectory, getAssetPrefix, routeChunkOptions, routeTransformExecutor, routeByFilePath, routeChunkConfig, isBuild, splitRouteModules, ssr, isSpaMode, rootRoutePath, isDevHmrEnabled, }: RegisterBuildOutputTransformsOptions) => void;
|
|
30
31
|
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Rspack } from '@rsbuild/core';
|
|
2
|
+
export declare const DEV_HMR_RUNTIME_MODULE_ID = "virtual/react-router/hmr-runtime";
|
|
3
|
+
export declare const isRspackSwcReactRefreshEnabled: (rspackConfig: Rspack.Configuration) => boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the `react-refresh/runtime` module that
|
|
6
|
+
* `@rspack/plugin-react-refresh` injects into the web bundle. The resolution
|
|
7
|
+
* walks the same dependency chain the refresh plugin uses so the returned file
|
|
8
|
+
* is the exact runtime instance already present in the browser module graph.
|
|
9
|
+
* Returns `undefined` when React Fast Refresh is unavailable, in which case
|
|
10
|
+
* dev HMR falls back to full reloads.
|
|
11
|
+
*/
|
|
12
|
+
export declare const resolveReactRefreshRuntimePath: (rootPath: string) => string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The HDR revision module is a real file (not a virtual module) because it
|
|
15
|
+
* must wake the web compiler through the regular file watcher: the browser
|
|
16
|
+
* HMR runtime imports it, so bumping the revision produces a web hot update
|
|
17
|
+
* whenever server code changes, which the client answers by revalidating
|
|
18
|
+
* React Router loader data.
|
|
19
|
+
*/
|
|
20
|
+
export declare const DEV_HDR_REVISION_RELATIVE_PATH = ".react-router/hdr-revision.mjs";
|
|
21
|
+
export declare const getDevHdrRevisionFilePath: (rootPath: string) => string;
|
|
22
|
+
export type DevHdrRevisionSignal = {
|
|
23
|
+
/** Writes the initial revision module so the first compile can resolve it. */
|
|
24
|
+
ensure: () => void;
|
|
25
|
+
/** Increments the revision, signaling hot data revalidation to the client. */
|
|
26
|
+
bump: () => void;
|
|
27
|
+
};
|
|
28
|
+
export declare const createDevHdrRevisionSignal: ({ filePath, onError, }: {
|
|
29
|
+
filePath: string;
|
|
30
|
+
onError?: (error: Error) => void;
|
|
31
|
+
}) => DevHdrRevisionSignal;
|
|
32
|
+
/**
|
|
33
|
+
* Browser-side HMR runtime shared by all route client entries in development.
|
|
34
|
+
*
|
|
35
|
+
* This mirrors React Router's Vite HMR contract (see `refresh-utils.mjs` in
|
|
36
|
+
* `@react-router/dev`): route module updates are applied by patching
|
|
37
|
+
* `window.__reactRouterRouteModules` while preserving the previous component
|
|
38
|
+
* identities (React Fast Refresh swaps their implementations in place),
|
|
39
|
+
* recreating the client routes with revalidation opt-out, revalidating loader
|
|
40
|
+
* data, and finally performing a React refresh.
|
|
41
|
+
*/
|
|
42
|
+
export declare const generateDevHmrRuntimeModule: ({ reactRefreshRuntimePath, hdrRevisionFilePath, }: {
|
|
43
|
+
reactRefreshRuntimePath: string;
|
|
44
|
+
hdrRevisionFilePath: string;
|
|
45
|
+
}) => string;
|
|
@@ -9,6 +9,11 @@ type CreateControllerOptions = {
|
|
|
9
9
|
api: RsbuildPluginAPI;
|
|
10
10
|
isBuild: boolean;
|
|
11
11
|
buildPlan: ReactRouterDevBuildPlan;
|
|
12
|
+
/**
|
|
13
|
+
* Invoked after a development attempt commits a re-evaluated node build for
|
|
14
|
+
* changed server files. Used to signal hot data revalidation to the client.
|
|
15
|
+
*/
|
|
16
|
+
onNodeRebuildCommitted?: () => void;
|
|
12
17
|
};
|
|
13
|
-
export declare const createReactRouterDevRuntimeController: ({ api, isBuild, buildPlan, }: CreateControllerOptions) => ReactRouterDevRuntimeController;
|
|
18
|
+
export declare const createReactRouterDevRuntimeController: ({ api, isBuild, buildPlan, onNodeRebuildCommitted, }: CreateControllerOptions) => ReactRouterDevRuntimeController;
|
|
14
19
|
export {};
|