cli: switch to using Rspack by default

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-04-07 01:02:39 +02:00
parent 0aa2fc14ab
commit 923ceb2f34
14 changed files with 218 additions and 171 deletions
+21
View File
@@ -0,0 +1,21 @@
---
'@backstage/cli': minor
---
**BREAKING**: The new app build based on [Rspack](https://rspack.dev/) is now the default, and the `EXPERIMENTAL_RSPACK` flag has been removed. To revert to the old behavior, set the `LEGACY_WEBPACK_BUILD` environment flag and install the following optional dependencies:
```json
{
"dependencies": {
"@module-federation/enhanced": "^0.9.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"esbuild-loader": "^4.0.0",
"mini-css-extract-plugin": "^2.4.2",
"terser-webpack-plugin": "^5.1.3",
"webpack": "^5.94.0",
"webpack-dev-server": "^5.0.0"
}
}
```
If you do encounter a blocking issue that forces you to use the old WebPack build, please [open an issue](https://github.com/backstage/backstage/issues) explaining the problem. The WebPack build will be removed in a future release.
+33 -18
View File
@@ -58,20 +58,20 @@
"@backstage/release-manifests": "workspace:^",
"@backstage/types": "workspace:^",
"@manypkg/get-packages": "^1.1.3",
"@module-federation/enhanced": "^0.9.0",
"@octokit/graphql": "^5.0.0",
"@octokit/graphql-schema": "^13.7.0",
"@octokit/oauth-app": "^4.2.0",
"@octokit/request": "^8.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"@rollup/plugin-commonjs": "^26.0.0",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-yaml": "^4.0.0",
"@rspack/core": "^1.4.11",
"@rspack/dev-server": "^1.1.4",
"@rspack/plugin-react-refresh": "^1.4.3",
"@spotify/eslint-config-base": "^15.0.0",
"@spotify/eslint-config-react": "^15.0.0",
"@spotify/eslint-config-typescript": "^15.0.0",
"@sucrase/webpack-loader": "^2.0.0",
"@swc/core": "^1.3.46",
"@swc/helpers": "^0.5.0",
"@swc/jest": "^0.2.22",
@@ -91,7 +91,6 @@
"css-loader": "^6.5.1",
"ctrlc-windows": "^2.1.0",
"esbuild": "^0.25.0",
"esbuild-loader": "^4.0.0",
"eslint": "^8.6.0",
"eslint-config-prettier": "^9.0.0",
"eslint-formatter-friendly": "^7.0.0",
@@ -120,7 +119,6 @@
"jest-runtime": "^29.0.2",
"json-schema": "^0.4.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^2.4.2",
"minimatch": "^9.0.0",
"node-stdlib-browser": "^1.3.1",
"npm-packlist": "^5.0.0",
@@ -144,12 +142,9 @@
"sucrase": "^3.20.2",
"swc-loader": "^0.2.3",
"tar": "^6.1.12",
"terser-webpack-plugin": "^5.1.3",
"ts-morph": "^24.0.0",
"undici": "^7.2.3",
"util": "^0.12.3",
"webpack": "^5.94.0",
"webpack-dev-server": "^5.0.0",
"yaml": "^2.0.0",
"yargs": "^16.2.0",
"yml-loader": "^2.1.0",
@@ -174,9 +169,8 @@
"@backstage/plugin-scaffolder-node-test-utils": "workspace:^",
"@backstage/test-utils": "workspace:^",
"@backstage/theme": "workspace:^",
"@rspack/core": "^1.3.9",
"@rspack/dev-server": "^1.1.1",
"@rspack/plugin-react-refresh": "^1.4.2",
"@module-federation/enhanced": "^0.9.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"@types/cross-spawn": "^6.0.2",
"@types/ejs": "^3.1.3",
"@types/express": "^4.17.6",
@@ -194,22 +188,43 @@
"@types/webpack-sources": "^3.2.3",
"@types/yarnpkg__lockfile": "^1.1.4",
"del": "^8.0.0",
"esbuild-loader": "^4.0.0",
"mini-css-extract-plugin": "^2.4.2",
"msw": "^1.0.0",
"nodemon": "^3.0.1"
"nodemon": "^3.0.1",
"terser-webpack-plugin": "^5.1.3",
"webpack": "~5.96.0",
"webpack-dev-server": "^5.0.0"
},
"peerDependencies": {
"@rspack/core": "^1.2.8",
"@rspack/dev-server": "^1.0.9",
"@rspack/plugin-react-refresh": "^1.0.0"
"@module-federation/enhanced": "^0.9.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"esbuild-loader": "^4.0.0",
"mini-css-extract-plugin": "^2.4.2",
"terser-webpack-plugin": "^5.1.3",
"webpack": "~5.96.0",
"webpack-dev-server": "^5.0.0"
},
"peerDependenciesMeta": {
"@rspack/core": {
"@module-federation/enhanced": {
"optional": true
},
"@rspack/dev-server": {
"@pmmmwh/react-refresh-webpack-plugin": {
"optional": true
},
"@rspack/plugin-react-refresh": {
"esbuild-loader": {
"optional": true
},
"mini-css-extract-plugin": {
"optional": true
},
"terser-webpack-plugin": {
"optional": true
},
"webpack": {
"optional": true
},
"webpack-dev-server": {
"optional": true
}
},
@@ -25,8 +25,8 @@ import { isValidUrl } from '../../../lib/urls';
import chalk from 'chalk';
export async function command(opts: OptionValues): Promise<void> {
const rspack = process.env.EXPERIMENTAL_RSPACK
? (require('@rspack/core') as typeof import('@rspack/core').rspack)
const webpack = process.env.LEGACY_WEBPACK_BUILD
? (require('webpack') as typeof import('webpack'))
: undefined;
const role = await findRoleFromCommand(opts);
@@ -44,7 +44,7 @@ export async function command(opts: OptionValues): Promise<void> {
targetDir: paths.targetDir,
configPaths,
writeStats: Boolean(opts.stats),
rspack,
webpack,
});
}
return buildBackend({
@@ -67,7 +67,7 @@ export async function command(opts: OptionValues): Promise<void> {
configPaths: [],
writeStats: Boolean(opts.stats),
isModuleFederationRemote: true,
rspack,
webpack,
});
}
@@ -31,10 +31,9 @@ import { createScriptOptionsParser } from '../../../../lib/optionsParser';
export async function command(opts: OptionValues, cmd: Command): Promise<void> {
let packages = await PackageGraph.listTargetPackages();
const shouldUseRspack = Boolean(process.env.EXPERIMENTAL_RSPACK);
const rspack = shouldUseRspack
? (require('@rspack/core') as typeof import('@rspack/core').rspack)
const webpack = process.env.LEGACY_WEBPACK_BUILD
? (require('webpack') as typeof import('webpack'))
: undefined;
if (opts.since) {
@@ -116,7 +115,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise<void> {
targetDir: pkg.dir,
configPaths: (buildOptions.config as string[]) ?? [],
writeStats: Boolean(buildOptions.stats),
rspack,
webpack,
});
},
});
@@ -26,11 +26,11 @@ interface BuildAppOptions {
writeStats: boolean;
configPaths: string[];
isModuleFederationRemote?: true;
rspack?: typeof import('@rspack/core').rspack;
webpack?: typeof import('webpack');
}
export async function buildFrontend(options: BuildAppOptions) {
const { targetDir, writeStats, configPaths, rspack } = options;
const { targetDir, writeStats, configPaths, webpack } = options;
const packageJson = (await fs.readJson(
resolvePath(targetDir, 'package.json'),
)) as BackstagePackageJson;
@@ -48,6 +48,6 @@ export async function buildFrontend(options: BuildAppOptions) {
args: configPaths,
fromPackage: packageJson.name,
})),
rspack,
webpack,
});
}
@@ -17,7 +17,7 @@
import yn from 'yn';
import fs from 'fs-extra';
import { resolve as resolvePath } from 'path';
import webpack from 'webpack';
import { rspack, Configuration, MultiStats } from '@rspack/core';
import {
measureFileSizesBeforeBuild,
printFileSizesAfterBuild,
@@ -38,7 +38,7 @@ function applyContextToError(error: string, moduleName: string): string {
}
export async function buildBundle(options: BuildOptions) {
const { statsJsonEnabled, schema: configSchema, rspack } = options;
const { statsJsonEnabled, schema: configSchema, webpack } = options;
const paths = resolveBundlingPaths(options);
const publicPaths = await resolveOptionalBundlingPaths({
@@ -54,7 +54,7 @@ export async function buildBundle(options: BuildOptions) {
getFrontendAppConfigs: () => options.frontendAppConfigs,
};
const configs: webpack.Configuration[] = [];
const configs: Configuration[] = [];
if (options.moduleFederation?.mode === 'remote') {
// Package detection is disabled for remote bundles
@@ -119,13 +119,11 @@ export async function buildBundle(options: BuildOptions) {
);
}
if (rspack) {
console.log(
chalk.yellow(`⚠️ WARNING: Using experimental RSPack bundler.`),
);
if (webpack) {
console.log(chalk.yellow(`⚠️ WARNING: Using legacy WebPack bundler`));
}
const { stats } = await build(configs, isCi, rspack);
const { stats } = await build(configs, isCi, webpack);
if (!stats) {
throw new Error('No stats returned');
@@ -159,34 +157,32 @@ export async function buildBundle(options: BuildOptions) {
}
async function build(
configs: webpack.Configuration[],
configs: Configuration[],
isCi: boolean,
rspack?: typeof import('@rspack/core').rspack,
webpack?: typeof import('webpack'),
) {
const bundler = (rspack ?? webpack) as typeof webpack;
const bundler = (webpack ?? rspack) as typeof rspack;
const stats = await new Promise<webpack.MultiStats | undefined>(
(resolve, reject) => {
bundler(configs, (err, buildStats) => {
if (err) {
if (err.message) {
const { errors } = formatWebpackMessages({
errors: [err.message],
warnings: new Array<string>(),
_showErrors: true,
_showWarnings: true,
});
const stats = await new Promise<MultiStats | undefined>((resolve, reject) => {
bundler(configs, (err, buildStats) => {
if (err) {
if (err.message) {
const { errors } = formatWebpackMessages({
errors: [err.message],
warnings: new Array<string>(),
_showErrors: true,
_showWarnings: true,
});
throw new Error(errors[0]);
} else {
reject(err);
}
throw new Error(errors[0]);
} else {
resolve(buildStats);
reject(err);
}
});
},
);
} else {
resolve(buildStats);
}
});
});
if (!stats) {
throw new Error('Failed to compile: No stats provided');
@@ -16,16 +16,15 @@
import { BundlingOptions, ModuleFederationOptions } from './types';
import { resolve as resolvePath } from 'path';
import webpack from 'webpack';
import { rspack, Configuration } from '@rspack/core';
import { BundlingPaths } from './paths';
import { Config } from '@backstage/config';
import ESLintPlugin from 'eslint-webpack-plugin';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin';
import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import { ModuleFederationPlugin } from '@module-federation/enhanced/rspack';
import { paths as cliPaths } from '../../../../lib/paths';
import fs from 'fs-extra';
import { optimization as optimizationConfig } from './optimization';
@@ -113,14 +112,14 @@ async function readBuildInfo() {
export async function createConfig(
paths: BundlingPaths,
options: BundlingOptions,
): Promise<webpack.Configuration> {
): Promise<Configuration> {
const {
checksEnabled,
isDev,
frontendConfig,
moduleFederation,
publicSubPath = '',
rspack,
webpack,
} = options;
const { plugins, loaders } = transforms(options);
@@ -147,11 +146,12 @@ export async function createConfig(
},
} as const;
if (rspack) {
if (webpack) {
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
plugins.push(new ReactRefreshPlugin(refreshOptions));
} else {
const RspackReactRefreshPlugin = require('@rspack/plugin-react-refresh');
plugins.push(new RspackReactRefreshPlugin(refreshOptions));
} else {
plugins.push(new ReactRefreshPlugin(refreshOptions));
}
}
@@ -167,7 +167,7 @@ export async function createConfig(
);
}
const bundler = rspack ? (rspack as unknown as typeof webpack) : webpack;
const bundler = webpack ? (webpack as unknown as typeof rspack) : rspack;
// TODO(blam): process is no longer auto polyfilled by webpack in v5.
// we use the provide plugin to provide this polyfill, but lets look
@@ -190,7 +190,11 @@ export async function createConfig(
config: frontendConfig,
},
};
if (rspack) {
if (webpack) {
// Config injection via index.html doesn't work across reloads with
// WebPack, so we rely on the APP_CONFIG injection instead
plugins.push(new HtmlWebpackPlugin(templateOptions));
} else {
// With Rspack we inject config via index.html, this is both because we
// can't use APP_CONFIG due to the lack of support for runtime values, but
// also because we are able to do it and it lines up better with what the
@@ -204,10 +208,6 @@ export async function createConfig(
options.getFrontendAppConfigs,
),
);
} else {
// Config injection via index.html doesn't work across reloads with
// WebPack, so we rely on the APP_CONFIG injection instead
plugins.push(new HtmlWebpackPlugin(templateOptions));
}
plugins.push(
new HtmlWebpackPlugin({
@@ -227,9 +227,9 @@ export async function createConfig(
if (options.moduleFederation) {
const isRemote = options.moduleFederation?.mode === 'remote';
const AdaptedModuleFederationPlugin = rspack
? (require('@module-federation/enhanced/rspack')
.ModuleFederationPlugin as typeof ModuleFederationPlugin)
const AdaptedModuleFederationPlugin = webpack
? (require('@module-federation/enhanced/webpack')
.ModuleFederationPlugin as unknown as typeof ModuleFederationPlugin)
: ModuleFederationPlugin;
const exposes = options.moduleFederation?.exposes
@@ -304,18 +304,28 @@ export async function createConfig(
const buildInfo = await readBuildInfo();
plugins.push(
new bundler.DefinePlugin({
'process.env.BUILD_INFO': JSON.stringify(buildInfo),
'process.env.APP_CONFIG': rspack
? JSON.stringify([]) // Inject via index.html instead
: bundler.DefinePlugin.runtimeValue(
webpack
? new webpack.DefinePlugin({
'process.env.BUILD_INFO': JSON.stringify(buildInfo),
'process.env.APP_CONFIG': webpack.DefinePlugin.runtimeValue(
() => JSON.stringify(options.getFrontendAppConfigs()),
true,
),
// This allows for conditional imports of react-dom/client, since there's no way
// to check for presence of it in source code without module resolution errors.
'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(hasReactDomClient()),
}),
// This allows for conditional imports of react-dom/client, since there's no way
// to check for presence of it in source code without module resolution errors.
'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(
hasReactDomClient(),
),
})
: new bundler.DefinePlugin({
'process.env.BUILD_INFO': JSON.stringify(buildInfo),
'process.env.APP_CONFIG': JSON.stringify([]), // Inject via index.html instead
// This allows for conditional imports of react-dom/client, since there's no way
// to check for presence of it in source code without module resolution errors.
'process.env.HAS_REACT_DOM_CLIENT': JSON.stringify(
hasReactDomClient(),
),
}),
);
if (options.linkedWorkspace) {
@@ -330,9 +340,8 @@ export async function createConfig(
// These files are required by the transpiled code when using React Refresh.
// They need to be excluded to the module scope plugin which ensures that files
// that exist in the package are required.
const reactRefreshFiles = rspack
? []
: [
const reactRefreshFiles = webpack
? [
require.resolve(
'@pmmmwh/react-refresh-webpack-plugin/lib/runtime/RefreshUtils.js',
),
@@ -340,7 +349,8 @@ export async function createConfig(
'@pmmmwh/react-refresh-webpack-plugin/overlay/index.js',
),
require.resolve('react-refresh'),
];
]
: [];
const mode = isDev ? 'development' : 'production';
const optimization = optimizationConfig(options);
@@ -388,7 +398,7 @@ export async function createConfig(
util: require.resolve('util/'),
},
// FIXME: see also https://github.com/web-infra-dev/rspack/issues/3408
...(!rspack && {
...(webpack && {
plugins: [
new ModuleScopePlugin(
[paths.targetSrc, paths.targetDev],
@@ -421,7 +431,7 @@ export async function createConfig(
},
experiments: {
lazyCompilation: yn(process.env.EXPERIMENTAL_LAZY_COMPILATION),
...(rspack && {
...(!webpack && {
// We're still using `style-loader` for custom `insert` option
css: false,
}),
@@ -16,7 +16,7 @@
import { relative as relativePath } from 'path';
import { getPackages } from '@manypkg/get-packages';
import webpack from 'webpack';
import { rspack } from '@rspack/core';
import { paths } from '../../../../lib/paths';
/**
@@ -26,7 +26,7 @@ import { paths } from '../../../../lib/paths';
* of react and react-dom which are always resolved from the target workspace.
*/
export async function createWorkspaceLinkingPlugins(
bundler: typeof webpack,
bundler: typeof rspack,
workspace: string,
) {
const { packages: linkedPackages, root: linkedRoot } = await getPackages(
@@ -14,19 +14,21 @@
* limitations under the License.
*/
import { WebpackOptionsNormalized } from 'webpack';
import { BundlingOptions } from './types';
const { EsbuildPlugin } = require('esbuild-loader');
import {
SwcJsMinimizerRspackPlugin,
LightningCssMinimizerRspackPlugin,
RspackOptionsNormalized,
} from '@rspack/core';
export const optimization = (
options: BundlingOptions,
): WebpackOptionsNormalized['optimization'] => {
const { isDev, rspack } = options;
): RspackOptionsNormalized['optimization'] => {
const { isDev, webpack } = options;
const MinifyPlugin = rspack
? rspack.SwcJsMinimizerRspackPlugin
: EsbuildPlugin;
const MinifyPlugin = webpack
? require('esbuild-loader').EsbuildPlugin
: SwcJsMinimizerRspackPlugin;
return {
minimize: !isDev,
@@ -42,7 +44,7 @@ export const optimization = (
format: undefined,
include: 'remoteEntry.js',
}),
rspack && new rspack.LightningCssMinimizerRspackPlugin(),
webpack ? undefined : new LightningCssMinimizerRspackPlugin(),
],
runtimeChunk: 'single',
splitChunks: {
@@ -74,7 +76,7 @@ export const optimization = (
priority: 10,
minSize: 100000,
minChunks: 1,
...(!rspack && {
...(webpack && {
maxAsyncRequests: Infinity,
maxInitialRequests: Infinity,
}),
@@ -19,8 +19,8 @@ import chalk from 'chalk';
import fs from 'fs-extra';
import { resolve as resolvePath } from 'path';
import openBrowser from 'react-dev-utils/openBrowser';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import { rspack } from '@rspack/core';
import { RspackDevServer } from '@rspack/dev-server';
import { paths as libPaths } from '../../../../lib/paths';
import { loadCliConfig } from '../../../config/lib/config';
@@ -55,20 +55,20 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
resolvePath(options.targetDir ?? libPaths.targetDir, 'package.json'),
);
let webpackServer: WebpackDevServer | undefined = undefined;
let devServer: RspackDevServer | undefined = undefined;
let latestFrontendAppConfigs: AppConfig[] = [];
/** Triggers a full reload of all clients */
const triggerReload = () => {
if (webpackServer) {
webpackServer.invalidate();
if (devServer) {
devServer.invalidate();
// For the Rspack server it's not enough to invalidate, we also need to
// tell the browser to reload, which we do with a 'static-changed' message
if (process.env.EXPERIMENTAL_RSPACK) {
webpackServer.sendMessage(
webpackServer.webSocketServer?.clients ?? [],
if (!process.env.LEGACY_WEBPACK_BUILD) {
devServer.sendMessage(
devServer.webSocketServer?.clients ?? [],
'static-changed',
);
}
@@ -122,8 +122,8 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
},
});
const rspack = process.env.EXPERIMENTAL_RSPACK
? (require('@rspack/core') as typeof import('@rspack/core').rspack)
const webpack = process.env.LEGACY_WEBPACK_BUILD
? (require('webpack') as typeof import('webpack'))
: undefined;
const commonConfigOptions = {
@@ -132,7 +132,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
isDev: true,
baseUrl: url,
frontendConfig,
rspack,
webpack,
getFrontendAppConfigs: () => {
return latestFrontendAppConfigs;
},
@@ -144,15 +144,13 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
moduleFederation: options.moduleFederation,
});
const bundler = (rspack ?? webpack) as typeof webpack;
const DevServer: typeof WebpackDevServer = rspack
? require('@rspack/dev-server').RspackDevServer
: WebpackDevServer;
const bundler = (webpack ?? rspack) as typeof rspack;
const DevServer: typeof RspackDevServer = webpack
? require('webpack-dev-server')
: RspackDevServer;
if (rspack) {
console.log(
chalk.yellow(`⚠️ WARNING: Using experimental RSPack dev server.`),
);
if (webpack) {
console.log(chalk.yellow(`⚠️ WARNING: Using legacy WebPack dev server.`));
}
const publicPaths = await resolveOptionalBundlingPaths({
@@ -170,7 +168,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
? bundler([config, await createConfig(publicPaths, commonConfigOptions)])
: bundler(config);
webpackServer = new DevServer(
devServer = new DevServer(
{
hot: !process.env.CI,
devMiddleware: {
@@ -225,8 +223,8 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
);
await new Promise<void>(async (resolve, reject) => {
if (webpackServer) {
webpackServer.startCallback((err?: Error) => {
if (devServer) {
devServer.startCallback((err?: Error) => {
if (err) {
reject(err);
return;
@@ -245,7 +243,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be
const waitForExit = async () => {
for (const signal of ['SIGINT', 'SIGTERM'] as const) {
process.on(signal, () => {
webpackServer?.stop();
devServer?.stop();
// exit instead of resolve. The process is shutting down and resolving a promise here logs an error
process.exit();
});
@@ -14,26 +14,30 @@
* limitations under the License.
*/
import { RuleSetRule, WebpackPluginInstance } from 'webpack';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import {
RuleSetRule,
RspackPluginInstance,
CssExtractRspackPlugin,
WebpackPluginInstance,
} from '@rspack/core';
type Transforms = {
loaders: RuleSetRule[];
plugins: WebpackPluginInstance[];
plugins: Array<RspackPluginInstance | WebpackPluginInstance>;
};
type TransformOptions = {
isDev: boolean;
isBackend?: boolean;
rspack?: typeof import('@rspack/core').rspack;
webpack?: typeof import('webpack').webpack;
};
export const transforms = (options: TransformOptions): Transforms => {
const { isDev, isBackend, rspack } = options;
const { isDev, isBackend, webpack } = options;
const CssExtractRspackPlugin: typeof MiniCssExtractPlugin = rspack
? (rspack.CssExtractRspackPlugin as unknown as typeof MiniCssExtractPlugin)
: MiniCssExtractPlugin;
const CssExtractPlugin: typeof CssExtractRspackPlugin = webpack
? (require('mini-css-extract-plugin') as unknown as typeof CssExtractRspackPlugin)
: CssExtractRspackPlugin;
// This ensures that styles inserted from the style-loader and any
// async style chunks are always given lower priority than JSS styles.
@@ -58,7 +62,9 @@ export const transforms = (options: TransformOptions): Transforms => {
exclude: /node_modules/,
use: [
{
loader: rspack ? 'builtin:swc-loader' : require.resolve('swc-loader'),
loader: webpack
? require.resolve('swc-loader')
: 'builtin:swc-loader',
options: {
jsc: {
target: 'es2022',
@@ -86,7 +92,9 @@ export const transforms = (options: TransformOptions): Transforms => {
exclude: /node_modules/,
use: [
{
loader: rspack ? 'builtin:swc-loader' : require.resolve('swc-loader'),
loader: webpack
? require.resolve('swc-loader')
: 'builtin:swc-loader',
options: {
jsc: {
target: 'es2022',
@@ -161,7 +169,7 @@ export const transforms = (options: TransformOptions): Transforms => {
insert: insertBeforeJssStyles,
},
}
: CssExtractRspackPlugin.loader,
: CssExtractPlugin.loader,
{
loader: require.resolve('css-loader'),
options: {
@@ -172,11 +180,11 @@ export const transforms = (options: TransformOptions): Transforms => {
},
];
const plugins = new Array<WebpackPluginInstance>();
const plugins = new Array<RspackPluginInstance | WebpackPluginInstance>();
if (!isDev) {
plugins.push(
new CssExtractRspackPlugin({
new CssExtractPlugin({
filename: 'static/[name].[contenthash:8].css',
chunkFilename: 'static/[name].[id].[contenthash:8].css',
insert: insertBeforeJssStyles, // Only applies to async chunks
@@ -45,7 +45,7 @@ export type BundlingOptions = {
// An external linked workspace to include in the bundling
linkedWorkspace?: string;
moduleFederation?: ModuleFederationOptions;
rspack?: typeof import('@rspack/core').rspack;
webpack?: typeof import('webpack');
};
export type ServeOptions = BundlingPathsOptions & {
@@ -69,7 +69,7 @@ export type BuildOptions = BundlingPathsOptions & {
frontendAppConfigs: AppConfig[];
fullConfig: Config;
moduleFederation?: ModuleFederationOptions;
rspack?: typeof import('@rspack/core').rspack;
webpack?: typeof import('webpack');
};
export type BackendBundlingOptions = {
@@ -79,5 +79,5 @@ export type BackendBundlingOptions = {
inspectEnabled: boolean;
inspectBrkEnabled: boolean;
require?: string;
rspack?: typeof import('@rspack/core').rspack;
webpack?: typeof import('webpack');
};
+1 -3
View File
@@ -58,8 +58,6 @@ declare module 'react-dev-utils/ModuleScopePlugin' {
}
declare module 'react-dev-utils/FileSizeReporter' {
import webpack = require('webpack');
export interface OpaqueFileSizes {
root: string;
sizes: Record<string, number>;
@@ -81,7 +79,7 @@ declare module 'react-dev-utils/FileSizeReporter' {
* the main bundle or a chunk exceeds the specified size (in bytes).
*/
export function printFileSizesAfterBuild(
webpackStats: webpack.Stats,
stats: import('@rspack/core').Stats,
previousFileSizes: OpaqueFileSizes,
buildFolder: string,
maxBundleGzipSize?: number,
+26 -26
View File
@@ -2976,13 +2976,12 @@ __metadata:
"@rollup/plugin-json": "npm:^6.0.0"
"@rollup/plugin-node-resolve": "npm:^15.0.0"
"@rollup/plugin-yaml": "npm:^4.0.0"
"@rspack/core": "npm:^1.3.9"
"@rspack/dev-server": "npm:^1.1.1"
"@rspack/plugin-react-refresh": "npm:^1.4.2"
"@rspack/core": "npm:^1.4.11"
"@rspack/dev-server": "npm:^1.1.4"
"@rspack/plugin-react-refresh": "npm:^1.4.3"
"@spotify/eslint-config-base": "npm:^15.0.0"
"@spotify/eslint-config-react": "npm:^15.0.0"
"@spotify/eslint-config-typescript": "npm:^15.0.0"
"@sucrase/webpack-loader": "npm:^2.0.0"
"@swc/core": "npm:^1.3.46"
"@swc/helpers": "npm:^0.5.0"
"@swc/jest": "npm:^0.2.22"
@@ -3078,7 +3077,7 @@ __metadata:
ts-morph: "npm:^24.0.0"
undici: "npm:^7.2.3"
util: "npm:^0.12.3"
webpack: "npm:^5.94.0"
webpack: "npm:~5.96.0"
webpack-dev-server: "npm:^5.0.0"
yaml: "npm:^2.0.0"
yargs: "npm:^16.2.0"
@@ -3087,15 +3086,27 @@ __metadata:
zod: "npm:^3.22.4"
zod-validation-error: "npm:^3.4.0"
peerDependencies:
"@rspack/core": ^1.2.8
"@rspack/dev-server": ^1.0.9
"@rspack/plugin-react-refresh": ^1.0.0
"@module-federation/enhanced": ^0.9.0
"@pmmmwh/react-refresh-webpack-plugin": ^0.5.7
esbuild-loader: ^4.0.0
mini-css-extract-plugin: ^2.4.2
terser-webpack-plugin: ^5.1.3
webpack: ~5.96.0
webpack-dev-server: ^5.0.0
peerDependenciesMeta:
"@rspack/core":
"@module-federation/enhanced":
optional: true
"@rspack/dev-server":
"@pmmmwh/react-refresh-webpack-plugin":
optional: true
"@rspack/plugin-react-refresh":
esbuild-loader:
optional: true
mini-css-extract-plugin:
optional: true
terser-webpack-plugin:
optional: true
webpack:
optional: true
webpack-dev-server:
optional: true
bin:
backstage-cli: bin/backstage-cli
@@ -16828,7 +16839,7 @@ __metadata:
languageName: node
linkType: hard
"@rspack/core@npm:^1.3.9":
"@rspack/core@npm:^1.4.11":
version: 1.4.11
resolution: "@rspack/core@npm:1.4.11"
dependencies:
@@ -16844,7 +16855,7 @@ __metadata:
languageName: node
linkType: hard
"@rspack/dev-server@npm:^1.1.1":
"@rspack/dev-server@npm:^1.1.4":
version: 1.1.4
resolution: "@rspack/dev-server@npm:1.1.4"
dependencies:
@@ -16866,7 +16877,7 @@ __metadata:
languageName: node
linkType: hard
"@rspack/plugin-react-refresh@npm:^1.4.2":
"@rspack/plugin-react-refresh@npm:^1.4.3":
version: 1.4.3
resolution: "@rspack/plugin-react-refresh@npm:1.4.3"
dependencies:
@@ -18867,17 +18878,6 @@ __metadata:
languageName: node
linkType: hard
"@sucrase/webpack-loader@npm:^2.0.0":
version: 2.0.0
resolution: "@sucrase/webpack-loader@npm:2.0.0"
dependencies:
loader-utils: "npm:^1.1.0"
peerDependencies:
sucrase: ^3
checksum: 10/16578991b1b888ac5bec5628bd24db9e21651bbbe30de076aece8787f115d8971ac87a20bc75446187c73c3185851ec2233d5b6f18c4a2dd53fbbb1ed4e488b4
languageName: node
linkType: hard
"@swagger-api/apidom-ast@npm:^1.0.0-beta.11":
version: 1.0.0-beta.11
resolution: "@swagger-api/apidom-ast@npm:1.0.0-beta.11"
@@ -49465,7 +49465,7 @@ __metadata:
languageName: node
linkType: hard
"webpack@npm:5, webpack@npm:^5, webpack@npm:^5.94.0":
"webpack@npm:5, webpack@npm:^5, webpack@npm:~5.96.0":
version: 5.96.1
resolution: "webpack@npm:5.96.1"
dependencies: