Back to Rspack

Migrate from webpack

website/docs/en/guide/migration/webpack.mdx

2.1.818.9 KB
Original Source

import { PackageManagerTabs } from '@theme';

Migrate from webpack

Rspack's configuration is designed based on webpack, enabling you to migrate your project from webpack to Rspack with ease.

This document is primarily aimed at projects using webpack 5. Since Rspack's API and configuration align with webpack 5. For projects not using webpack 5, there are other migration guides that can be referenced:

Checking the Node.js version

Before migrating, make sure that all build environments use a Node.js version supported by Rspack. @rspack/core@2 requires Node.js ^20.19.0 || >=22.12.0.

Keep the Node.js version consistent across local development, CI, and deployment builds. Update version settings such as .nvmrc, Volta configuration, and build images as needed.

Installing Rspack

Install Rspack in your project directory:

<PackageManagerTabs command="add @rspack/core @rspack/cli @rspack/dev-server -D" />

Both @rspack/cli and @rspack/dev-server are optional dependencies:

  • If you are not using webpack-cli, no need to install @rspack/cli.
  • If you are not using webpack-dev-server, no need to install @rspack/dev-server.
  • Use the same version of @rspack/core and @rspack/cli. The version of @rspack/dev-server may differ and does not need to match.

Updating package.json

Update your build scripts to use Rspack instead of webpack, see CLI for more details.

diff
{
  "scripts": {
-   "dev": "webpack serve",
-   "build": "webpack build",
+   "dev": "rspack dev",
+   "build": "rspack build",
+   "preview": "rspack preview",
  }
}

Remove unsupported CLI options

Rspack CLI does not support some webpack CLI options, including --progress, --color, --bail, and --output-pathinfo. Keeping these options causes an Unknown option error before the configuration is loaded.

During migration, remove these unsupported options from the build command. If you still need the corresponding behavior, use the Rspack configuration instead:

diff
{
  "scripts": {
-   "build": "webpack --mode production --progress --color",
+   "build": "rspack --mode production",
  }
}
js
export default {
  stats: {
    // Equivalent to webpack CLI's --color
    colors: true,
  },
};

Updating configuration

Rename the webpack.config.js file to rspack.config.js.

:::tip Rspack commands can specify the configuration file with -c or --config, similar to webpack commands. However, unlike webpack, if a configuration file is not explicitly specified, Rspack defaults to using rspack.config.js. :::

Rspack supports most webpack configuration options. See Configure Rspack for the complete list of supported options.

Cache configuration

Webpack and Rspack use different cache option shapes. Do not copy webpack cache options directly; map them to the corresponding Rspack cache options.

Disabled cache and memory cache can be kept as-is: cache: false, cache: true, and cache: { type: 'memory' } have the same meaning in Rspack.

For webpack filesystem cache, use Rspack persistent cache, then migrate the supported fields below.

  1. Change webpack cache.type: 'filesystem' to Rspack cache.type: 'persistent'.
diff
export default {
- cache: {
-   type: 'filesystem',
- },
+ cache: {
+   type: 'persistent',
+ },
};
  1. Flatten webpack cache.buildDependencies into Rspack cache.buildDependencies, which accepts a file path array.
diff
export default {
- cache: {
-   buildDependencies: {
-     config: [__filename, path.join(__dirname, 'package.json')],
-     ts: [path.join(__dirname, 'tsconfig.json')]
-   }
- },
+ cache: {
+   type: 'persistent',
+   buildDependencies: [
+     __filename,
+     path.join(import.meta.dirname, 'package.json'),
+     path.join(import.meta.dirname, 'tsconfig.json')
+   ]
+ },
};
  1. Keep webpack cache.name and cache.version as-is. Rspack uses the same cache.name semantics to create coexisting caches.

  2. Move webpack top-level snapshot options into Rspack cache.snapshot.

