I tried replacing Webpack with Rspack and here’s what I’ve found

Eason Lin
5 min readJul 29, 2023

--

While working as a frontend web developer, we usually use building tools like Webpack to bundle our code so that browsers can understand it. Webpack is powerful and provides all the necessary features. However, what if there’s an alternative that can perform a similar job but with faster build times?

Recently, I spent some time reading Rspack’s official documentation. Its low setup cost, user-friendly interface for Webpack users, and faster build times are all highly appealing to me.

Taking advantage of a relatively idle work period, I applied Rspack to our company’s project, and the results were quite impressive. In this article, I would like to share our project’s frontend architecture and compare the build speeds between Rspack and Webpack, hoping that this article will be helpful to someone.

TL;DR: if you’re using Webpack with custom configs, you should try replacing it with Rspack, it would save tons of your waiting time.

The Webpack config of my work project

Before we compare the performance between Rspack and Webpack, let me show you how we configure our Webpack to build CSS and JavaScript files.

Here’s the webpack.config.js of our project:

const path = require('path');
const glob = require('glob');
const toObject = require('./scripts/toObject');
const { VueLoaderPlugin } = require("vue-loader");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries");

module.exports = (env, options) => {
const jsSetting = {
mode: 'production',
entry: {
'index': path.resolve(__dirname, 'src/js/entry/index.js'),
},
output: {
path: path.resolve(__dirname, 'apps/statics/dist/'),
filename: 'js/[name].js',
},
target: ['web', 'es5'],
module: {
rules: [
{
test: /\.m?js$/,
include: path.resolve(__dirname, 'src'),
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
plugins: ['@babel/plugin-transform-runtime']
}
}
],
},
{
test: /\.vue$/,
use: [
'vue-loader'
]
},
{
test: /\.s?css$/i,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
],
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
name: '[path][name].[ext]',
context: 'src',
fallback: require.resolve('file-loader'),
limit: 8192,
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf|)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
context: 'src'
},
},
],
},
],
},
plugins: [
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: 'style/[name].css',
}),
new CleanWebpackPlugin({ verbose: true }),
],
resolve: {
alias: {
src: path.resolve(__dirname, 'src/'),
apps: path.resolve(__dirname, 'apps/'),
}
},
externals: {
vue: 'Vue',
axios: 'axios',
jquery: 'jQuery',
}
};
const cssSetting = {
mode: 'production',
entry: {
...toObject(glob.sync('apps/statics/scss/**/*.scss')),
},
output: {
path: path.resolve(__dirname, ''),
},
module: {
rules: [
{
test: /\.s?css$/i,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { url: false }},
'postcss-loader',
{
loader: 'sass-loader',
options: {
implementation: require("sass"),
sassOptions: {
outputStyle: 'expanded'
}
}
}
],
},
],
},
plugins: [
new FixStyleOnlyEntriesPlugin(),
new MiniCssExtractPlugin({}),
],
resolve: {
alias: {
src: path.resolve(__dirname, 'src/'),
apps: path.resolve(__dirname, 'apps/'),
}
},
};

if (options.mode == 'development') {
jsSetting.devtool = 'eval-source-map'
}
return [
cssSetting,
jsSetting,
];
};

To simplify the content, I have removed most of the files in the entry and retained only the necessary parts for illustration purposes.

In our project, we firstly build CSS, then JavaScript. For css files, we use a library called glob to detect all of the .scss files. toObject is a custom function for generating key-value pairs like this:

{
"apps/statics/scss/index": "apps/statics/scss/index.scss",
// ...
}

We use MiniCssExtractPlugin for generating the output .js files css-loader made into .css, and delete the same .js files by FixStyleOnlyEntriesPlugin so that we can built .scss files into .css files right at the same folder.

for JavaScript files, we use vue-loader for building Vue SFC, vue-style-loader, css-loader and sass-loaderenableus to write scss in .vue files, and we use babel-loader for building JavaScript files.

