packages/rsbuild/src/migrations/update-23-0-0/migrate-performance-options.md
performance options for @rsbuild/core@2@rsbuild/core@2 removed two performance options and deprecated a third.
rsbuild v2 does not hard-error on the stale keys — it warns and ignores the
removed ones, and the deprecated one still works — so the changes here are
about adopting the replacements rather than fixing a broken build. None
have a drop-in key rename, so this ships as an AI-assisted instruction.
This only affects projects whose rsbuild.config.{ts,js,mjs,cjs} sets one
of the options below. If none of your configs use them, there is nothing
to do.
performance.bundleAnalyze was removedrsbuild v1 bundled webpack-bundle-analyzer and exposed it through
performance.bundleAnalyze. v2 removed it to cut install size.
For every config that sets performance.bundleAnalyze, remove that option
and pick one replacement:
Preferred — Rsdoctor. Add the Rsdoctor plugin; it covers bundle-size analysis and more. See rsbuild.rs/guide/debug/rsdoctor.
Keep webpack-bundle-analyzer. Install it and register it via
tools.rspack:
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
export default {
tools: {
rspack: {
plugins: [new BundleAnalyzerPlugin({ analyzerMode: 'static' })],
},
},
};
If performance is left empty after removing the option, delete the empty
performance: {} block too.
performance.profile was removedperformance.profile emitted an rspack stats JSON file. v2 removed it; emit
the file from a small custom plugin instead.
For every config that sets performance.profile: true, remove that option
and add:
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
const statsJsonPlugin = {
name: 'stats-json-plugin',
setup(api) {
api.onAfterBuild(({ stats }) => {
writeFileSync(
join(api.context.distPath, 'stats.json'),
JSON.stringify(stats?.toJson({}), null, 2)
);
});
},
};
export default {
plugins: [statsJsonPlugin],
};
performance.chunkSplit is deprecatedperformance.chunkSplit still works in v2 but is deprecated. Migrate it to
the new top-level splitChunks option, which aligns with Rspack's
optimization.splitChunks.
For every config that sets performance.chunkSplit, translate strategy:
chunkSplit.strategy | splitChunks replacement |
|---|---|
split-by-experience | { preset: 'default' } |
split-by-module | { preset: 'per-package' } |
single-vendor | { preset: 'single-vendor' } |
all-in-one | false (chunk splitting disabled) |
custom (with a nested splitChunks) | { preset: 'none', ...the nested splitChunks } |
split-by-size (with minSize / maxSize) | { preset: 'none', minSize, maxSize } |
Then translate the remaining chunkSplit keys:
override → spread its contents directly into the top-level splitChunks.
forceSplitting → splitChunks.cacheGroups. Each forceSplitting entry
name: <RegExp> expands to a full cache group:
cacheGroups: {
<name>: {
test: <RegExp>,
name: '<name>',
chunks: 'all',
// priority 0 normally; use 1 when the `single-vendor` preset is set
priority: 0,
enforce: true,
},
}
forceSplitting exampleexport default {
- performance: {
- chunkSplit: {
- forceSplitting: {
- axios: /node_modules[\\/]axios/,
- },
- },
- },
+ splitChunks: {
+ cacheGroups: {
+ axios: {
+ test: /node_modules[\\/]axios/,
+ name: 'axios',
+ chunks: 'all',
+ priority: 0,
+ enforce: true,
+ },
+ },
+ },
};
If performance is empty after removing chunkSplit, delete the empty
performance: {} block.
export default defineConfig({
performance: {
bundleAnalyze: {},
profile: true,
},
});
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
const statsJsonPlugin = {
name: 'stats-json-plugin',
setup(api) {
api.onAfterBuild(({ stats }) => {
writeFileSync(
join(api.context.distPath, 'stats.json'),
JSON.stringify(stats?.toJson({}), null, 2)
);
});
},
};
export default defineConfig({
plugins: [statsJsonPlugin],
tools: {
rspack: {
plugins: [new BundleAnalyzerPlugin({ analyzerMode: 'static' })],
},
},
});