As developers, we all value two things: performance and control over our code. This is why we often debate whether to use Webpack or Vite. Webpack, with over a decade of history, offers a highly customizable solution and has a strong community support. Vite is simpler to use, provides an almost zero-config solution in many cases, and is also highly performant.
I have experience working with both Webpack and Vite on various projects, and I’ve found that in many cases, Vite may be the best choice.
But first, let’s see how they compare.
Webpack
Configuration
You can find a simple Webpack configuration example generated by createapp.dev on GitHub. I used a bit of AI to create this configuration because, let’s face it, if you don’t use AI these days, are you even a developer (pun intended)? However, I’m also a bit lazy, so this example is simple but sufficient for our proof of concept.
Below are the package.json
and webpack.config.js
files that set up Webpack:
{ "name": "webpack-config", "version": "1.0.0", "description": "", "main": "index.js", "keywords": [], "author": "", "license": "ISC", "scripts": { "clean": "rm dist/bundle.js", "build-dev": "webpack --mode development", "build-prod": "webpack --mode production" }, "dependencies": { "tailwindcss": "^3.4.7" }, "devDependencies": { "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "autoprefixer": "^10.4.20", "babel-loader": "^9.1.3", "css-loader": "^7.1.2", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.6.0", "mini-css-extract-plugin": "^2.9.0", "postcss-loader": "^8.1.1", "prettier": "^3.3.3", "sass": "^1.77.8", "sass-loader": "^16.0.0", "style-loader": "^4.0.0", "ts-loader": "^9.5.1", "typescript": "^5.5.4", "url-loader": "^4.1.1", "webpack": "^5.93.0", "webpack-cli": "^5.1.4" }}
const webpack = require("webpack");const path = require("path");const HtmlWebpackPlugin = require("html-webpack-plugin");const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const config = { entry: "./src/index.ts", output: { path: path.resolve(__dirname, "dist"), filename: "[name].[contenthash].js", }, module: { rules: [ { test: /\.js$/, use: "babel-loader", exclude: /node_modules/, }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: { importLoaders: 1, }, }, "postcss-loader", ], }, { test: /\.ts(x)?$/, loader: "ts-loader", exclude: /node_modules/, }, { test: /\.scss$/, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], }, { test: /\.svg$/, use: "file-loader", }, { test: /\.png$/, use: [ { loader: "url-loader", options: { mimetype: "image/png", }, }, ], }, ], }, resolve: { extensions: [".tsx", ".ts", ".js"], }, plugins: [ new HtmlWebpackPlugin({ templateContent: ({ htmlWebpackPlugin }) => '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' + htmlWebpackPlugin.options.title + '</title></head><body><div id="app"></div></body></html>', filename: "index.html", }), new MiniCssExtractPlugin(), ], optimization: { runtimeChunk: "single", splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all", }, }, }, },};
module.exports = config;
As we can see, this setup requires 19 dependencies and 90 lines of code in the Webpack config file.
Size and Performance
Running npm run build-prod
on my machine (a MacBook Pro with an Apple M1 Pro chip) produced these results:
assets by chunk 11.7 KiB (name: main) asset main.css 11.1 KiB [emitted] (name: main) asset main.ad88b4ed4a59346d5aa1.js 606 bytes [emitted] [immutable] [minimized] (name: main)asset runtime.84fe7964e40459f6d228.js 912 bytes [emitted] [immutable] [minimized] (name: runtime)asset index.html 296 bytes [emitted]Entrypoint main 12.6 KiB = runtime.84fe7964e40459f6d228.js 912 bytes main.css 11.1 KiB main.ad88b4ed4a59346d5aa1.js 606 bytesorphan modules 14.6 KiB (javascript) 1.83 KiB (runtime) [orphan] 14 modulesruntime modules 2.48 KiB 3 modulescacheable modules 569 bytes (javascript) 11.1 KiB (css/mini-extract) ./src/index.ts 569 bytes [built] [code generated] css ./node_modules/.pnpm/css-loader@7.1.2_webpack@5.93.0/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].use[1]!./node_modules/.pnpm/postcss-loader@8.1.1_postcss@8.4.40_typescript@5.5.4_webpack@5.93.0/node_modules/postcss-loader/dist/cjs.js!./src/styles.css 10.1 KiB [built] [code generated] css ./node_modules/.pnpm/css-loader@7.1.2_webpack@5.93.0/node_modules/css-loader/dist/cjs.js!./node_modules/.pnpm/sass-loader@16.0.0_sass@1.77.8_webpack@5.93.0/node_modules/sass-loader/dist/cjs.js!./src/styles.scss 1.02 KiB [built] [code generated]webpack 5.93.0 compiled successfully in 1038 ms
Webpack compiles in about 1 second, producing a CSS bundle of 11 KiB and a JavaScript bundle of 606 bytes.
Vite
Configuration
Now, let’s compare this with a similar Vite configuration.
You can find a simple Vite configuration example on GitHub. Yes, it was also generated by AI. AI is everywhere these days, it may even steal our jobs one day. Has anyone said that yet?
Here are the package.json
and vite.config.js
files for Vite:
{ "name": "vite-config", "version": "1.0.0", "description": "", "main": "index.js", "keywords": [], "author": "", "license": "ISC", "scripts": { "dev": "vite", "build": "vite build", "serve": "vite preview" }, "dependencies": { "tailwindcss": "^3.4.7" }, "devDependencies": { "@vitejs/plugin-legacy": "^5.4.1", "autoprefixer": "^10.4.20", "postcss": "^8.4.40", "sass": "^1.77.8", "typescript": "^5.5.4", "vite": "^5.3.5" }}
import { defineConfig } from "vite";import path from "path";
export default defineConfig({ resolve: { alias: { "@": path.resolve(__dirname, "./src"), }, }, css: { preprocessorOptions: { scss: {}, }, }, build: { outDir: "dist", },});
With Vite, we only need 7 dependencies and 18 lines of code in the configuration file. This represents a reduction of over half the dependencies and nearly 80% fewer lines of code compared to Webpack.
Size and Performance
Running npm run build
produced these results:
✓ 5 modules transformed.dist/index.html 0.39 kB │ gzip: 0.27 kBdist/assets/index-B2adr4Ei.css 6.15 kB │ gzip: 1.88 kBdist/assets/index-CnDDn-85.js 1.18 kB │ gzip: 0.55 kB✓ built in 303ms
Vite compiles in 0.3 seconds, generating a CSS bundle of 6.15 KiB and a JavaScript bundle of 1.18 KiB. This means that Vite is more than 3 times faster than Webpack and produces significantly smaller bundles.
Real-World Example
The above comparison is based on a simple proof of concept, but let’s consider a real-world scenario. At DEside, we migrated from Webpack to Vite in one of our WordPress projects. For confidentiality reasons, we can’t share the exact code, but we can discuss the results.
Webpack Size and Performance
assets by path images/ 345 KiB assets by path images/*.svg 34.6 KiB 4 assets assets by path images/*.jpeg 275 KiB 2 assets asset images/214309fe3a452007cc0f.png 36 KiB [emitted] [immutable] [from: images/favicon-admin.png] (auxiliary name: wp-admin-css)assets by path *.js 128 KiB asset main.js 128 KiB [emitted] [minimized] (name: main) asset wp-admin-css.js 0 bytes [emitted] [minimized] (name: wp-admin-css) asset wp-admin-palette.js 0 bytes [emitted] [minimized] (name: wp-admin-palette) asset wp-login-css.js 0 bytes [emitted] [minimized] (name: wp-login-css)assets by path *.css 136 KiB asset main.css 111 KiB [emitted] (name: main) asset wp-admin-palette.css 12.6 KiB [emitted] (name: wp-admin-palette) asset wp-login-css.css 7.21 KiB [emitted] (name: wp-login-css) asset wp-admin-css.css 5.21 KiB [emitted] (name: wp-admin-css)Entrypoint main 239 KiB = main.css 111 KiB main.js 128 KiBEntrypoint wp-login-css 7.21 KiB (9.63 KiB) = wp-login-css.css 7.21 KiB wp-login-css.js 0 bytes 1 auxiliary assetEntrypoint wp-admin-css 5.21 KiB (36 KiB) = wp-admin-css.css 5.21 KiB wp-admin-css.js 0 bytes 1 auxiliary assetEntrypoint wp-admin-palette 12.6 KiB = wp-admin-palette.css 12.6 KiB wp-admin-palette.js 0 bytesorphan modules 532 KiB (javascript) 345 KiB (asset) 5.07 KiB (runtime) [orphan] 155 modulescacheable modules 136 KiB (css/mini-extract) 421 KiB (javascript) modules by path ./src/scss/*.scss 130 KiB (css/mini-extract) 150 bytes (javascript) css modules 130 KiB css ./node_modules/.pnpm/css-loader@6.11.0_webpack@5.93.0/node_modules/css-loader/dist/cjs.js!./node_modules/.pnpm/postcss-loader@7.3.4_postcss@8.4.41_typescript@5.5.4_webpack@5.93.0/node_modules/postcss-loader/dist/cjs.js!./src/scss/wp-login.scss 7.28 KiB [built] [code generated] css ./node_modules/.pnpm/css-loader@6.11.0_webpack@5.93.0/node_modules/css-loader/dist/cjs.js!./node_modules/.pnpm/postcss-loader@7.3.4_postcss@8.4.41_typescript@5.5.4_webpack@5.93.0/node_modules/postcss-loader/dist/cjs.js!./src/scss/wp-admin.scss 5.29 KiB [built] [code generated] css ./node_modules/.pnpm/css-loader@6.11.0_webpack@5.93.0/node_modules/css-loader/dist/cjs.js!./node_modules/.pnpm/postcss-loader@7.3.4_postcss@8.4.41_typescript@5.5.4_webpack@5.93.0/node_modules/postcss-loader/dist/cjs.js!./src/scss/wp-admin-palette.scss 12.6 KiB [built] [code generated] css ./node_modules/.pnpm/css-loader@6.11.0_webpack@5.93.0/node_modules/css-loader/dist/cjs.js!./node_modules/.pnpm/postcss-loader@7.3.4_postcss@8.4.41_typescript@5.5.4_webpack@5.93.0/node_modules/postcss-loader/dist/cjs.js!./src/scss/main.scss 105 KiB [built] [code generated] javascript modules 150 bytes ./src/scss/wp-login.scss 50 bytes [built] [code generated] ./src/scss/wp-admin.scss 50 bytes [built] [code generated] ./src/scss/wp-admin-palette.scss 50 bytes [built] [code generated] ./src/ts/main.ts + 94 modules 421 KiB [built] [code generated] css ./node_modules/.pnpm/css-loader@6.11.0_webpack@5.93.0/node_modules/css-loader/dist/cjs.js!./node_modules/.pnpm/postcss-loader@7.3.4_postcss@8.4.41_typescript@5.5.4_webpack@5.93.0/node_modules/postcss-loader/dist/cjs.js!./node_modules/.pnpm/swiper@9.4.1/node_modules/swiper/swiper.scss 6.34 KiB [built] [code generated]webpack 5.93.0 compiled successfully in 4784 ms
Vite Size and Performance
✓ 108 modules transformed.dist/images/B-Nb8i25.svg 5.27 kB │ gzip: 2.35 kBdist/images/BsMD5M02.jpeg 9.86 kBdist/images/VNsNsbZY.svg 13.18 kB │ gzip: 1.05 kBdist/images/BTcOzB81.svg 13.21 kB │ gzip: 0.94 kBdist/images/DFdp8c8q.png 36.90 kBdist/images/Dp_QVDBh.jpeg 271.31 kBdist/wp-admin-css.css 5.32 kB │ gzip: 1.27 kBdist/wp-login-css.css 7.37 kB │ gzip: 1.36 kBdist/wp-admin-palette.css 13.02 kB │ gzip: 2.42 kBdist/main.css 115.67 kB │ gzip: 19.38 kBdist/main.js 110.12 kB │ gzip: 31.59 kB✓ built in 1.80s
Comparison
Webpack compiles in 4.8 seconds, while Vite compiles in 1.8 seconds - making Vite 2.6 times faster than Webpack. Bundle sizes are quite similar: 349.73 kB for Vite versus 353.28 kB for Webpack, resulting in a slight reduction of 3.55 kB, meaning Vite is 1% more efficient in terms of asset size.
For CSS, Vite generates a total of 141.38 kB, while Webpack generates 139.26 kB. This means that Webpack’s CSS output is 2.12 kB lighter, which is about 1.5% smaller than Vite’s.
For JavaScript, Vite produces 110.12 kB, while Webpack produces 131.07 kB. This makes Webpack’s JS bundle 20.95 kB larger, so Vite is 19% more efficient in this regard.
Webpack | Vite | Improvement | |
---|---|---|---|
Compilation time | 4.8s | 1.8s | 260% |
Assets size | 353.28 kB | 349.73 kB | 1% |
CSS size | 141.38 kB | 139.26 kB | 1.5% |
JS size | 131.07 kB | 110.12 kB | 19% |
Conclusion
It’s clear that Vite simplifies the build process, requires less configuration, and is more performant in terms of both speed and bundle size. But does this mean we should abandon Webpack altogether and switch to Vite for every project?
The answer isn’t black and white. I don’t believe in a one-size-fits-all solutions, and this is no exception. Vite is an excellent choice for small to medium-sized projects, or where performance is critical and you don’t need complex configurations. It’s also ideal if you’re looking for a (almost) zero-config solution.
However, for large and complex projects, it may still be worth the time to configure Webpack properly. Webpack’s extensive customization options can be advantageous for managing large codebases and complicated build processes.
So, I guess the title was a little clickbait, huh?