So basically those are the things we need for our project:

  • Building Vue SFC files
  • Building CSS files from SCSS files
  • Building JavaScript files

Let’s see how we configure our Rspack settings.

My Rspack setting

Here’s my rspack.config.js:

const path = require("path");
const glob = require("glob");
const toObject = require("./scripts/toObject");
const { VueLoaderPlugin } = require("vue-loader");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const PreventOutputJSPlugin = require("./scripts/PreventOutputJSPlugin");
module.exports = (env, options) => {
const isProd = options.mode === "production";
const cssSetting = {
mode: "development",
context: __dirname,
devtool: false,
entry: {
...toObject(glob.sync("apps/statics/scss/**/*.scss")),
},
output: {
path: path.resolve(__dirname, ""),
},
module: {
rules: [
{
test: /\.scss$/,
use: ["postcss-loader", "sass-loader"],
type: "css",
},
],
},
plugins: [new PreventOutputJSPlugin()],
resolve: {
alias: {
src: path.resolve(__dirname, "src/"),
apps: path.resolve(__dirname, "apps/"),
},
},
optimization: {
minimize: false,
},
};
const jsSetting = {
context: __dirname,
devtool: false,
entry: {
index: path.resolve(__dirname, "src/js/entry/index.js"),
},
output: {
path: path.resolve(__dirname, "apps/statics/dist/"),
filename: "js/[name].js",
},
target: ["web", "es5"],
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader",
options: {
experimentalInlineMatchResource: true,
},
},
{
test: /\.scss$/,
use: [
{
loader: "style-loader",
options: {
esModule: false,
},
},
"css-loader",
"postcss-loader",
"sass-loader",
],
type: "javascript/auto",
},
{
test: /\.css$/,
use: [
{
loader: "style-loader",
options: {
esModule: false,
},
},
"css-loader",
],
type: "javascript/auto",
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
type: "asset/inline",
},
{
test: /\.(woff|woff2|eot|ttf|otf|)$/,
type: "asset/resource",
},
],
},
plugins: [new VueLoaderPlugin()],
resolve: {
alias: {
src: path.resolve(__dirname, "src/"),
apps: path.resolve(__dirname, "apps/"),
node_modules: path.resolve(__dirname, "node_modules/"),
},
},
externals: {
vue: "Vue",
axios: "axios",
jquery: "jQuery",
},
optimization: {
minimize: isProd,
},
};
if (isProd) {
jsSetting.plugins.push(new CleanWebpackPlugin({ verbose: true }));
}
return [cssSetting, jsSetting];
};

For CSS files, we don’t need css-loader nor MiniCssExtractPlugin to build .scss.

For JavaScript files, most of the configs where same as before.

There’re about 40 JavaScript files and 90 CSS files need to be built in our project, and let’s see the building performance:

Webpack

  • Starts dev server: 35s
  • Production build: 42s
  • Dev server hot build time: ~300ms

Rspack

  • Starts dev server: 15s
  • Production build: 15s
  • Dev server hot build time: ~170ms

As you can see, RSPack outperforms Webpack in various scenarios.

Did I replace Webpack with Rspack already?

I really want to retire Webpack to save my precious time. However, in our project, we would configure our css-loader not to resolve the urls in our .scss files:

{ loader: 'css-loader', options: { url: false }}

And the current version of Rspack (v0.2.9) does not support it yet. Though it still builds far faster than Webpack, it’ll also leave tons of error messages on our terminal. After discussing with my team members, we decide not to replace it for now. I’ve reported it as a feature request to Rspack’s Github issues, and hope this feature could be avaiable soon.

Conclusion

As I mentioned in the beggining, Rspack really does a good job building CSS and JavaScript files comparing with Webpack, and it won’t cost a lot of times migrating from Webpack. So if you want to reduce your building time, don’t hesitate, try it!

I hope this article helps, and if you have any suggestions, please let me know. See you next month!

References:

--

--

Eason Lin
Eason Lin

Written by Eason Lin

Frontend Web Developer | Books

No responses yet