close

Upgrading from v1 to v2

This document lists the breaking changes from Rspack 1.x to 2.0.

Using Agent Skills

If your Coding Agent supports Skills, install the rspack-v2-upgrade skill to help with the migration.

npx skills add rstackjs/agent-skills --skill rspack-v2-upgrade

After installation, let the agent guide you through the upgrade.

Upgrade Node.js

Rspack 2.0 requires a minimum Node.js version of 20.19+ or 22.12+, and Node.js 18 is no longer supported.

Pure ESM packages

@rspack/core, @rspack/cli, and @rspack/dev-server are now published as pure ESM packages, with CommonJS builds removed.

In Node.js 20 and later, the runtime natively supports loading ESM modules via require(esm), so for most projects that use Rspack through its JavaScript API, this change should have no practical impact and does not require code changes.

This does not affect Rspack's ability to build CommonJS output. All related build behavior and configuration remain unchanged.

Dev server

@rspack/dev-server 2.0 includes the following changes:

  • @rspack/cli no longer depends on @rspack/dev-server by default, since some workflows do not require a dev server. When using the rspack dev or rspack serve commands, install @rspack/dev-server manually:
npm
yarn
pnpm
bun
deno
npm add @rspack/dev-server@beta -D
  • Some devServer options have changed, including devServer.proxy and devServer.watchFiles. See the upgrade guide for details.

@rspack/dev-server dependencies are now more streamlined and modernized:

Bundle analysis

The built-in webpack-bundler-analyzer has been removed from @rspack/cli, and the --analyze flag is no longer available.

If you need to analyze bundle outputs, it is recommended to use Rsdoctor, which provides more powerful analysis capabilities.

Module compilation changes

Changed default value of module.parser.javascript.exportsPresence

The default value of module.parser.javascript.exportsPresence has been changed from warn to error. When detecting non-existent exports, an error will now be thrown directly instead of just a warning.

If you want to restore the old behavior, you can explicitly set it to auto:

rspack.config.mjs
export default {
  module: {
    parser: {
      javascript: {
        exportsPresence: 'auto',
      },
    },
  },
};

Removed module.parser.javascript.strictExportPresence

module.parser.javascript.strictExportPresence has been removed. You can use module.parser.javascript.exportsPresence to control the behavior when exports don't exist.

Changed default value of module.parser.javascript.requireAlias

The default value of module.parser.javascript.requireAlias changed from true to false. If your code relies on renamed require calls being parsed and bundled, explicitly enable it:

rspack.config.mjs
export default {
  module: {
    parser: {
      javascript: {
        requireAlias: true,
      },
    },
  },
};

Disabled builtin:swc-loader reading .swcrc

In Rspack 2.0, builtin:swc-loader no longer supports reading .swcrc files. Move your SWC configuration into the loader options in rspack.config.js:

rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'builtin:swc-loader',
        options: {
          jsc: {
            parser: {
              syntax: 'ecmascript',
              jsx: true,
            },
            transform: {
              react: {
                runtime: 'automatic',
              },
            },
          },
        },
      },
    ],
  },
};

Removed builtin:swc-loader's rspackExperiments.collectTypeScriptInfo

The rspackExperiments.collectTypeScriptInfo option of builtin:swc-loader has been removed. Use collectTypeScriptInfo to control TypeScript information collection:

rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'builtin:swc-loader',
        options: {
          collectTypeScriptInfo: {
            typeExports: true,
          },
        },
      },
    ],
  },
};

Moved builtin:swc-loader's rspackExperiments.import

The rspackExperiments.import option of builtin:swc-loader has been moved to the top-level transformImport option. rspackExperiments.import is still supported as a deprecated alias in Rspack 2.0, but you should migrate to transformImport to avoid future breakage:

rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'builtin:swc-loader',
        options: {
-         rspackExperiments: {
-           import: [
-             {
-               libraryName: 'antd',
-               style: true,
-             },
-           ],
-         },
+         transformImport: [
+           {
+             libraryName: 'antd',
+             style: true,
+           },
+         ],
        },
      },
    ],
  },
};

Derive loader and plugin targets from target

In Rspack 2.0, the targets configuration for builtin:swc-loader, builtin:lightningcss-loader, and rspack.LightningCssMinimizerRspackPlugin now defaults to the target configuration. If you need different targets, configure them in the loader or plugin options:

rspack.config.mjs
export default {
  target: 'node',
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'builtin:swc-loader',
        options: {
          env: {
            targets: 'chrome >= 87',
          },
        },
      },
    ],
  },
};

Output configuration changes

Moved output library options

Changed default value of output.chunkLoadingGlobal

