Webpack just got an update, and it's fast. Intro to Rspack and migration.

Webpack just got an update, and it's fast. Intro to Rspack and migration.

ยท

7 min read

If you're a frontend developer and have been working on React you must know that Webpack is the core of React and bundling the assets.

We use webpack in our day-to-day work, you might not know it yet. Most of us still use CRA(create react app) simple tool to create and run react apps which are built on top webpack. CRA uses webpack and I know it feels slow and compute-intensive too.

Webpack is being used by many popular frameworks out there and it is a fully matured and community-supportive bundler.

So, What is the problem?!

We, developers want to make our websites lighter & faster. But why not development speed and iterations on the codebase? This is where webpack lacks support, even though it supports many features that one can ask for, it was built in Javascript and it's not fast, maybe not for you :P. Whatever the work I have been doing and the codebase I have been working is large and I've been waiting for a full-fledged bundler that is fast, simple to migrate and gonna be the next webpack replacer.

PS: I love webpack, and I still do but it's ok to look at other options if you're in need :)

Solution?!

I have been looking over multiple promising projects over the past year and tried all of them.

The first promising thing that I found is SWC(spdy-web-compiler), built with rust. But it's not a replacer for webpack unfortunately :(

Next, I have worked with Vite, I have been using vite and it is speedy and better than webpack.

Multiple bundlers are being built open-source and they're also promising.

TurboPack -> by vercel, even webpack creator is also part of the team building it :) and it's announced as the next version of webpack. It's so promising would love to work on it once it's stable.

Rome -> Rome wants to replace all the tools we're currently using like linter, Formatter, bundler, transpiler etc. Rome is a unified framework that does multiple things at a time. It is also built in Rust.

What is Rspack?!

Rspack is stable for use, for plugin development they're not yet stable, use with caution :)

Except for vite all the others are in the testing/building stage. A week back team from bytedance released a new bundler Rspack :)

I feel they're true replacer for webpack maybe for some time till the market goes up and introduce more tools like this :xD

I have seen the performance of rspack and it is fast.

The codebase I have worked with is taking > 1min to cold-start (no-eslint checking) and sometimes more than 5min to produce a production build and I'm using M1 mac with 16gb ram. I feel stuck whenever there is a build that needs to be done in my system(sometimes we need to build the code in our system, we use CI/CD as well).

With Vite we were able to reduce the build time to 12min from 25min, I feel with rspack we can make it around <5min.

I have integrated Rspack with our codebase and it's fast it took around 10sec to produce the production build.

I know it seems and feels heavy to shift a new bundler at the production level, but rspack supports all the major features that are supported by webpack which mostly startups and small websites need and need to speed up their development speed.

Migrating to the Rspack.

Believe me, it's easier than you think :).

This guide is for the projects which are based on CRA, if you're on vite, I need some time to experiment and get back to you guys

Step 1:

Create a config file for rspack which is rspack.config.js at the root of the application.

As every config expects rspack does also expects the same, an object exported default in rspack.config.js

Our Initial file state follows below:

module.exports = {
    // Here our config goes :)
}

Step 2:

define the entry file for the application where our web app is starting, usually, it will be ./src/index.(js|ts)x.

Config will be

module.exports = {
    entry: {
        main: './src/index.tsx',
    },
}

Our entry has been defined, and we know that CRA is SPA(Single Page Application) which will have an index.html and all the app's entry point is that.

We need to handle our index.html file in rspack so that it will be using the entry.main file served at the client side to display the react UI.

Rspack have an integrated HTML plugin implemented in default and it's easy too :)

Since it's a built-in plugin they included the config under the same key as well.

Maybe not :)

Updated Config

module.exports = {
    entry: {
        main: './src/index.tsx',
    },
    builtins: {
        html: [{ template: './public/index.html' }], // html file location relative to config file
    }
}

CRA used %PUBLIC_URL% variable in html to handle assets related to the public folder, we need to remove that %PUBLIC_URL% and make it relative to the public folder.

Ex:
In CRA -> %PUBLIC_URL%/favicon.ico

In Rspack -> /favicon.ico should do the work.


Step 3:

