Skip to content

Add support for Rspack #1389

@Kocal

Description

@Kocal

Related to symfony/symfony#59707

The plan generated by Claude Opus 4.5 after some discussions, and may evolve in the future.

Plan: Experimental Rspack Support in Webpack Encore

Allow users to use rspack as an alternative to webpack via Encore.enableRspack(). Rspack is a webpack-compatible bundler written in Rust, offering significantly better performance.

Caution

Before starting anything, web-infra-dev/rspack#12682 must be solved.


Phase 1: Base Infrastructure

  • 1.1 Update package.json: make webpack, webpack-cli, webpack-dev-server optional via peerDependenciesMeta
  • 1.2 Add @rspack/core, @rspack/cli, @rspack/dev-server as optional peerDependencies
  • 1.3 Create a helper lib/utils/bundler.js exposing:
    • isWebpackInstalled(): checks if webpack and webpack-cli are present
    • isRspackInstalled(): checks if @rspack/core and @rspack/cli are present
    • getBundlerModule(): returns require('webpack') or require('@rspack/core') based on context
  • 1.4 Update encore.js: on startup, verify at least one bundler is installed. Clear error otherwise: "Neither webpack nor @rspack/core is installed. Please install one: npm install webpack webpack-cli --save-dev"

Phase 2: Public API enableRspack()

  • 2.1 Add useRspack = false flag in WebpackConfig.js
  • 2.2 Add enableRspack() method in WebpackConfig.js:
    • Sets useRspack flag to true
    • Displays console warning [EXPERIMENTAL] Rspack support is experimental and may not work with all features
  • 2.3 Expose enableRspack() in index.js via the Encore proxy
  • 2.4 Update encore.js: if useRspack is enabled but rspack is not installed, throw explicit error. Same if rspack is enabled but webpack-dev-server is used without @rspack/dev-server

Phase 3: Dynamic Bundler CLI Switch

  • 3.1 Update encore.js: dynamically switch between CLIs based on useRspack
    • webpack/bin/webpack@rspack/cli
    • webpack-dev-server/bin/webpack-dev-server@rspack/dev-server
  • 3.2 Adapt console messages: "Running rspack..." vs "Running webpack..."
  • 3.3 Update showUsageInstructions() to mention rspack if installed

Phase 4: Config Generator Adaptation

  • 4.1 Update config-generator.js: dynamically import the bundler module via the getBundlerModule() helper
  • 4.2 Adapt native plugin imports: DefinePlugin, ProvidePlugin, HotModuleReplacementPlugin from webpack or @rspack/core
  • 4.3 Handle stats configuration differences between webpack and rspack

Phase 5: Plugin Adaptation

  • 5.1 mini-css-extract.js: use CssExtractRspackPlugin (builtin) if rspack, otherwise MiniCssExtractPlugin
  • 5.2 terser.js: use SwcJsMinimizerRspackPlugin (builtin) if rspack, otherwise TerserWebpackPlugin
  • 5.3 css-minimizer.js: use LightningCssMinimizerRspackPlugin (builtin) if rspack, otherwise CssMinimizerPlugin
  • 5.4 define.js: import DefinePlugin from the correct module
  • 5.5 variable-provider.js: import ProvidePlugin from the correct module
  • 5.6 friendly-errors.js: disable if rspack (return null), rspack has its own error reporting system via stats

Phase 6: Loader Adaptation

  • 6.1 css.js: adapt import of MiniCssExtractPlugin.loader vs rspack builtin loader
  • 6.2 [CRITICAL] Rewrite copy-files-loader.js: remove usage of webpack/lib/dependencies/LoaderDependency (internal API incompatible with rspack). Possible alternatives:
    • Use native asset modules
    • Use rspack.CopyPlugin / copy-webpack-plugin
  • 6.3 Verify compatibility of other loaders with rspack (most should work out of the box)

Phase 7: Custom Encore Plugin Adaptation

  • 7.1 delete-unused-entries-js-plugin.js: verify compatibility of hooks compiler.hooks.compilation and compilation.hooks.additionalAssets with rspack
  • 7.2 entry-points-plugin.js: verify compatibility of hook compiler.hooks.afterEmit
  • 7.3 asset-output-display.js: verify compatibility of hook compiler.hooks.emit

Phase 8: features.js Update

  • 8.1 Add rspack feature in features.js with required packages: @rspack/core, @rspack/cli
  • 8.2 Add rspack-dev-server feature with package @rspack/dev-server
  • 8.3 Adapt error messages to guide users toward installing the correct bundler

Phase 9: Tests

  • 9.1 Create test_apps/rspack/: minimal test application with rspack
  • 9.2 Create test_apps/rspack-with-babel/: test with babel-loader
  • 9.3 Adapt unit tests to cover both bundlers (parameterized)
  • 9.4 Adapt functional.js to run tests with rspack
  • 9.5 Configure CI (GitHub Actions) with matrix: bundler: [webpack, rspack]

Phase 10: Documentation

  • 10.1 Update README.md: add section "Experimental: Using Rspack"
    • Explain benefits (performance)
    • Installation: npm install @rspack/core @rspack/cli @rspack/dev-server --save-dev
    • Activation: Encore.enableRspack()
    • Known limitations
  • 10.2 Document features not supported with rspack (if any)
  • 10.3 Update CHANGELOG.md

Out of Scope (v1) / Future Improvements

  • handlebars-loader support with rspack (to be investigated)
  • Migrate friendly-errors transformers/formatters to rspack system
  • Encore.disableRspack() method (for override if both bundlers are installed)
  • Automatic bundler detection if only one is installed (without explicit enableRspack() call)

Identified Risks

Risk Impact Mitigation
copy-files-loader.js uses internal webpack APIs 🔴 Blocking Mandatory rewrite (Phase 6.2)
Custom plugins incompatible with rspack hooks 🟡 Medium Manual testing, adapt if needed
Third-party loaders not compatible 🟡 Medium Document limitations, suggest alternatives
friendly-errors-webpack-plugin incompatible 🟢 Low Disabled, rspack has its own reporting

Resources

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions