Frontend Development 23 min read

Design and Exploration of a Rust-Based Web Bundler: Insights from Rspack, Webpack, Rollup, and Esbuild

The article chronicles the technical background, challenges, and design decisions behind building a Rust-powered web bundler, comparing it with existing tools like Webpack, Vite, Rollup, and esbuild, and outlines future directions for improving plugin APIs, AST reuse, and build performance.

ByteDance Web Infra
ByteDance Web Infra
ByteDance Web Infra
Design and Exploration of a Rust-Based Web Bundler: Insights from Rspack, Webpack, Rollup, and Esbuild

In March this year the team released Rspack, a ByteDance‑developed web build tool, after extensive experience with webpack, Vite, esbuild, Rollup and other bundlers while maintaining a suite of internal Infra tools such as Modernjs Builder, Garfish, Modernjs Framework, PIA, Module Tools, Rspress, Lynx Speedy, and Web Doctor.

The Infra team faces heavy on‑call pressure because many user issues stem from the underlying build system, and they must balance low‑cost maintenance of diverse solutions (SSR, micro‑frontend, etc.) with rapid business response.

Webpack offers strong extensibility but suffers from poor debugging, black‑box behavior, and performance limits despite many optimizations (swc‑loader, cache‑loader, Persistent Cache, etc.). Vite’s dual‑engine approach reduces some pain points but introduces plugin‑reuse difficulties across Rollup and webpack, and its performance on large projects is still lacking.

Rollup provides clean ESM‑centric output and good tree‑shaking but struggles with CommonJS compatibility and lacks persistent caching and HMR, making it less suitable for large‑scale library builds.

esbuild solves Rollup’s CommonJS and performance issues but its minimal API hampers complex plugin development, leading to challenges in transform pipelines, rebuild performance, HMR support, and runtime extensions.

Initially the team attempted a Rust version of esbuild/rollup with built‑in HMR, CommonJS, and bundle‑splitting support, but practical experience pushed them toward a webpack‑style architecture.

Rust Bundler Exploration

The Rust bundler aims to keep compatibility with esbuild’s API while adding missing features such as HMR and bundle splitting. Early prototypes based on Rollup exposed many problems, prompting a shift to a webpack‑like design.

Plugin API Design

The core requirement is a JavaScript‑written plugin system that balances performance and composability. Rollup’s single transform hook mixes filter, transformer, and module‑type conversion, causing high Rust‑JS communication overhead and loss of flexibility.

Example of an esbuild onLoad hook:

build.onLoad({ filter: /.txt$/ }, async (args) => {
  let text = await fs.promises.readFile(args.path, 'utf8');
  return {
    contents: JSON.stringify(text.split(/\s+/)),
    loader: 'json',
  };
});

Parcel’s plugin model separates filter, transformer, and type change, illustrated by its transformer configuration and code:

{
  "transformers": {
    "icons/*.svg": ["@company/parcel-transformer-svg-icons", "..."],
    "*.svg": ["@parcel/transformer-svg"]
  }
}

Webpack’s rule‑based system also cleanly separates these concerns:

module: {
  rules: {
    test: /.svgr/,
    use: ['@svgr/webpack']
  }
}

After evaluating these models, the team concluded that webpack’s architecture best satisfies their performance and customization needs, especially given the team’s familiarity with it.

AST Reuse

Reusing ASTs across transforms can dramatically reduce parse overhead. esbuild shares a single AST for parse, transform, and minify. Rollup can return ESTree ASTs from load/transform hooks. Parcel provides sophisticated AST‑reuse mechanisms for both string‑to‑string and AST‑to‑AST pipelines. Webpack can return ESTree ASTs from loaders but community loaders often do not conform, limiting practical reuse.

Future Vision

The roadmap includes moving beyond a pure webpack drop‑in replacement, improving out‑of‑the‑box developer experience, enhancing diagnostics via Web Doctor, exploring function‑level optimizations for bundle splitting and tree shaking, and implementing portable and remote build caches for large monorepos.

References are provided for build dependencies, unplugin, rollup commonjs options, tsup, tsdx, rollup hash dilemma, incremental build performance, Remix HMR, legacy code, @svgr/core, vite‑plugin‑svgr, Parcel transform plugin, inlineMatchResource, virtual resource, and AST reuse.

rustwebpackesbuildBundlerplugin APIAST reuse
ByteDance Web Infra
Written by

ByteDance Web Infra

ByteDance Web Infra team, focused on delivering excellent technical solutions, building an open tech ecosystem, and advancing front-end technology within the company and the industry | The best way to predict the future is to create it

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.