diff
export default {
- snapshot: {
-   immutablePaths: [path.join(__dirname, 'constant')],
-   managedPaths: [path.join(__dirname, 'node_modules')],
-   unmanagedPaths: []
- },
+ cache: {
+   type: 'persistent',
+   snapshot: {
+     immutablePaths: [path.join(import.meta.dirname, 'constant')],
+     managedPaths: [path.join(import.meta.dirname, 'node_modules')],
+     unmanagedPaths: []
+   }
+ },
};
  1. Move webpack cache.cacheDirectory to Rspack cache.storage.directory, and webpack cache.cacheLocation to Rspack cache.storage.location. The option names differ, but their semantics are aligned. Rspack also defaults storage.location to storage.directory/cache.name.
diff
export default {
- cache: {
-   type: 'filesystem',
-   cacheDirectory: path.join(__dirname, 'node_modules/.cache/test'),
-   cacheLocation: path.join(__dirname, 'node_modules/.cache/test/client')
- },
+ cache: {
+   type: 'persistent',
+   storage: {
+     type: 'filesystem',
+     directory: path.join(import.meta.dirname, 'node_modules/.cache/test'),
+     location: path.join(import.meta.dirname, 'node_modules/.cache/test/client')
+   }
+ },
};

The following example shows the same mapping when automating config migration:

js
function transform(webpackConfig, rspackConfig) {
  if (webpackConfig.cache === undefined) {
    webpackConfig.cache = webpackConfig.mode === 'development';
  }

  if (!webpackConfig.cache) {
    rspackConfig.cache = false;
    return;
  }

  if (webpackConfig.cache === true || webpackConfig.cache.type === 'memory') {
    rspackConfig.cache = true;
    return;
  }

  rspackConfig.cache = { type: 'persistent' };

  rspackConfig.cache.buildDependencies = Object.values(
    webpackConfig.cache.buildDependencies || {},
  ).flat();

  rspackConfig.cache.name = webpackConfig.cache.name;
  rspackConfig.cache.version = webpackConfig.cache.version;

  rspackConfig.cache.snapshot = {
    immutablePaths: webpackConfig.snapshot?.immutablePaths,
    managedPaths: webpackConfig.snapshot?.managedPaths,
    unmanagedPaths: webpackConfig.snapshot?.unmanagedPaths,
  };

  rspackConfig.cache.storage = {
    type: 'filesystem',
    directory: webpackConfig.cache.cacheDirectory,
    location: webpackConfig.cache.cacheLocation,
  };
}

Webpack built-in plugins

Rspack has implemented most of webpack's built-in plugins, with the same names and configuration parameters, allowing for easy replacement.

For example, replacing the DefinePlugin:

js
const webpack = require('webpack'); // [!code --]
const { rspack } = require('@rspack/core'); // [!code ++]

