Skip to content

Fix: Rspack Not Working — Build Failing, Loaders Not Applying, or Dev Server Not Starting

FixDevs ·

Quick Answer

How to fix Rspack issues — configuration migration from webpack, loader compatibility, CSS extraction, module federation, React Fast Refresh, and build performance tuning.

The Problem

Rspack fails to start with a config error:

npx rspack build
Error: configuration.module.rules[0].use is not a valid value

Or a webpack loader you migrated doesn’t work:

Error: Can't resolve 'babel-loader'
Module not found: Error: Package path ./loader is not exported from package

Or CSS isn’t extracted into separate files:

All styles are inlined in JavaScript — no .css output file

Or React Fast Refresh doesn’t work — the page fully reloads on every change:

[HMR] Update applied. Full reload needed.

Why This Happens

Rspack is a Rust-based bundler designed as a drop-in replacement for webpack. It supports most of webpack’s configuration format, but with important differences:

  • Not all webpack loaders are compatible — Rspack uses its own Rust-based implementations for common transformations (TypeScript, JSX, CSS). JavaScript-based loaders like babel-loader and ts-loader work but are slower. Some loaders that depend on webpack internals don’t work at all.
  • Built-in features replace plugins — Rspack has native CSS support, built-in SWC for TypeScript/JSX, and integrated asset handling. Using the webpack equivalents (css-loader, style-loader, MiniCssExtractPlugin) still works but is unnecessary and slower.
  • Config format is almost identical but not 100% — most webpack.config.js options work unchanged. But some plugin APIs, hook signatures, and loader option formats differ. The error messages are usually clear about what’s wrong, but the fix isn’t always obvious.
  • React Fast Refresh needs the Rspack plugin, not the webpack one@pmmmwh/react-refresh-webpack-plugin doesn’t work with Rspack. Use @rspack/plugin-react-refresh instead.

Fix 1: Basic Rspack Configuration

npm install -D @rspack/core @rspack/cli
// rspack.config.js
const { defineConfig } = require('@rspack/cli');
const path = require('path');

module.exports = defineConfig({
  entry: './src/index.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    clean: true,
  },

  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        // Use Rspack's built-in SWC loader — much faster than babel-loader
        loader: 'builtin:swc-loader',
        options: {
          jsc: {
            parser: {
              syntax: 'typescript',
              tsx: true,
            },
            transform: {
              react: {
                runtime: 'automatic',  // React 17+ JSX transform
                development: process.env.NODE_ENV === 'development',
                refresh: process.env.NODE_ENV === 'development',
              },
            },
          },
        },
      },
      {
        test: /\.css$/,
        // Built-in CSS support — no css-loader or style-loader needed
        type: 'css',
      },
      {
        test: /\.(png|jpg|gif|svg|woff2?)$/,
        // Built-in asset handling
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 8 * 1024,  // Inline if under 8kb
          },
        },
      },
    ],
  },

  // Built-in plugins — no npm install needed
  plugins: [],

  devServer: {
    port: 3000,
    hot: true,
    historyApiFallback: true,
  },
});

Fix 2: CSS Extraction and Processing

Rspack has native CSS support — no plugins needed for basic CSS:

// rspack.config.js
module.exports = {
  module: {
    rules: [
      // Basic CSS — extracted to separate file automatically in production
      {
        test: /\.css$/,
        type: 'css',  // Built-in CSS handling
      },

      // CSS Modules
      {
        test: /\.module\.css$/,
        type: 'css/module',  // Built-in CSS Modules
      },

      // Sass/SCSS — still needs sass-loader
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'sass-loader',
            options: {
              // Use modern API
              api: 'modern-compiler',
            },
          },
        ],
        type: 'css',  // Output goes through built-in CSS pipeline
      },

      // PostCSS + Tailwind CSS
      {
        test: /\.css$/,
        use: [
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  'tailwindcss',
                  'autoprefixer',
                ],
              },
            },
          },
        ],
        type: 'css',
      },
    ],
  },

  // For production — CSS is extracted by default
  // For development — CSS is injected via style tags for HMR
  experiments: {
    css: true,  // Enable native CSS support (default in Rspack)
  },
};

If you prefer the webpack-style MiniCssExtractPlugin approach:

const rspack = require('@rspack/core');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          rspack.CssExtractRspackPlugin.loader,
          'css-loader',
          'postcss-loader',
        ],
      },
    ],
  },
  plugins: [
    new rspack.CssExtractRspackPlugin({
      filename: 'css/[name].[contenthash].css',
    }),
  ],
};

Fix 3: React Fast Refresh

HMR for React requires the Rspack-specific refresh plugin:

npm install -D @rspack/plugin-react-refresh react-refresh
// rspack.config.js
const ReactRefreshPlugin = require('@rspack/plugin-react-refresh');

const isDev = process.env.NODE_ENV === 'development';

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'builtin:swc-loader',
        options: {
          jsc: {
            parser: { syntax: 'typescript', tsx: true },
            transform: {
              react: {
                runtime: 'automatic',
                development: isDev,
                refresh: isDev,  // Enable refresh transform in dev
              },
            },
          },
        },
      },
    ],
  },
  plugins: [
    isDev && new ReactRefreshPlugin(),
  ].filter(Boolean),
  devServer: {
    hot: true,
  },
};

