cli: switch to using Rspack by default
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -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
@@ -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');
|
||||
};
|
||||
|
||||
Vendored
+1
-3
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user