The default value of output.chunkLoadingGlobal changed from webpackChunk${output.uniqueName} to rspackChunk${output.uniqueName}. If your application depends on the old name, configure it explicitly:

rspack.config.mjs
export default {
  output: {
    chunkLoadingGlobal: 'webpackChunkMyApp',
  },
};

Changed default value of output.hotUpdateGlobal

The default value of output.hotUpdateGlobal changed from webpackHotUpdate${output.uniqueName} to rspackHotUpdate${output.uniqueName}. If your application depends on the old name, configure it explicitly:

rspack.config.mjs
export default {
  output: {
    hotUpdateGlobal: 'webpackHotUpdateMyApp',
  },
};

Changed default fallback value of output.trustedTypes.policyName

The fallback value of output.trustedTypes.policyName changed from 'webpack' to 'rspack'. policyName still defaults to output.uniqueName, and the fallback is only used when uniqueName is not set. If your project relies on the old fallback, update your CSP configuration or set it explicitly:

rspack.config.mjs
export default {
  output: {
    trustedTypes: {
      policyName: 'webpack',
    },
  },
};

Removed output.charset

The output.charset configuration has been removed. It only added a charset attribute to generated <script> tags, and modern browsers already default to UTF-8.

Removed optimization.removeAvailableModules

The optimization.removeAvailableModules configuration has been removed. It had no actual effect in Rspack and can be safely removed from your configuration.

Stats changes

Changed default parameters of stats.toJson()

When stats.toJson() is called without parameters, these fields now default to false:

  • modules: Module information
  • assets: Asset information
  • chunks: Chunk information
  • chunkGroups: Chunk group information
  • entryPoints: Entry point information

By default, stats.toJson() no longer includes these details, so the returned object is more compact. If you need them, pass the parameters explicitly:

const statsData = stats.toJson({
  modules: true,
  assets: true,
  chunks: true,
  chunkGroups: true,
  entryPoints: true,
});

For detailed parameter configuration, refer to Stats.

Removed profile and stats.profile configuration

The top-level profile configuration and stats.profile configuration have been removed. Use Rsdoctor for performance analysis:

rspack.config.mjs
export default {
-  profile: true,
  stats: {
-    profile: true,
  },
};

Plugin changes

Removed EsmLibraryPlugin

The rspack.EsmLibraryPlugin plugin has been removed. Configure output.library to generate ESM output:

rspack.config.mjs
-import { EsmLibraryPlugin } from '@rspack/core';

export default {
-  plugins: [new EsmLibraryPlugin()],
+  output: {
+    library: {
+      type: 'modern-module',
+    },
+  },
};

Removed WarnCaseSensitiveModulesPlugin

WarnCaseSensitiveModulesPlugin has been renamed to CaseSensitivePlugin, which covers all of its functionality.

Removed getHooks method from some plugins

The getHooks method on HtmlRspackPlugin, RsdoctorPlugin, and RuntimePlugin has been removed. It was only a deprecated alias of getCompilationHooks, so migrate to getCompilationHooks directly.

Adjusted HtmlRspackPlugin configuration

The sri configuration of HtmlRspackPlugin has been removed. If you need SRI functionality, use the SubresourceIntegrityPlugin plugin.

rspack.config.mjs
export default {
  plugins: [
    new rspack.HtmlRspackPlugin({
-      sri: "sha256",
    }),
+    new rspack.SubresourceIntegrityPlugin({
+      hashFuncNames: ["sha256"],
+    }),
  ],
};

Adjusted LightningCssMinimizerRspackPlugin configuration

The following LightningCssMinimizerRspackPlugin options have changed:

  • draft: removed; use drafts instead
  • cssHeadDataCompression: removed; delete this option directly

Resolve behavior changes

Default extensions change

Rspack 2.0 no longer includes .wasm in the default resolve.extensions used for JavaScript requests. That means extension-less requests such as import './module' or require('./module') no longer try ./module.wasm by default, while explicit imports like import './module.wasm' are not affected. If you need the previous behavior, add .wasm back to the corresponding resolve.byDependency entries:

rspack.config.mjs
export default {
  resolve: {
    byDependency: {
      esm: {
        extensions: ['.js', '.json', '.wasm'],
      },
      commonjs: {
        extensions: ['.js', '.json', '.wasm'],
      },
    },
  },
};

CSS resolve conditions

Rspack 2.0 no longer includes webpack in the default CSS @import resolve conditions. If you need the previous behavior, add webpack back explicitly:

rspack.config.mjs
export default {
  resolve: {
    byDependency: {
      'css-import': {
        conditionNames: ['webpack', '...'],
      },
    },
  },
};

Other changes

Changed devtool default value