A website must consist of multiple static assets like images, icons, fonts etc. To handle all those in rspack we need to provide a rule for rspack to load them as assets into the build.

Config will be

module.exports = {
    entry: {
        main: './src/index.tsx', // Entry file
    },
    builtins: {
        html: [{ template: './public/index.html' }], // html file location relative to config file
    }
    rules: [
        {
        test: /\.(png|svg|jpg|gif|webp)$/, // These all are I need :)
        type: 'asset/resource',
        }
    ]
}

If you're using some css pre-processors like LESS or SCSS rspack does have default support for it, all you need to provide the config.

I have the need of LESS, the config follows below:

module.exports = {
    entry: {
        main: './src/index.tsx', // Entry file
    },
    builtins: {
        html: [{ template: './public/index.html' }], // html file location relative to config file
    }
    rules: [
        {
        test: /\.(png|svg|jpg|gif|webp)$/, // These all are I need :)
        type: 'asset/resource',
        },
        {
        test: /\.less$/,
        use: [
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                modifyVars: {
                  // Options
                },
                javascriptEnabled: true,
              },
            },
          },
        ],
        type: 'css', // This is must, which tells rspack this is type of css resources
      },
    ]
}

Step 4:

last, but not final

I think many of us use typescript and typescript features like paths to simplify their imports and make code look cleaner.

Same as with Monorepos to simplify and break the into modules and sub-packages.

What about them? I think there seems less/no support for the paths or sub-packages with whatever I tried, I don't find it simple to use them without changing the config or reading the config from tsconfig.json.

So, let's change the config.

To tell rspack that we're using a few imports bases on paths and some are sub-packages we need to provide alias to the rspack config.

Config follows:

module.exports = {
    entry: {
        main: './src/index.tsx', // Entry file
    },
    resolve: {
        alias: {
            container: path.resolve(__dirname, './src/container'),
            components: path.resolve(__dirname, './src/components'),
            // Alais to the imports and structure you follows based on `tsconfig.json`, we just use `baseUrl` which will produce imports as `components/**/*`
        "sub-package": path.resolve(__dirname, "../path-to/sub-pacakge") // Sub-package in case of monorepo
        }
    }
    builtins: {
        html: [{ template: './public/index.html' }], // html file location relative to config file
    }
    rules: [
        {
        test: /\.(png|svg|jpg|gif|webp)$/, // These all are I need :)
        type: 'asset/resource',
        },
        {
        test: /\.less$/,
        use: [
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                modifyVars: {
                  // Options
                },
                javascriptEnabled: true,
              },
            },
          },
        ],
        type: 'css', // This is must, which tells rspack this is type of css resources
      },
    ]
}

This is it, till here everything solves and should do that work, if not something is missing in the config, maybe node polyfills?

Yes, sometimes the packages we use, use the node's internal modules like process,os or path which the browser doesn't support.! Here comes the node polyfills package by rspack team :)

npm install -D @rspack/plugin-node-polyfill using this will solve issues like

require('path') not found or undefined
require("process") not found or undefined

Okay, there's one last thing to talk about, the server :). Webpack is known for HMR or its dev mode, which rspack does provide by default.

To make it more custom, we can define the port of the server, WebSocket provider, fallback on 404 etc.

Sample Config follows:

module.exports = {
    /// base config
    devServer: {
        port: 3000, // Port to run the dev-server
        hot: true, // HMR
        historyApiFallback: true, // React router v5 might need it, in case there is not route found(try navigate to nest route and refesh without this), will be redirected to `index.html` which should solve the issue.
        static: true, // Serving static files (public folder in default)
  },
}

I think I covered most cases and I feel it is simple when compared to other bundlers(vite).

If you face any issues in migrating/integrating with rspack, do reach out to me would love to help :).

Results :)

With Webpack

With Rspack

Resources

Announcing Rspack

rspack

Resolve Alias

HTML Config

Hope this article helped you in learning about new things and made your web development faster :)

Thanks for reading ๐Ÿ™๐Ÿป๐Ÿ™Œ

Did you find this article valuable?

Support Mahesh Vagicherla by becoming a sponsor. Any amount is appreciated!

ย