module.exports = {
  //...
  plugins: [
    new webpack.DefinePlugin({ // [!code --]
    new rspack.DefinePlugin({ // [!code ++]
      // ...
    }),
  ],
}

See Built-in plugins for more information about supported webpack plugins in Rspack.

Community plugins

Rspack supports most of the webpack community plugins and also offers alternative solutions for some currently unsupported plugins.

Check Plugin compat for more information on Rspack's compatibility with popular webpack community plugins.

Some webpack ecosystem packages, such as webpack-node-externals and node-polyfill-webpack-plugin, require newer versions for Rspack compatibility. Before reusing a community package, upgrade it to the latest version, as older versions may rely on incompatible webpack APIs.

unplugin

Some unplugin packages provide separate entry points for each bundler. When a /rspack entry is available, use it instead of /webpack so the plugin selects the Rspack adapter:

diff
- import AutoImport from 'unplugin-auto-import/webpack';
- import Components from 'unplugin-vue-components/webpack';
+ import AutoImport from 'unplugin-auto-import/rspack';
+ import Components from 'unplugin-vue-components/rspack';

copy-webpack-plugin

Use rspack.CopyRspackPlugin instead of copy-webpack-plugin:

js
const CopyWebpackPlugin = require('copy-webpack-plugin'); // [!code --]
const { rspack } = require('@rspack/core'); // [!code ++]

module.exports = {
  plugins: [
    new CopyWebpackPlugin({ // [!code --]
    new rspack.CopyRspackPlugin({ // [!code ++]
      // ...
    }),
  ]
}

mini-css-extract-plugin

Use rspack.CssExtractRspackPlugin instead of mini-css-extract-plugin:

diff
- const CssExtractWebpackPlugin = require('mini-css-extract-plugin');
+ const { rspack } = require('@rspack/core');

module.exports = {
  plugins: [
-   new CssExtractWebpackPlugin({
+   new rspack.CssExtractRspackPlugin({
      // ...
    }),
  ]
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
-         CssExtractWebpackPlugin.loader,
+         rspack.CssExtractRspackPlugin.loader,
          "css-loader"
        ],
      }
    ]
  }
}

tsconfig-paths-webpack-plugin

Rspack does not support webpack's resolve.plugins option. Use resolve.tsConfig option instead of tsconfig-paths-webpack-plugin:

diff
-import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
+import path from 'node:path';

 export default {
  resolve: {
-    plugins: [new TsconfigPathsPlugin()],
+    tsConfig: path.resolve(import.meta.dirname, 'tsconfig.json'),
  },
};

fork-ts-checker-webpack-plugin

Use ts-checker-rspack-plugin instead of fork-ts-checker-webpack-plugin:

js
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); // [!code --]
const { TsCheckerRspackPlugin } = require('ts-checker-rspack-plugin'); // [!code ++]

module.exports = {
  plugins: [
    new ForkTsCheckerWebpackPlugin(), // [!code --]
    new TsCheckerRspackPlugin(), // [!code ++]
  ],
};

terser-webpack-plugin

For projects that use terser-webpack-plugin to minify JavaScript, we recommend switching to rspack.SwcJsMinimizerRspackPlugin for better build performance:

js
const TerserPlugin = require('terser-webpack-plugin'); // [!code --]
const { rspack } = require('@rspack/core'); // [!code ++]

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin(), // [!code --]
      new rspack.SwcJsMinimizerRspackPlugin(), // [!code ++]
      new rspack.LightningCssMinimizerRspackPlugin(),
    ],
  },
};

:::tip When you explicitly configure optimization.minimizer, Rspack's default minimizers are disabled, so we recommend keeping both JavaScript and CSS minimizers in the list. :::

css-minimizer-webpack-plugin

For projects that use css-minimizer-webpack-plugin to minify CSS, we recommend switching to rspack.LightningCssMinimizerRspackPlugin for better build performance:

js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); // [!code --]
const { rspack } = require('@rspack/core'); // [!code ++]

module.exports = {
  optimization: {
    minimizer: [
      new rspack.SwcJsMinimizerRspackPlugin(),
      new CssMinimizerPlugin(), // [!code --]
      new rspack.LightningCssMinimizerRspackPlugin(), // [!code ++]
    ],
  },
};

Loaders

Rspack is compatible with most webpack loaders, so existing loaders can typically be reused without changes.

For optimal performance and consistency, we recommend the following migrations where applicable:

babel-loader

Migrate babel-loader to builtin:swc-loader to use Rspack's built-in SWC transform for better performance.

If you need custom transformation logic using Babel plugins, you can retain babel-loader, but it is recommended to limit its use to fewer files to prevent significant performance degradation.

diff
module.exports = {
  module: {
    rules: [
      {
-        test: /\.(j|t)sx?$/,
+        test: /\.(?:js|mjs|jsx|ts|tsx)$/,
        exclude: [/[\\/]node_modules[\\/]/],
        use: [
          {
-           loader: 'babel-loader',
+           loader: 'builtin:swc-loader',
+           options: {
+             detectSyntax: 'auto',
+           },
          },
        ],
      },
    ],
  },
};
diff
+const isDev = process.env.NODE_ENV === 'development';

module.exports = {
  module: {
    rules: [
      {
        test: /\.(?:js|mjs|jsx|ts|tsx)$/,
        exclude: [/[\\/]node_modules[\\/]/],
        use: [
          {
-            loader: 'babel-loader',
+            loader: 'builtin:swc-loader',
            options: {
-              presets: ['@babel/preset-typescript', '@babel/preset-react'],
+              jsc: {
+                transform: {
+                  react: {
+                    runtime: 'automatic',
+                    development: isDev,
+                    refresh: isDev,
+                  },
+                },
+              },
+              detectSyntax: 'auto',
            },
          },
        ],
      },
    ],
  },
};

swc-loader

When migrating external swc-loader to builtin:swc-loader, only the loader name changes to builtin:swc-loader; all the options remain exactly the same as your original swc-loader config.

js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(j|t)sx?$/,
        use: [
          {
            loader: 'swc-loader', // [!code --]
            loader: 'builtin:swc-loader', // [!code ++]
          },
        ],
      },
    ],
  },
};

file-loader

Migrate file-loader to Asset Modules with asset/resource.

diff
 module.exports = {
   module: {
     rules: [
-      {
-        test: /\.(png|jpe?g|gif)$/i,
-        use: ["file-loader"],
-      },
+      {
+        test: /\.(png|jpe?g|gif)$/i,
+        type: "asset/resource",
+      },
     ],
   },
 };

url-loader

Migrate url-loader to Asset Modules with asset/inline.

diff
 module.exports = {
   module: {
     rules: [
-      {
-        test: /\.(png|jpe?g|gif)$/i,
-        use: ["url-loader"],
-      },
+      {
+        test: /\.(png|jpe?g|gif)$/i,
+        type: "asset/inline",
+      },
     ],
   },
 };

raw-loader

Migrate raw-loader to Asset Modules with asset/source.

diff
 module.exports = {
   module: {
     rules: [
-      {
-        test: /^BUILD_ID$/,
-        use: ["raw-loader",],
-      },
+      {
+        test: /^BUILD_ID$/,
+        type: "asset/source",
+      },
     ],
   },
 };

vue-loader

For Vue 3 projects, replace vue-loader with rspack-vue-loader, and update both the plugin import and loader name:

diff
-import { VueLoaderPlugin } from 'vue-loader';
+import { VueLoaderPlugin } from 'rspack-vue-loader';

export default {
  plugins: [new VueLoaderPlugin()],
  module: {
    rules: [
      {
        test: /\.vue$/,
-       loader: 'vue-loader',
+       loader: 'rspack-vue-loader',
+       options: {
+         experimentalInlineMatchResource: true,
+       },
      },
    ],
  },
};

Common webpack package replacements

When migrating webpack ecosystem packages, the following non-plugin packages usually need to be replaced.

webpack packageRspack replacementNotes
webpack@rspack/coreCore package.
webpack-cli@rspack/cliCLI commands for Rspack.
webpack-dev-server@rspack/dev-serverDevelopment server for Rspack.
webpack-dev-middleware@rspack/dev-middlewareMiddleware for custom Node.js servers.
webpack-chainrspack-chainChainable Rspack configuration API.
webpack-mergerspack-mergeRspack configuration merging.

For plugin packages, see Plugin compatibility.

Removing webpack dependencies

After successfully building your project with Rspack, check whether any loaders, plugins, or custom build scripts still import webpack or webpack/lib/*.

If imports remain, keep webpack temporarily as a compatibility dependency. Remove webpack-related dependencies after they have been replaced or verified as unnecessary:

<PackageManagerTabs command="remove webpack webpack-cli webpack-dev-server" />