Webpack and Other Bundlers
Vite is the default choice for new projects, but it is not the only bundler. Webpack was the most widely used bundler for years, and esbuild, Parcel, and Rollup are each good at something.
Setting Up Webpack
Webpack has a lot of configuration options and a large plugin ecosystem. The trade-off is that it takes more setup than Vite.
npm install webpack webpack-cli --save-dev
A minimal config tells Webpack where to start and where to write output:
// webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
mode: "development", // or 'production'
};
Loaders
Webpack only understands JavaScript files by default. Loaders let it process other file types, such as transpiling modern syntax with Babel or importing CSS.
// webpack.config.js (module.rules section)
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: { presets: ["@babel/preset-env"] },
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.(png|jpg|gif)$/,
type: "asset/resource",
},
],
},
};
Each rule matches files by extension (test) and applies one or more loaders to transform them before bundling.
Plugins
Loaders transform individual files. Plugins work on the whole bundle. A common example is generating an HTML file that automatically includes your bundled scripts:
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
Code Splitting
For larger apps, you do not want to ship one big bundle. Webpack can split your code into separate chunks that load on demand, using dynamic imports:
// Dynamic import creates a separate chunk
const module = await import("./heavy-module.js");
esbuild
esbuild is written in Go and is very fast, often much faster than Webpack on comparable tasks. It works well for simple builds, or as a low-level tool that other toolchains build on.
# Bundle and minify in one command
npx esbuild src/app.js --bundle --minify --outfile=dist/bundle.js
The trade-off is a smaller plugin ecosystem and fewer built-in features than Webpack.
Parcel
Parcel takes the opposite approach from Webpack: it requires zero configuration. Point it at your HTML file and it works out the configuration on its own:
{
"scripts": {
"dev": "parcel src/index.html",
"build": "parcel build src/index.html"
}
}
Parcel automatically handles TypeScript, CSS preprocessors, images, and HMR. It works well for quick prototypes where you do not want to write config files.
Rollup
Rollup is designed for building libraries rather than applications. It works with ES modules directly, so the output is smaller and easier to read. Many modern tools also use Rollup-compatible plugin and config concepts, including Vite’s production pipeline.
// rollup.config.js
export default {
input: "src/index.js",
output: {
file: "dist/bundle.js",
format: "esm", // or 'cjs', 'umd', 'iife'
},
};
Comparing the Bundlers
| Tool | Best For | Speed | Configuration |
|---|---|---|---|
| Vite | Modern web apps | Very fast | Minimal |
| Webpack | Complex apps, legacy | Moderate | Extensive |
| esbuild | Speed-critical builds | Fastest | Minimal |
| Parcel | Quick prototypes | Fast | Zero config |
| Rollup | Libraries | Fast | Moderate |