Fast Refresh won’t work if:

  • Component files export non-component values (e.g., constants alongside components)
  • Components are wrapped in React.memo at the export level in some edge cases
  • The file uses module.hot.accept() manually — remove it and let the plugin handle it
  • Class components are used — Fast Refresh only works with function components and hooks

Fix 4: Migrate from webpack

Most webpack configs work with minimal changes:

// webpack.config.js → rspack.config.js — what to change

// BEFORE (webpack)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  module: {
    rules: [
      { test: /\.tsx?$/, use: 'ts-loader' },
      { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' }),
    new MiniCssExtractPlugin(),
    new CopyWebpackPlugin({ patterns: [{ from: 'public' }] }),
  ],
};

// AFTER (rspack)
const rspack = require('@rspack/core');

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        // Replace ts-loader with built-in SWC
        loader: 'builtin:swc-loader',
        options: {
          jsc: {
            parser: { syntax: 'typescript', tsx: true },
            transform: { react: { runtime: 'automatic' } },
          },
        },
      },
      {
        test: /\.css$/,
        // Replace css-loader + MiniCssExtractPlugin with built-in
        type: 'css',
      },
    ],
  },
  plugins: [
    // HtmlWebpackPlugin → built-in HtmlRspackPlugin
    new rspack.HtmlRspackPlugin({ template: './public/index.html' }),
    // CopyWebpackPlugin → built-in CopyRspackPlugin
    new rspack.CopyRspackPlugin({
      patterns: [{ from: 'public', globOptions: { ignore: ['**/index.html'] } }],
    }),
  ],
};

Loader compatibility quick reference:

webpack LoaderRspack Equivalent
babel-loaderbuiltin:swc-loader (built-in)
ts-loaderbuiltin:swc-loader (built-in)
css-loader + style-loadertype: 'css' (built-in)
file-loader / url-loadertype: 'asset' (built-in)
sass-loadersass-loader (still needed)
postcss-loaderpostcss-loader (still needed)
svg-inline-loadertype: 'asset/source'

Fix 5: Module Federation

Rspack supports Module Federation v1.5 natively:

// rspack.config.js — host application
const rspack = require('@rspack/core');

module.exports = {
  plugins: [
    new rspack.container.ModuleFederationPlugin({
      name: 'host',
      remotes: {
        // Remote app available at runtime
        remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
      },
    }),
  ],
};

// rspack.config.js — remote application
module.exports = {
  plugins: [
    new rspack.container.ModuleFederationPlugin({
      name: 'remoteApp',
      filename: 'remoteEntry.js',
      exposes: {
        './Button': './src/components/Button',
        './Header': './src/components/Header',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
      },
    }),
  ],
};
// In host app — import remote component
const RemoteButton = React.lazy(() => import('remoteApp/Button'));

function App() {
  return (
    <Suspense fallback="Loading...">
      <RemoteButton />
    </Suspense>
  );
}

Fix 6: Build Performance Tuning

Rspack is fast by default, but you can optimize further:

module.exports = {
  // Source maps — choose based on need
  devtool: process.env.NODE_ENV === 'production'
    ? 'source-map'          // Full source maps for production debugging
    : 'cheap-module-source-map',  // Faster for dev

  // Caching — persistent cache across builds
  cache: true,  // Simple boolean or configure as object

  // Optimization
  optimization: {
    // Split vendor chunks
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all',
        },
      },
    },
    // Tree shaking — on by default in production
    usedExports: true,
    sideEffects: true,
    // Minimize — uses SWC minifier (faster than terser)
    minimize: process.env.NODE_ENV === 'production',
  },

  // Resolve — limit resolution scope
  resolve: {
    extensions: ['.ts', '.tsx', '.js'],  // Don't add unnecessary extensions
    modules: ['node_modules'],           // Don't search upward
  },

  // Stats — reduce build output noise
  stats: 'errors-warnings',
};

Compare build times:

# Measure build performance
npx rspack build --profile

# Analyze bundle size
npx rspack build --analyze
# Opens a bundle analyzer in the browser

Still Not Working?

builtin:swc-loader throws “unexpected token” on decorators — SWC needs decorator support enabled explicitly. Add jsc.parser.decorators: true and jsc.transform.legacyDecorator: true to your builtin:swc-loader options. Make sure experimentalDecorators is also set in your tsconfig.json.

Webpack plugin X doesn’t work with Rspack — not all webpack plugins are compatible. Plugins that use compiler.hooks extensively (e.g., webpack-bundle-analyzer, ForkTsCheckerWebpackPlugin) may need Rspack-specific alternatives. Check @rspack/ scoped packages first. For webpack-bundle-analyzer, use Rspack’s built-in --analyze flag instead.

Dev server starts but page is blank — check that devServer.historyApiFallback: true is set if you’re using client-side routing. Also verify the output.publicPath matches your dev server setup. The default / works for most cases, but if your app is served from a subdirectory, set it explicitly.

CSS @import in type: 'css' doesn’t resolve node_modules — by default, Rspack’s built-in CSS resolves @import relative to the file. For @import 'package-name/styles.css', prefix with ~: @import '~package-name/styles.css'. Or switch to postcss-loader with postcss-import which resolves node_modules automatically.

For related build tool issues, see Fix: esbuild Not Working and Fix: Webpack Bundle Size Too Large.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles