rsbuild-plugin-react-router 0.6.6 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -2
- package/dist/511.js +10 -3
- package/dist/environment-output.d.ts +16 -2
- package/dist/federation.d.ts +26 -0
- package/dist/index.cjs +160 -76
- package/dist/index.js +149 -70
- package/dist/manifest.d.ts +31 -0
- package/dist/mode-plan.d.ts +1 -1
- package/dist/plugin-utils.d.ts +19 -13
- package/dist/rsc-virtual-modules.d.ts +1 -3
- package/package.json +1 -1
- package/src/environment-output.ts +60 -2
- package/src/federation.ts +93 -14
- package/src/index.ts +75 -62
- package/src/manifest.ts +96 -17
- package/src/mode-plan.ts +6 -12
- package/src/modify-browser-manifest.ts +4 -4
- package/src/plugin-utils.ts +37 -23
- package/src/rsc-route-transforms.ts +8 -12
- package/src/rsc-virtual-modules.ts +59 -8
package/README.md
CHANGED
|
@@ -103,9 +103,17 @@ pluginReactRouter({
|
|
|
103
103
|
| `federation` | `false` | Enables the plugin's experimental Module Federation integration. |
|
|
104
104
|
|
|
105
105
|
When `federation` is enabled, configure the Module Federation plugin with
|
|
106
|
-
`experiments.asyncStartup: true
|
|
106
|
+
`experiments.asyncStartup: true` on every compiler (the plugin enforces it) and
|
|
107
|
+
keep shared dependencies non-eager. The dev server resolves async server build
|
|
107
108
|
exports automatically; production custom servers or adapters should resolve
|
|
108
|
-
async exports before passing the build to React Router's request handler
|
|
109
|
+
async exports before passing the build to React Router's request handler
|
|
110
|
+
(`resolveReactRouterServerBuild`). Give remote containers an explicit
|
|
111
|
+
`filename` (for example `static/js/remote.js`); every other browser chunk keeps
|
|
112
|
+
Rsbuild's content hash. Under the hood the plugin gives each container its own
|
|
113
|
+
runtime chunk (so importing a container does not start the app's own share
|
|
114
|
+
consumes), makes browser route-module entries async so their exports resolve
|
|
115
|
+
through the async startup, and keeps server code splitting async-only so the
|
|
116
|
+
`@module-federation/node` chunk loader can satisfy the server build's startup.
|
|
109
117
|
|
|
110
118
|
### React Router Config
|
|
111
119
|
|
|
@@ -343,6 +351,38 @@ If you configure `output.assetPrefix` in Rsbuild, the plugin uses that value
|
|
|
343
351
|
for the React Router browser manifest and server build `publicPath` so asset
|
|
344
352
|
URLs resolve correctly when serving from a CDN or sub-path.
|
|
345
353
|
|
|
354
|
+
The web environment's own `output.assetPrefix` is passed through to the browser
|
|
355
|
+
compiler untouched, so `environments.web.output.assetPrefix: 'auto'` lets the
|
|
356
|
+
browser runtime resolve async chunks and stylesheets relative to the loaded
|
|
357
|
+
script. The server build and browser manifest need an absolute prefix: they use
|
|
358
|
+
the web environment's prefix when it is usable and otherwise fall back to the
|
|
359
|
+
root `output.assetPrefix`. A common CDN setup is therefore:
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
export default defineConfig({
|
|
363
|
+
output: { assetPrefix: 'https://cdn.example.com/app/' }, // server-rendered URLs
|
|
364
|
+
environments: {
|
|
365
|
+
web: { output: { assetPrefix: 'auto' } }, // browser runtime resolves itself
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
The plugin does not set `output.filename`, `chunkFilename`, or `publicPath`
|
|
371
|
+
for the web environment. Production browser entries use Rsbuild's default
|
|
372
|
+
content-hashed filenames, and `output.filename`, `output.filenameHash`,
|
|
373
|
+
`output.distPath`, and `tools.rspack` output settings you configure govern
|
|
374
|
+
the emitted files and the manifest URLs that reference them.
|
|
375
|
+
|
|
376
|
+
Supported browser filename forms differ by mode:
|
|
377
|
+
|
|
378
|
+
- **Classic mode** accepts any scheme, including `.mjs`/`.cjs` and query-hash
|
|
379
|
+
names such as `[name].js?v=[contenthash:8]`; the browser manifest classifies
|
|
380
|
+
emitted assets by pathname and keeps the full reference.
|
|
381
|
+
- **RSC mode** requires every browser JavaScript asset to be named `*.js`
|
|
382
|
+
(hashes are fine, e.g. `[contenthash:8]-[name].js`): rspack's RSC manifest
|
|
383
|
+
only records `.js` files, so the build fails with a clear error for query
|
|
384
|
+
hashes or other extensions.
|
|
385
|
+
|
|
346
386
|
## Custom Server Setup
|
|
347
387
|
|
|
348
388
|
The plugin supports two ways to handle server-side rendering:
|
package/dist/511.js
CHANGED
|
@@ -375,9 +375,16 @@ function combineURLs(baseURL, relativeURL) {
|
|
|
375
375
|
function normalizeAssetPrefix(assetPrefix) {
|
|
376
376
|
return assetPrefix && 'auto' !== assetPrefix ? assetPrefix.endsWith('/') ? assetPrefix : `${assetPrefix}/` : '/';
|
|
377
377
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
378
|
+
let asString = (value)=>'string' == typeof value ? value : void 0, pickConfiguredAssetPrefix = ({ dev, output }, isBuild)=>isBuild ? asString(output?.assetPrefix) : asString(dev?.assetPrefix) ?? asString(output?.assetPrefix);
|
|
379
|
+
function resolveEffectiveAssetPrefix(config, ...fallbacks) {
|
|
380
|
+
for (let candidate of [
|
|
381
|
+
config,
|
|
382
|
+
...fallbacks
|
|
383
|
+
]){
|
|
384
|
+
let prefix = pickConfiguredAssetPrefix(candidate, config.isBuild);
|
|
385
|
+
if (prefix && 'auto' !== prefix) return normalizeAssetPrefix(prefix);
|
|
386
|
+
}
|
|
387
|
+
return '/';
|
|
381
388
|
}
|
|
382
389
|
function createRouteId(file) {
|
|
383
390
|
return normalize(file.replace(/\.[^/.]+$/, ''));
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import type { RsbuildPluginAPI } from '@rsbuild/core';
|
|
2
|
-
|
|
1
|
+
import type { RsbuildPluginAPI, Rspack } from '@rsbuild/core';
|
|
2
|
+
/**
|
|
3
|
+
* Rspack `output` policy for the web and node environments, in two tiers:
|
|
4
|
+
*
|
|
5
|
+
* 1. Overridable defaults, registered through `modifyRspackConfig`. Rsbuild
|
|
6
|
+
* runs the user's `tools.rspack` (object or function form) after this hook,
|
|
7
|
+
* so user output settings such as `chunkFilename` take precedence
|
|
8
|
+
* (#129, #130). Neither `filename` nor `publicPath` is set here: Rsbuild
|
|
9
|
+
* derives them from `output.filename`/`output.filenameHash`/`output.distPath`
|
|
10
|
+
* and the environment's `output.assetPrefix`, which keeps `'auto'` intact.
|
|
11
|
+
* 2. Enforced invariants, registered through a `tools.rspack` function that
|
|
12
|
+
* runs after the user's own `tools.rspack`: the server library type must
|
|
13
|
+
* match the server module format, and federation builds need async startup.
|
|
14
|
+
*/
|
|
15
|
+
export declare const registerReactRouterEnvironmentOutput: ({ api, federation, resolvedServerOutput, webOutput, }: {
|
|
3
16
|
api: RsbuildPluginAPI;
|
|
4
17
|
federation: boolean | undefined;
|
|
5
18
|
resolvedServerOutput: "commonjs" | "module";
|
|
19
|
+
webOutput: NonNullable<Rspack.Configuration["output"]>;
|
|
6
20
|
}) => void;
|
package/dist/federation.d.ts
CHANGED
|
@@ -1,2 +1,28 @@
|
|
|
1
1
|
import type { Rspack } from '@rsbuild/core';
|
|
2
|
+
/**
|
|
3
|
+
* The Module Federation container name(s) configured on this compiler, i.e.
|
|
4
|
+
* the entry names of the remote containers it emits.
|
|
5
|
+
*/
|
|
6
|
+
export declare const getFederationContainerNames: (rspackConfig: Rspack.Configuration | undefined) => string[];
|
|
7
|
+
/**
|
|
8
|
+
* Classic mode shares one runtime chunk across every browser entry so route
|
|
9
|
+
* module entries share a module registry. A federation container must not
|
|
10
|
+
* share it: importing the container would run the app entries' async startup
|
|
11
|
+
* (share-scope consumes) before the host has initialized the share scope,
|
|
12
|
+
* yielding duplicate singletons (a second React). Give containers their own
|
|
13
|
+
* runtime chunk.
|
|
14
|
+
*/
|
|
15
|
+
export declare const isolateFederationContainerRuntime: (rspackConfig: Rspack.Configuration | undefined) => void;
|
|
2
16
|
export declare const ensureFederationAsyncStartup: (rspackConfig: Rspack.Configuration | undefined) => void;
|
|
17
|
+
/**
|
|
18
|
+
* `@module-federation/node` replaces Rspack's `readFileVm` chunk loader with one
|
|
19
|
+
* that tracks loaded chunks privately, so initial chunks split off a
|
|
20
|
+
* multi-entry server build never satisfy Rspack's startup gate
|
|
21
|
+
* (`__webpack_require__.O`) and the async startup resolves to `undefined`
|
|
22
|
+
* instead of the server build's exports. Keep server code splitting to async
|
|
23
|
+
* chunks only. Runs at the final `tools.rspack` boundary so a user
|
|
24
|
+
* `optimization.splitChunks` override or a preset whose cache group selects
|
|
25
|
+
* `chunks: 'all'` (e.g. Rsbuild's `single-vendor`, `enforce: true`) cannot
|
|
26
|
+
* reintroduce initial chunk dependencies. A disabled `splitChunks` is kept.
|
|
27
|
+
*/
|
|
28
|
+
export declare const enforceAsyncOnlyServerSplitChunks: (rspackConfig: Rspack.Configuration | undefined) => void;
|
package/dist/index.cjs
CHANGED
|
@@ -543,9 +543,16 @@ function combineURLs(baseURL, relativeURL) {
|
|
|
543
543
|
function normalizeAssetPrefix(assetPrefix) {
|
|
544
544
|
return assetPrefix && 'auto' !== assetPrefix ? assetPrefix.endsWith('/') ? assetPrefix : `${assetPrefix}/` : '/';
|
|
545
545
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
546
|
+
const asString = (value)=>'string' == typeof value ? value : void 0, pickConfiguredAssetPrefix = ({ dev, output }, isBuild)=>isBuild ? asString(output?.assetPrefix) : asString(dev?.assetPrefix) ?? asString(output?.assetPrefix);
|
|
547
|
+
function resolveEffectiveAssetPrefix(config, ...fallbacks) {
|
|
548
|
+
for (let candidate of [
|
|
549
|
+
config,
|
|
550
|
+
...fallbacks
|
|
551
|
+
]){
|
|
552
|
+
let prefix = pickConfiguredAssetPrefix(candidate, config.isBuild);
|
|
553
|
+
if (prefix && 'auto' !== prefix) return normalizeAssetPrefix(prefix);
|
|
554
|
+
}
|
|
555
|
+
return '/';
|
|
549
556
|
}
|
|
550
557
|
function createRouteId(file) {
|
|
551
558
|
return (0, external_pathe_namespaceObject.normalize)(file.replace(/\.[^/.]+$/, ''));
|
|
@@ -610,20 +617,53 @@ const resolveEntryWithTemplate = ({ appDirectory, entryName, templateName, templ
|
|
|
610
617
|
hasServerApp,
|
|
611
618
|
serverAppPath
|
|
612
619
|
};
|
|
620
|
+
}, getModuleFederationOptions = (plugin)=>{
|
|
621
|
+
if (plugin && 'object' == typeof plugin && ('ModuleFederationPlugin' === plugin.name || 'RspackModuleFederationPlugin' === plugin.name)) return plugin._options ?? plugin.options;
|
|
622
|
+
}, getFederationContainerNames = (rspackConfig)=>(rspackConfig?.plugins ?? []).map(getModuleFederationOptions).map((options)=>options?.name).filter((name)=>'string' == typeof name), isolateFederationContainerRuntime = (rspackConfig)=>{
|
|
623
|
+
let containers = new Set(getFederationContainerNames(rspackConfig));
|
|
624
|
+
if (!rspackConfig || 0 === containers.size) return;
|
|
625
|
+
let current = rspackConfig.optimization?.runtimeChunk, appRuntimeName = 'object' == typeof current && 'string' == typeof current?.name ? current.name : 'runtime';
|
|
626
|
+
rspackConfig.optimization = {
|
|
627
|
+
...rspackConfig.optimization,
|
|
628
|
+
runtimeChunk: {
|
|
629
|
+
name: (entrypoint)=>containers.has(entrypoint.name) ? `runtime-${entrypoint.name}` : appRuntimeName
|
|
630
|
+
}
|
|
631
|
+
};
|
|
613
632
|
}, ensureFederationAsyncStartup = (rspackConfig)=>{
|
|
614
633
|
if (rspackConfig?.plugins?.length) for (let plugin of rspackConfig.plugins){
|
|
615
|
-
|
|
616
|
-
let pluginOptions = plugin._options ?? plugin.options;
|
|
634
|
+
let pluginOptions = getModuleFederationOptions(plugin);
|
|
617
635
|
pluginOptions && (pluginOptions.experiments = {
|
|
618
636
|
...pluginOptions.experiments,
|
|
619
637
|
asyncStartup: !0
|
|
620
638
|
});
|
|
621
639
|
}
|
|
622
|
-
},
|
|
623
|
-
|
|
640
|
+
}, enforceAsyncOnlyServerSplitChunks = (rspackConfig)=>{
|
|
641
|
+
let splitChunks = rspackConfig?.optimization?.splitChunks;
|
|
642
|
+
if (splitChunks) for (let group of (splitChunks.chunks = 'async', Object.values(splitChunks.cacheGroups ?? {})))group && 'object' == typeof group && 'chunks' in group && (group.chunks = 'async');
|
|
643
|
+
}, registerReactRouterEnvironmentOutput = ({ api, federation, resolvedServerOutput, webOutput })=>{
|
|
644
|
+
let nodeChunkLoading = 'module' === resolvedServerOutput ? 'import' : federation ? 'async-node' : 'require';
|
|
645
|
+
api.modifyRspackConfig((rspackConfig, { environment, mergeConfig })=>'web' === environment.name ? mergeConfig(rspackConfig, {
|
|
646
|
+
output: {
|
|
647
|
+
...webOutput,
|
|
648
|
+
...federation ? {
|
|
649
|
+
chunkLoading: 'import'
|
|
650
|
+
} : {}
|
|
651
|
+
}
|
|
652
|
+
}) : 'node' === environment.name ? mergeConfig(rspackConfig, {
|
|
653
|
+
output: {
|
|
654
|
+
chunkFormat: resolvedServerOutput,
|
|
655
|
+
chunkLoading: nodeChunkLoading,
|
|
656
|
+
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
657
|
+
devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
|
|
658
|
+
workerChunkLoading: nodeChunkLoading,
|
|
659
|
+
wasmLoading: 'fetch',
|
|
660
|
+
module: 'module' === resolvedServerOutput,
|
|
661
|
+
chunkFilename: 'static/js/async/[name].js'
|
|
662
|
+
}
|
|
663
|
+
}) : rspackConfig), api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
|
|
624
664
|
tools: {
|
|
625
665
|
rspack: (rspackConfig)=>{
|
|
626
|
-
if (federation && ensureFederationAsyncStartup(rspackConfig), 'node' === name) {
|
|
666
|
+
if (federation && (ensureFederationAsyncStartup(rspackConfig), 'web' === name ? isolateFederationContainerRuntime(rspackConfig) : enforceAsyncOnlyServerSplitChunks(rspackConfig)), 'node' === name) {
|
|
627
667
|
let output = rspackConfig.output;
|
|
628
668
|
if (output) {
|
|
629
669
|
let library = output.library, libraryOptions = library && 'object' == typeof library && !Array.isArray(library) ? library : {};
|
|
@@ -1444,7 +1484,7 @@ const getCurrentVersion = ()=>moduleVersion, setCurrentVersion = (version)=>{
|
|
|
1444
1484
|
}), findLast = null, zip = null, Iterable_zipWith = null, intersperse = null, Iterable_containsWith = (isEquivalent)=>dual(2, (self, a)=>{
|
|
1445
1485
|
for (let i of self)if (isEquivalent(a, i)) return !0;
|
|
1446
1486
|
return !1;
|
|
1447
|
-
}), Iterable_equivalence = null, Iterable_contains = null, chunksOf = null, groupWith = null,
|
|
1487
|
+
}), Iterable_equivalence = null, Iterable_contains = null, chunksOf = null, groupWith = null, Iterable_group = null, groupBy = null, constEmpty = {
|
|
1448
1488
|
[Symbol.iterator]: ()=>constEmptyIterator
|
|
1449
1489
|
}, constEmptyIterator = {
|
|
1450
1490
|
next: ()=>({
|
|
@@ -11790,12 +11830,23 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
|
|
|
11790
11830
|
routeModuleAnalysis
|
|
11791
11831
|
} : {}
|
|
11792
11832
|
};
|
|
11793
|
-
},
|
|
11794
|
-
let
|
|
11795
|
-
return
|
|
11796
|
-
|
|
11797
|
-
|
|
11798
|
-
|
|
11833
|
+
}, isManifestJsAsset = (asset)=>/(?<!\.hot-update)\.[cm]?js(?:\?.*)?$/.test(asset), isManifestCssAsset = (asset)=>/\.css(?:\?.*)?$/.test(asset), hasSome = (iterable)=>{
|
|
11834
|
+
for (let _ of iterable)return !0;
|
|
11835
|
+
return !1;
|
|
11836
|
+
}, collectUnsupportedRscScriptAssets = (compilation)=>{
|
|
11837
|
+
let unsupported = new Set();
|
|
11838
|
+
for (let chunk of compilation.chunks){
|
|
11839
|
+
if (!(chunk.contentHash?.javascript !== void 0 || hasSome(compilation.chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript")))) continue;
|
|
11840
|
+
let pathData = {
|
|
11841
|
+
chunk,
|
|
11842
|
+
contentHashType: "javascript"
|
|
11843
|
+
}, template = chunk.canBeInitial() ? compilation.outputOptions.filename : compilation.outputOptions.chunkFilename, resolvedTemplate = 'function' == typeof template ? template(pathData) : template;
|
|
11844
|
+
if ('string' != typeof resolvedTemplate) continue;
|
|
11845
|
+
let file = compilation.getPath(resolvedTemplate, pathData);
|
|
11846
|
+
file.endsWith('.js') || unsupported.add(file);
|
|
11847
|
+
}
|
|
11848
|
+
return [
|
|
11849
|
+
...unsupported
|
|
11799
11850
|
];
|
|
11800
11851
|
}, collectManifestFilesByName = (items, names, getFiles)=>{
|
|
11801
11852
|
let filesByName = {};
|
|
@@ -11813,14 +11864,14 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
|
|
|
11813
11864
|
return filesByName;
|
|
11814
11865
|
}, createReactRouterManifestStats = (compilation, chunkNames)=>{
|
|
11815
11866
|
if (!compilation) return;
|
|
11816
|
-
let assetsByChunkName = collectManifestFilesByName(compilation.namedChunks, chunkNames, (
|
|
11867
|
+
let assetsByChunkName = collectManifestFilesByName(compilation.namedChunks, chunkNames, (_chunkName, chunk)=>Array.from(chunk.files ?? [])), entrypointFilesByName = compilation.entrypoints ? collectManifestFilesByName(compilation.entrypoints, chunkNames, (_name, entrypoint)=>Array.from(entrypoint.getFiles?.() ?? [])) : {};
|
|
11817
11868
|
return Object.keys(entrypointFilesByName).length > 0 ? {
|
|
11818
11869
|
assetsByChunkName,
|
|
11819
11870
|
entrypointFilesByName
|
|
11820
11871
|
} : {
|
|
11821
11872
|
assetsByChunkName
|
|
11822
11873
|
};
|
|
11823
|
-
}, DEFAULT_MANIFEST_DIR =
|
|
11874
|
+
}, DEFAULT_MANIFEST_DIR = 'static/js', CSS_IMPORT_RE = /\.(?:css|less|sass|scss)(?:\?[^'"`]+)?['"`]/, createChunkAssetResolver = (clientStats, includeEntrypointJs)=>{
|
|
11824
11875
|
let chunkAssetsByName = new Map();
|
|
11825
11876
|
return (chunkName)=>{
|
|
11826
11877
|
let cached = chunkAssetsByName.get(chunkName);
|
|
@@ -11829,16 +11880,16 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
|
|
|
11829
11880
|
if (!assets) {
|
|
11830
11881
|
let result = {
|
|
11831
11882
|
js: [
|
|
11832
|
-
`${
|
|
11883
|
+
`${DEFAULT_MANIFEST_DIR}/${chunkName}.js`
|
|
11833
11884
|
],
|
|
11834
11885
|
css: []
|
|
11835
11886
|
};
|
|
11836
11887
|
return chunkAssetsByName.set(chunkName, result), result;
|
|
11837
11888
|
}
|
|
11838
11889
|
let cssAssets = new Set(), jsAssets = new Set();
|
|
11839
|
-
for (let asset of assets)asset
|
|
11840
|
-
for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])asset
|
|
11841
|
-
0 === jsAssets.size
|
|
11890
|
+
for (let asset of assets)isManifestCssAsset(asset) ? cssAssets.add(asset) : isManifestJsAsset(asset) && jsAssets.add(asset);
|
|
11891
|
+
for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])isManifestCssAsset(asset) ? cssAssets.add(asset) : includeEntrypointJs && isManifestJsAsset(asset) && jsAssets.add(asset);
|
|
11892
|
+
if (0 === jsAssets.size) throw Error(`[react-router] Chunk "${chunkName}" emitted no JavaScript asset the browser manifest can reference (files: ${assets.join(', ') || 'none'}). Check the web \`output.filename.js\` scheme.`);
|
|
11842
11893
|
let result = {
|
|
11843
11894
|
js: [
|
|
11844
11895
|
...jsAssets
|
|
@@ -11851,7 +11902,7 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
|
|
|
11851
11902
|
};
|
|
11852
11903
|
}, analyzeRouteForManifestEffect = ({ discoveredCssAssets, isBuild, routeChunkCache, routeChunkConfig, routeEntryName, routeFilePath, route, routeModuleAnalysis })=>tryPluginPromise(async ()=>{
|
|
11853
11904
|
let { code, exports: exportNames } = await routeModuleAnalysis?.(routeFilePath, route) ?? await getRouteModuleAnalysis(routeFilePath), cssAssets = !isBuild && 0 === discoveredCssAssets.length && CSS_IMPORT_RE.test(code) ? [
|
|
11854
|
-
`${
|
|
11905
|
+
`${DEFAULT_MANIFEST_DIR.replace('/js', '/css')}/${routeEntryName}.css`
|
|
11855
11906
|
] : discoveredCssAssets, chunkInfo = isBuild && routeChunkConfig ? await detectRouteChunksIfEnabled(routeChunkCache, routeChunkConfig, routeFilePath, code) : null;
|
|
11856
11907
|
return {
|
|
11857
11908
|
cssAssets,
|
|
@@ -11865,9 +11916,9 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
|
|
|
11865
11916
|
routeModuleExports: [],
|
|
11866
11917
|
hasRouteChunkByExportName: null
|
|
11867
11918
|
})))), getManifestDirFromEntryAsset = (entryModulePath)=>{
|
|
11868
|
-
if (!entryModulePath) return
|
|
11919
|
+
if (!entryModulePath) return DEFAULT_MANIFEST_DIR;
|
|
11869
11920
|
let dir = (0, external_pathe_namespaceObject.dirname)(entryModulePath);
|
|
11870
|
-
return '.' === dir ?
|
|
11921
|
+
return '.' === dir ? DEFAULT_MANIFEST_DIR : dir;
|
|
11871
11922
|
}, getReactRouterManifestPath = ({ version, isBuild, entryModulePath })=>{
|
|
11872
11923
|
if (!isBuild) return 'static/js/virtual/react-router/browser-manifest.js';
|
|
11873
11924
|
let dir = getManifestDirFromEntryAsset(entryModulePath);
|
|
@@ -12418,13 +12469,13 @@ const redirectStatusCodes = new Set([
|
|
|
12418
12469
|
}), external_jsesc_namespaceObject = require("jsesc");
|
|
12419
12470
|
var external_jsesc_default = __webpack_require__.n(external_jsesc_namespaceObject);
|
|
12420
12471
|
const BROWSER_MANIFEST_ASSET = 'static/js/virtual/react-router/browser-manifest.js', ABSOLUTE_URL_RE = /^[a-zA-Z][a-zA-Z\d+\-.]*:/, toManifestAssetUrl = (assetPrefix, assetName)=>ABSOLUTE_URL_RE.test(assetName) || assetName.startsWith('//') || assetName.startsWith('/') ? assetName : combineURLs(assetPrefix, assetName), addIntegrity = (sri, assetPrefix, assetName, integrity)=>{
|
|
12421
|
-
'string' == typeof assetName && assetName
|
|
12472
|
+
'string' == typeof assetName && isManifestJsAsset(assetName) && 'string' == typeof integrity && (sri[toManifestAssetUrl(assetPrefix, assetName)] = integrity);
|
|
12422
12473
|
}, computeSubresourceIntegrity = (source)=>{
|
|
12423
12474
|
if (source) return `sha384-${(0, external_node_crypto_namespaceObject.createHash)('sha384').update(source.source()).digest('base64')}`;
|
|
12424
12475
|
}, collectSubresourceIntegrity = (stats, compilation, assetPrefix = '/')=>{
|
|
12425
12476
|
let sri = {};
|
|
12426
12477
|
for (let asset of stats?.assets ?? [])addIntegrity(sri, assetPrefix, asset.name, asset.integrity);
|
|
12427
|
-
if ('function' == typeof compilation?.getAssets) for (let asset of compilation.getAssets())asset.name
|
|
12478
|
+
if ('function' == typeof compilation?.getAssets) for (let asset of compilation.getAssets())isManifestJsAsset(asset.name) && addIntegrity(sri, assetPrefix, asset.name, computeSubresourceIntegrity(asset.source) ?? asset.info?.integrity);
|
|
12428
12479
|
return Object.keys(sri).length > 0 ? sri : void 0;
|
|
12429
12480
|
};
|
|
12430
12481
|
function registerModifyBrowserManifestAssets(api, routes, pluginOptions, appDirectory, assetPrefix = '/', routeChunkOptions, options) {
|
|
@@ -12444,7 +12495,7 @@ function registerModifyBrowserManifestAssets(api, routes, pluginOptions, appDire
|
|
|
12444
12495
|
compilation.updateAsset(BROWSER_MANIFEST_ASSET, new sources.RawSource(newSource));
|
|
12445
12496
|
}
|
|
12446
12497
|
if (isBuild) {
|
|
12447
|
-
let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter(
|
|
12498
|
+
let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter(isManifestJsAsset) || [], manifestPath = getReactRouterManifestPath({
|
|
12448
12499
|
version: manifest.version,
|
|
12449
12500
|
isBuild: !0,
|
|
12450
12501
|
entryModulePath: entryJsAssets[0]
|
|
@@ -14418,12 +14469,14 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
|
|
|
14418
14469
|
}, createServerRouteEntry = async (options)=>{
|
|
14419
14470
|
let ast, plan = await createRscRouteExportPlan(options);
|
|
14420
14471
|
validateRscRouteExportPlan(plan, options);
|
|
14421
|
-
let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1,
|
|
14472
|
+
let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1, pushStylesheetLinks = (entryCssFilesExpression)=>{
|
|
14473
|
+
lines.push(` ...(${entryCssFilesExpression} ?? []).map(href =>`), lines.push(' React.createElement("link", { key: href, rel: "stylesheet", href: href, precedence: "default" })),');
|
|
14474
|
+
}, streamsClientRouteCss = !plan.exportNames.some(isServerComponentExport) && plan.exportNames.includes('default') && programHasSideEffectStyleImports((ast = yuku_parse(options.code, {
|
|
14422
14475
|
sourceType: 'module'
|
|
14423
14476
|
})).program ?? ast);
|
|
14424
14477
|
for (let exportName of plan.exportNames){
|
|
14425
14478
|
if (streamsClientRouteCss && 'default' === exportName) {
|
|
14426
|
-
needsReactImport = !0, needsStyleEntryImport = !0, lines.push(`import RscClientRouteDefault___ from ${JSON.stringify(plan.clientTargetFor('default'))};`), lines.push('export default function RscClientRouteWithStyles___(props) {'), lines.push(' return React.createElement(React.Fragment, null,'),
|
|
14479
|
+
needsReactImport = !0, needsStyleEntryImport = !0, lines.push(`import RscClientRouteDefault___ from ${JSON.stringify(plan.clientTargetFor('default'))};`), lines.push('export default function RscClientRouteWithStyles___(props) {'), lines.push(' return React.createElement(React.Fragment, null,'), pushStylesheetLinks(`${RSC_ROUTE_STYLE_ENTRY_EXPORT}.entryCssFiles`), lines.push(' React.createElement(RscClientRouteDefault___, props),'), lines.push(' );'), lines.push('}');
|
|
14427
14480
|
continue;
|
|
14428
14481
|
}
|
|
14429
14482
|
if (isClientRouteExport(exportName)) {
|
|
@@ -14431,7 +14484,7 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
|
|
|
14431
14484
|
continue;
|
|
14432
14485
|
}
|
|
14433
14486
|
if (isServerComponentExport(exportName)) {
|
|
14434
|
-
needsReactImport = !0, needsEnsureHmrImport = !0, lines.push(`import { ${exportName} as ${exportName}WithoutClientChunk } from ${JSON.stringify(plan.serverTarget)};`), lines.push(`export function ${exportName}(props) {`), lines.push(' return React.createElement(React.Fragment, null,'),
|
|
14487
|
+
needsReactImport = !0, needsEnsureHmrImport = !0, lines.push(`import { ${exportName} as ${exportName}WithoutClientChunk } from ${JSON.stringify(plan.serverTarget)};`), lines.push(`export function ${exportName}(props) {`), lines.push(' return React.createElement(React.Fragment, null,'), pushStylesheetLinks(`${exportName}WithoutClientChunk.entryCssFiles`), lines.push(' React.createElement(EnsureClientRouteModuleForHMR___, null),'), lines.push(` React.createElement(${exportName}WithoutClientChunk, props),`), lines.push(' );'), lines.push('}');
|
|
14435
14488
|
continue;
|
|
14436
14489
|
}
|
|
14437
14490
|
lines.push(createReexport(exportName, plan.serverTarget));
|
|
@@ -14689,6 +14742,7 @@ export {
|
|
|
14689
14742
|
'allowed-action-origins',
|
|
14690
14743
|
'client-version',
|
|
14691
14744
|
'react-router-serve-config',
|
|
14745
|
+
'manifest-prefix',
|
|
14692
14746
|
"bootstrap-scripts",
|
|
14693
14747
|
'server-manifest'
|
|
14694
14748
|
], createReactRouterRscResolveAliases = (rootPath, options = {})=>({
|
|
@@ -14710,8 +14764,8 @@ export {
|
|
|
14710
14764
|
];
|
|
14711
14765
|
})),
|
|
14712
14766
|
'react-router/internal/react-server-client': (0, external_pathe_namespaceObject.resolve)(rootPath, getVirtualModuleFilePath('virtual/react-router/rsc-internal-client'))
|
|
14713
|
-
}), createReactRouterRscVirtualModules = ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild,
|
|
14714
|
-
let rscAssetsBuildDirectory = (0, external_pathe_namespaceObject.relative)((0, external_pathe_namespaceObject.resolve)(buildDirectory, 'server'), outputClientPath),
|
|
14767
|
+
}), createReactRouterRscVirtualModules = ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, outputClientPath, publicPath, routeDiscovery, routes, ssr })=>{
|
|
14768
|
+
let rscAssetsBuildDirectory = (0, external_pathe_namespaceObject.relative)((0, external_pathe_namespaceObject.resolve)(buildDirectory, 'server'), outputClientPath), serverPublicPath = normalizeAssetPrefix(publicPath);
|
|
14715
14769
|
return {
|
|
14716
14770
|
'virtual/react-router/unstable_rsc/routes': createRscRouteConfig({
|
|
14717
14771
|
appDirectory,
|
|
@@ -14733,9 +14787,41 @@ export {
|
|
|
14733
14787
|
assetsBuildDirectory: rscAssetsBuildDirectory,
|
|
14734
14788
|
publicPath
|
|
14735
14789
|
}),
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14790
|
+
'virtual/react-router/unstable_rsc/manifest-prefix': `const manifest = __webpack_require__.rscM;
|
|
14791
|
+
const serverPrefix = ${JSON.stringify(serverPublicPath)};
|
|
14792
|
+
const appliedPrefix = manifest?.moduleLoading?.prefix;
|
|
14793
|
+
// An empty applied prefix (web \`assetPrefix: ''\`) yields relative references
|
|
14794
|
+
// such as "static/js/index.js"; those are rebased too, while absolute and
|
|
14795
|
+
// protocol-relative URLs are left alone.
|
|
14796
|
+
const isAbsoluteUrl = url => /^(?:[a-z][a-z\\d+.-]*:|\\/\\/|\\/)/i.test(url);
|
|
14797
|
+
if (typeof appliedPrefix === "string" && appliedPrefix !== serverPrefix) {
|
|
14798
|
+
const rewrite = url =>
|
|
14799
|
+
typeof url !== "string"
|
|
14800
|
+
? url
|
|
14801
|
+
: appliedPrefix !== "" && url.startsWith(appliedPrefix)
|
|
14802
|
+
? serverPrefix + url.slice(appliedPrefix.length)
|
|
14803
|
+
: appliedPrefix === "" && !isAbsoluteUrl(url)
|
|
14804
|
+
? serverPrefix + url
|
|
14805
|
+
: url;
|
|
14806
|
+
const rewriteAll = list => {
|
|
14807
|
+
if (Array.isArray(list)) for (let i = 0; i < list.length; i++) list[i] = rewrite(list[i]);
|
|
14808
|
+
};
|
|
14809
|
+
manifest.moduleLoading.prefix = serverPrefix;
|
|
14810
|
+
rewriteAll(manifest.entryJsFiles);
|
|
14811
|
+
for (const files of Object.values(manifest.entryCssFiles ?? {})) rewriteAll(files);
|
|
14812
|
+
for (const reference of Object.values(manifest.clientManifest ?? {})) rewriteAll(reference.cssFiles);
|
|
14813
|
+
}
|
|
14814
|
+
export const rscManifest = manifest;
|
|
14815
|
+
`,
|
|
14816
|
+
"virtual/react-router/unstable_rsc/bootstrap-scripts": `import { rscManifest } from "virtual/react-router/unstable_rsc/manifest-prefix";
|
|
14817
|
+
const entryJsFiles = rscManifest?.entryJsFiles;
|
|
14818
|
+
if (!entryJsFiles?.length) {
|
|
14819
|
+
throw new Error(
|
|
14820
|
+
"[rsbuild-plugin-react-router] The rspack RSC manifest lists no browser entry script (entryJsFiles is empty), so the server cannot render bootstrap scripts. Rspack only records entry files whose name ends in \\".js\\"; web output.filename.js values with a query (for example \\"[name].js?v=[contenthash:8]\\") or another extension are not supported in RSC mode."
|
|
14821
|
+
);
|
|
14822
|
+
}
|
|
14823
|
+
export default entryJsFiles;
|
|
14824
|
+
`,
|
|
14739
14825
|
'virtual/react-router/unstable_rsc/server-manifest': `export default function getServerManifest() {
|
|
14740
14826
|
return __webpack_require__.rscM?.serverManifest;
|
|
14741
14827
|
}
|
|
@@ -15591,13 +15677,12 @@ export {
|
|
|
15591
15677
|
layer: RSC_LAYERS.rsc
|
|
15592
15678
|
}
|
|
15593
15679
|
},
|
|
15594
|
-
createVirtualModules: (publicPath
|
|
15680
|
+
createVirtualModules: (publicPath)=>createReactRouterRscVirtualModules({
|
|
15595
15681
|
allowedActionOrigins: allowedActionOriginsForBuild,
|
|
15596
15682
|
appDirectory,
|
|
15597
15683
|
basename,
|
|
15598
15684
|
buildDirectory,
|
|
15599
15685
|
isBuild,
|
|
15600
|
-
jsDistPath,
|
|
15601
15686
|
outputClientPath,
|
|
15602
15687
|
publicPath,
|
|
15603
15688
|
routeDiscovery,
|
|
@@ -15691,7 +15776,7 @@ export {
|
|
|
15691
15776
|
defaultEntryName,
|
|
15692
15777
|
serverBundleEntries: artifacts.serverBundleEntries
|
|
15693
15778
|
}),
|
|
15694
|
-
createVirtualModules: (publicPath
|
|
15779
|
+
createVirtualModules: (publicPath)=>createClassicVirtualModules({
|
|
15695
15780
|
allowedActionOrigins: allowedActionOriginsForBuild,
|
|
15696
15781
|
appDirectory,
|
|
15697
15782
|
assetsBuildDirectory,
|
|
@@ -15726,10 +15811,7 @@ export {
|
|
|
15726
15811
|
library: {
|
|
15727
15812
|
type: 'module'
|
|
15728
15813
|
},
|
|
15729
|
-
module: !0
|
|
15730
|
-
...isBuild ? {
|
|
15731
|
-
chunkFilename: 'static/js/async/[id]-[contenthash:16].js'
|
|
15732
|
-
} : {}
|
|
15814
|
+
module: !0
|
|
15733
15815
|
},
|
|
15734
15816
|
webOptimization: {
|
|
15735
15817
|
avoidEntryIife: !0,
|
|
@@ -15811,11 +15893,14 @@ export {
|
|
|
15811
15893
|
}), api.onBeforeBuild(()=>{
|
|
15812
15894
|
warnOnClientSourceMaps(api.getNormalizedConfig(), (msg)=>api.logger.warn(msg), 'web');
|
|
15813
15895
|
}), api.onBeforeCreateCompiler(()=>{
|
|
15814
|
-
let
|
|
15896
|
+
let root = api.getNormalizedConfig(), web = root.environments.web;
|
|
15815
15897
|
assetPrefix = resolveEffectiveAssetPrefix({
|
|
15816
|
-
dev:
|
|
15817
|
-
output:
|
|
15898
|
+
dev: web?.dev,
|
|
15899
|
+
output: web?.output,
|
|
15818
15900
|
isBuild: 'build' === api.context.action
|
|
15901
|
+
}, {
|
|
15902
|
+
dev: root.dev,
|
|
15903
|
+
output: root.output
|
|
15819
15904
|
});
|
|
15820
15905
|
});
|
|
15821
15906
|
let configPath = findEntryFile((0, external_pathe_namespaceObject.resolve)('react-router.config')), configExists = (0, external_node_fs_namespaceObject.existsSync)(configPath), configWatchPaths = configExists ? configPath : JS_EXTENSIONS.map((extension)=>(0, external_pathe_namespaceObject.resolve)(`react-router.config${extension}`)), reactRouterUserConfig = {};
|
|
@@ -16039,8 +16124,12 @@ export {
|
|
|
16039
16124
|
initialRouteTopology: routeTopology.initialRouteTopology,
|
|
16040
16125
|
onRouteTopologyChange: pluginOptions.onRouteTopologyChange
|
|
16041
16126
|
});
|
|
16042
|
-
api.onAfterEnvironmentCompile(({ stats, environment })=>{
|
|
16043
|
-
if ('web' === environment.name && (clientStats = createReactRouterManifestStats(stats?.compilation, manifestChunkNames)
|
|
16127
|
+
if (api.onAfterEnvironmentCompile(({ stats, environment })=>{
|
|
16128
|
+
if ('web' === environment.name && (clientStats = createReactRouterManifestStats(stats?.compilation, manifestChunkNames), isRscMode && stats)) {
|
|
16129
|
+
let unsupported = collectUnsupportedRscScriptAssets(stats.compilation);
|
|
16130
|
+
if (unsupported.length > 0) throw Error(`[${PLUGIN_NAME}] RSC mode requires every browser JavaScript asset to be named "*.js" (no query, no other extension): rspack's RSC manifest omits ${unsupported.slice(0, 5).map((asset)=>JSON.stringify(asset)).join(', ')}${unsupported.length > 5 ? ` and ${unsupported.length - 5} more` : ''}. Adjust web \`output.filename.js\` / \`chunkFilename\`.`);
|
|
16131
|
+
}
|
|
16132
|
+
if (pluginOptions.federation && ssr) {
|
|
16044
16133
|
let serverBuildDir = (0, external_pathe_namespaceObject.resolve)(buildDirectory, 'server'), clientBuildDir = (0, external_pathe_namespaceObject.resolve)(buildDirectory, 'client');
|
|
16045
16134
|
if ((0, external_node_fs_namespaceObject.existsSync)(serverBuildDir)) {
|
|
16046
16135
|
let ssrDir = (0, external_pathe_namespaceObject.resolve)(clientBuildDir, 'static');
|
|
@@ -16083,13 +16172,14 @@ export {
|
|
|
16083
16172
|
prerenderPaths: modePlan.prerenderPaths,
|
|
16084
16173
|
basename
|
|
16085
16174
|
})))), api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig })=>{
|
|
16086
|
-
let
|
|
16087
|
-
dev:
|
|
16088
|
-
output:
|
|
16175
|
+
let publicPath, webConfig = config.environments?.web, vmodPlugin = (publicPath = resolveEffectiveAssetPrefix({
|
|
16176
|
+
dev: webConfig?.dev,
|
|
16177
|
+
output: webConfig?.output,
|
|
16089
16178
|
isBuild
|
|
16090
|
-
}
|
|
16091
|
-
|
|
16092
|
-
|
|
16179
|
+
}, {
|
|
16180
|
+
dev: config.dev,
|
|
16181
|
+
output: config.output
|
|
16182
|
+
}), new core_namespaceObject.rspack.experiments.VirtualModulesPlugin(mapVirtualModules(modePlan.createVirtualModules(publicPath)))), guardedLazyCompilation = guardReactRouterLazyCompilation({
|
|
16093
16183
|
lazyCompilation: Object.prototype.hasOwnProperty.call(options, 'lazyCompilation') ? pluginOptions.lazyCompilation : config.dev?.lazyCompilation ?? pluginOptions.lazyCompilation,
|
|
16094
16184
|
entryClientPath: isRscMode ? finalEntryRscClientPath : finalEntryClientPath,
|
|
16095
16185
|
prewarmReactRouterModules: !!pluginOptions.unstableLazyCompilationPrewarm
|
|
@@ -16143,9 +16233,6 @@ export {
|
|
|
16143
16233
|
}
|
|
16144
16234
|
},
|
|
16145
16235
|
output: {
|
|
16146
|
-
filename: {
|
|
16147
|
-
js: '[name].js'
|
|
16148
|
-
},
|
|
16149
16236
|
distPath: {
|
|
16150
16237
|
root: outputClientPath
|
|
16151
16238
|
}
|
|
@@ -16164,13 +16251,6 @@ export {
|
|
|
16164
16251
|
]
|
|
16165
16252
|
},
|
|
16166
16253
|
externalsType: modePlan.webExternalsType,
|
|
16167
|
-
output: {
|
|
16168
|
-
...modePlan.webOutput,
|
|
16169
|
-
publicPath: assetPrefix,
|
|
16170
|
-
...options.federation ? {
|
|
16171
|
-
chunkLoading: 'import'
|
|
16172
|
-
} : {}
|
|
16173
|
-
},
|
|
16174
16254
|
optimization: modePlan.webOptimization
|
|
16175
16255
|
}
|
|
16176
16256
|
}
|
|
@@ -16208,17 +16288,7 @@ export {
|
|
|
16208
16288
|
},
|
|
16209
16289
|
externals: modePlan.nodeExternals,
|
|
16210
16290
|
...modePlan.nodeDependencies,
|
|
16211
|
-
externalsType: resolvedServerOutput
|
|
16212
|
-
output: {
|
|
16213
|
-
chunkFormat: resolvedServerOutput,
|
|
16214
|
-
chunkLoading: nodeChunkLoading,
|
|
16215
|
-
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
16216
|
-
devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
|
|
16217
|
-
workerChunkLoading: nodeChunkLoading,
|
|
16218
|
-
wasmLoading: 'fetch',
|
|
16219
|
-
module: 'module' === resolvedServerOutput,
|
|
16220
|
-
chunkFilename: 'static/js/async/[name].js'
|
|
16221
|
-
}
|
|
16291
|
+
externalsType: resolvedServerOutput
|
|
16222
16292
|
}
|
|
16223
16293
|
}
|
|
16224
16294
|
}
|
|
@@ -16227,8 +16297,22 @@ export {
|
|
|
16227
16297
|
}), registerReactRouterEnvironmentOutput({
|
|
16228
16298
|
api,
|
|
16229
16299
|
federation: pluginOptions.federation,
|
|
16230
|
-
resolvedServerOutput
|
|
16231
|
-
|
|
16300
|
+
resolvedServerOutput,
|
|
16301
|
+
webOutput: modePlan.webOutput
|
|
16302
|
+
}), pluginOptions.federation && 'classic' === modePlan.kind) {
|
|
16303
|
+
let browserEntryModules = new Set([
|
|
16304
|
+
finalEntryClientPath,
|
|
16305
|
+
...routeByFilePath.keys()
|
|
16306
|
+
]);
|
|
16307
|
+
api.transform({
|
|
16308
|
+
environments: [
|
|
16309
|
+
'web'
|
|
16310
|
+
],
|
|
16311
|
+
order: 'post',
|
|
16312
|
+
test: (resourcePath)=>browserEntryModules.has(resourcePath)
|
|
16313
|
+
}, ({ code })=>`${code}\nexport {};\nawait Promise.resolve();\n`);
|
|
16314
|
+
}
|
|
16315
|
+
'classic' === modePlan.kind && useRouteModuleTransformLoader && api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
|
|
16232
16316
|
tools: {
|
|
16233
16317
|
rspack: (rspackConfig)=>{
|
|
16234
16318
|
let environmentDevHmrEnabled = 'web' === name && !isBuild && void 0 !== devHmrRefreshRuntimePath && 'development' === config.mode && config.dev?.hmr !== !1 && isRspackSwcReactRefreshEnabled(rspackConfig);
|