The default value of the devtool option has changed:

  • When mode is development, the default value of devtool has been changed from eval to cheap-module-source-map
  • When mode is production and you are using @rspack/cli, the default value of devtool has been changed from source-map to false

If you need source maps in production, set devtool to source-map or hidden-source-map:

rspack.config.mjs
const isProd = process.env.NODE_ENV === 'production';

export default {
  devtool: isProd ? 'source-map' : 'cheap-module-source-map',
};

Removed runtime module deprecated properties

The following deprecated properties of Runtime module have been removed:

  • constructorName - Constructor name property
  • moduleIdentifier - Module identifier property

If you used these properties in custom plugins, update your code as follows:

my-plugin.js
class MyPlugin {
  apply(compiler) {
    compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
      compilation.hooks.runtimeModule.tap('MyPlugin', (module) => {
-       const name = module.constructorName;
-       const id = module.moduleIdentifier;
+       // Use alternative ways to get module information
+       const name = module.constructor.name;
+       const id = module.identifier();
      });
    });
  }
}

ProgressPlugin handler signature change

The ProgressPlugin custom handler's third argument changed from items: string[] to a structured info object.

- (percent, msg, items) => void
+ (percent, msg, info) => void

info includes:

  • builtModules: number: Number of modules built so far
  • moduleIdentifier?: string: Identifier of the module being built (only provided during build modules updates)

Changed default value of resolve.roots

The resolve's roots configuration default value changed from [ context ] to []. If you rely on server-relative URL resolution that expects paths to resolve relative to the roots directories, explicitly configure the roots option:

rspack.config.mjs
export default {
  resolve: {
    roots: [context], // the context path of the rspack config
  },
};

Removed readResourceForScheme hook

NormalModule.getCompilationHooks(compilation).readResourceForScheme has been removed. This hook was only a legacy alias for readResource.for(scheme), so migrate to that API directly.

@module-federation/runtime-tools is declared as optional peerDependency

The @module-federation/runtime-tools package has changed from dependencies to optional peerDependencies (declared via peerDependencies + peerDependenciesMeta.optional). If you are using ModuleFederationPlugin, ensure that this package is explicitly installed in your project.

Removed module.unsafeCache

module.unsafeCache was previously a performance optimization option. Because it conflicts with Rspack's Incremental Build and Persistent Cache mechanisms, it has been officially removed.

Experimental configuration changes

Remove experiments.css

experiments.css has been removed. CSS processing capability is now available by default, but you still need to configure the corresponding type in module.rules to enable it:

rspack.config.mjs
export default {
  module: {
    rules: [
      {
        test: /\.css$/,
        type: 'css/auto', // Auto-detect CSS Modules
      },
    ],
  },
};

Available type options:

  • css: Process CSS as plain CSS, without CSS Modules
  • css/module: Force enable CSS Modules
  • css/auto: Auto-detect, enable CSS Modules for .module.css files, and process plain .css files as regular CSS

For more details, refer to CSS

experiments.asyncWebAssembly enabled by default

The default value of experiments.asyncWebAssembly changed from false to true. Files with the .wasm extension will now be handled using the built-in webassembly/async rule. If you don't need this feature, you can explicitly disable it:

rspack.config.mjs
export default {
  experiments: {
    asyncWebAssembly: false,
  },
};

Other experimental configuration changes

  • experiments.cache: moved to the top-level cache.
  • experiments.rspackFuture: removed; bundlerInfo has moved to output.bundlerInfo.
  • experiments.incremental: moved to the top-level incremental.
  • experiments.layers: removed; layers are now stable and enabled by default, but you still need to configure layer in module.rules.
  • experiments.topLevelAwait: removed; top-level await is now stable and enabled by default in ESM modules.
  • experiments.lazyCompilation: moved to the top-level lazyCompilation.
  • experiments.lazyCompilationMiddleware: moved to the top-level lazyCompilationMiddleware.
  • experiments.lazyBarrel: removed; the Lazy barrel optimization is now enabled by default.
  • experiments.typeReexportsPresence: removed; use module.parser.javascript.typeReexportsPresence directly to control the behavior when re-exporting types.
  • experiments.inlineConst: removed; use optimization.inlineExports to control constant inlining optimization.
  • experiments.inlineEnum: removed; use optimization.inlineExports and builtin:swc-loader's collectTypeScriptInfo.exportedEnum to control enum inlining optimization.
  • experiments.outputModule: removed; use output.module directly to output ESM artifacts.
  • experiments.parallelLoader: removed; loader parallelization is now stable and enabled by default, but you still need to configure module.rules.use.parallel to opt in.
  • experiments.SubResourceIntegrityPlugin: moved to the top-level SubresourceIntegrityPlugin.