Rspack, Webpack, and Vite: Pick One and Move On
Why the choice of build tool matters less than you think — and what workspaces cannot solve on their own.
After seeing both an Rsbuild config (for the runtime federation example) and a Vite config (for the build-time monorepo), the difference is smaller than it looks. The fundamentals of what each does are identical. The syntax and performance characteristics differ; the concepts don't.
The Honest Comparison
For module federation specifically, you need a plugin. Every major build tool has one:
- Webpack:
@module-federation/webpack-plugin— the original, battle-tested - Rsbuild/Rspack:
@module-federation/rsbuild-plugin— Webpack semantics, Rust performance - Vite:
@originjs/vite-plugin-federation— same ideas, Vite-native
For a monorepo without runtime federation, any of them work. Vite's TypeScript transpilation is why the build-time composition example dropped the module federation config entirely — you don't need it. The workspace resolution handles the package linking, Vite handles the bundling, and the configs look nearly identical to a single-app project.
Package Manager Workspaces: They're All Similar
The same story applies to package managers. npm, pnpm, and Bun all support workspaces. The differences are mostly syntactic:
| Feature | npm | pnpm | Bun |
|---|---|---|---|
| Workspace definition | package.json workspaces field | pnpm-workspace.yaml | package.json workspaces field |
| Filter flag | --workspace | --filter (git-aware) | --filter |
| Strictness | Loose — allows phantom deps | Strict — hoists carefully | Configurable |
| Lockfile | package-lock.json | pnpm-lock.yaml | bun.lockb |
The pnpm --filter flag is worth knowing. It's git-aware and graph-aware — you can run scripts only on packages changed since a certain commit, or only on packages that depend on a changed package. That capability matters for large repos where you want CI to be selective.
pnpm is also stricter about phantom dependencies — packages you use but haven't declared. npm is more permissive and will let you import something that happens to be a transitive dependency. pnpm prevents this, which is painful when you first encounter it and valuable in the long run.
If you're already using one of these, the switching cost is real and rarely worth it just for marginal workspace features. The ideas apply regardless of the tool.
What Workspaces Still Don't Solve
After setting up workspaces, you're left with the same two problems:
Build ordering. If ui needs to compile before dashboard can build, nothing in the workspace tooling enforces that automatically. pnpm -r build runs builds recursively but won't figure out the right order unless you configure it explicitly.
Selective execution. pnpm -r test runs every test in every package. A one-line change to a utility function kicks off the full Playwright suite for every team. That's the CI time problem in a different costume.
Workspaces give you the package resolution. They don't give you the intelligence about what's changed, what depends on what, and what can be skipped. That's the problem Turborepo (and Nx, and Bazel) exist to solve.
The next section is where the monorepo goes from "organized" to "actually fast."
Keep reading
Enjoyed this? Get more like it.
Deep dives on system design, React, web development, and personal finance — straight to your inbox. Free, always.