Have you noticed your frontend build getting slower and the bundle growing with each new component? On one project with 200+ components, build time reached 4 minutes and the final bundle hit 2.5 MB. Without proper Webpack configuration, this is typical. Our team of certified Webpack experts with 5+ years of experience fixes such builds daily: analyze, tune loaders, implement code splitting and tree shaking, replace Babel with SWC. Result: build in 30 seconds and bundle of 800 KB. Hosting cost savings up to $300 per month thanks to Brotli compression. Cost is determined after analysis, starting from $500 for basic optimization, advanced from $1500.
Problems that proper Webpack configuration solves
Slow compilation and large bundles hurt everything from development speed to LCP and TTFB in production. Typical pain points:
- Slow build (3–5+ minutes) without SWC or esbuild — main causes: lack of code splitting, using Babel instead of SWC, incorrect resolve.alias settings, no caching.
- Bloated bundle (3–5+ MB) without code splitting: each module brings entire libraries.
- N+1 requests: without splitChunks, every route loads a separate vendor.
- No caching: missing contenthash, browser re-requests the same files.
- Missing source maps in production — debugging becomes a nightmare.
How we configure Webpack: stack and tools
For new projects we use React 18, TypeScript, PostCSS + Tailwind. Compilation is handed to SWC — it's written in Rust and gives a 20x speedup over Babel. Implementing persistent caching with contenthash and deterministic module IDs minimizes cache invalidation. Here's a comparison:
| Parameter | Babel | SWC |
|---|---|---|
| Compilation speed | 1x | 20x |
| TypeScript support | Yes | Yes (with decorators) |
| Number of plugins | Many | Enough for 95% of tasks |
| Production readiness | High | High (used in Vercel, Next.js) |
On one project with 200+ components, we reduced the bundle from 2.5 MB to 800 KB through code splitting and tree shaking. Build time dropped from 4 minutes to 30 seconds after switching to SWC. Hosting cost decreased by $200 per month thanks to Brotli compression.
Comparison before and after optimization
| Metric | Before | After |
|---|---|---|
| Build time | 4 min | 30 sec |
| Bundle size | 2.5 MB | 800 KB |
| Number of requests | 15 | 6 |
| Hosting savings | — | up to $300/month |
Why use SWC instead of Babel?
SWC compiles code 10–20x faster while supporting all necessary transformations: TypeScript, React JSX, decorators. Integrating with Webpack is straightforward — just replace babel-loader with swc-loader. We recommend SWC for new projects and migration of old ones. The only downside is fewer custom plugins, but for standard tasks they are sufficient. As the official documentation states: SWC is 20x faster than Babel on a single thread.
Code splitting for maximum performance
Effective webpack configuration for code splitting and tree shaking directly reduces bundle size and improves load times. We use optimization.splitChunks with grouping by vendors and common modules. For example, we separate React into its own vendor chunk, and other libraries into commons when reused across multiple chunks. Dynamic imports with /* webpackChunkName: "products" */ split code by routes. Enable runtimeChunk: 'single' so cache invalidation doesn't affect all chunks. Result: parallel loading of small fragments and high cache hit rate.
How to reduce bundle size without losing functionality
Combination of techniques:
- Tree shaking: ensure imports have no side effects and set
sideEffects: falsein package.json. - Minification with TerserPlugin and option
drop_console: true. - CSS minification with CssMinimizerPlugin.
- Brotli compression via CompressionPlugin (saves up to 30% volume).
-
webpack-bundle-analyzerfor visual control.
Below is a base configuration we adapt for each project.
Install dependencies
npm install -D webpack webpack-cli webpack-dev-server
npm install -D html-webpack-plugin mini-css-extract-plugin css-minimizer-webpack-plugin
npm install -D terser-webpack-plugin compression-webpack-plugin
npm install -D swc-loader @swc/core @swc/helpers
Main configuration file
import path from 'path'
import webpack from 'webpack'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
import TerserPlugin from 'terser-webpack-plugin'
import CompressionPlugin from 'compression-webpack-plugin'
const isDev = process.env.NODE_ENV !== 'production'
const root = path.resolve(__dirname)
const config: webpack.Configuration = {
mode: isDev ? 'development' : 'production',
entry: { main: './src/index.tsx' },
output: {
path: path.resolve(root, 'dist'),
filename: isDev ? '[name].js' : '[name].[contenthash:8].js',
chunkFilename: isDev ? '[name].chunk.js' : '[name].[contenthash:8].chunk.js',
assetModuleFilename: 'assets/[hash][ext][query]',
publicPath: '/',
clean: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
'@': path.resolve(root, 'src'),
'@components': path.resolve(root, 'src/components'),
'@hooks': path.resolve(root, 'src/hooks'),
},
},
module: {
rules: [
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'swc-loader',
options: {
jsc: {
parser: { syntax: 'typescript', tsx: true },
transform: {
react: {
runtime: 'automatic',
development: isDev,
refresh: isDev,
},
},
target: 'es2020',
},
},
},
},
{
test: /\.css$/,
use: [
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: {
auto: /\.module\.css$/,
localIdentName: isDev ? '[local]--[hash:base64:5]' : '[hash:base64:8]',
},
importLoaders: 1,
},
},
'postcss-loader',
],
},
{
test: /\.(png|jpg|webp|gif|svg)$/,
type: 'asset',
parser: { dataUrlCondition: { maxSize: 4 * 1024 } },
},
{
test: /\.(woff2?|ttf|eot)$/,
type: 'asset/resource',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
favicon: './public/favicon.ico',
minify: !isDev,
}),
!isDev && new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css',
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(process.env.API_URL),
}),
!isDev && new CompressionPlugin({
algorithm: 'brotliCompress',
test: /\.(js|css|html|svg)$/,
threshold: 10240,
}),
].filter(Boolean),
optimization: {
minimize: !isDev,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: { drop_console: true },
format: { comments: false },
},
extractComments: false,
}),
new CssMinimizerPlugin(),
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/](react|react-dom|react-router-dom)[\\/]/,
name: 'vendor-react',
chunks: 'all',
priority: 20,
},
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor-commons',
chunks: 'all',
priority: 10,
minChunks: 2,
},
},
},
runtimeChunk: 'single',
moduleIds: isDev ? 'named' : 'deterministic',
chunkIds: isDev ? 'named' : 'deterministic',
},
devServer: {
port: 3000,
hot: true,
historyApiFallback: true,
compress: true,
proxy: [
{
context: ['/api'],
target: 'http://localhost:8000',
changeOrigin: true,
},
],
client: { overlay: { errors: true, warnings: false } },
},
devtool: isDev ? 'eval-cheap-module-source-map' : 'source-map',
performance: {
hints: isDev ? false : 'warning',
maxAssetSize: 250_000,
maxEntrypointSize: 500_000,
},
}
export default config
Also attach postcss.config.js with Tailwind, autoprefixer and cssnano, and for TypeScript configure tsconfig.json with paths (must duplicate in resolve.alias).
Work process
- Audit current build: measure time, analyze bundle with
webpack-bundle-analyzer. - Choose strategy: determine which optimizations are needed — code splitting, tree shaking, SWC.
- Configuration: set up Webpack, loaders, plugins, dev server.
- Testing: verify correct build and behavior in production.
- Deployment: integrate configuration into CI/CD, set up caching.
Timeline: from 1 to 3 days depending on stack complexity. Cost is determined individually, starting from $500, advanced from $1500.
Deliverables
- Audit report of existing configuration.
- Setup of SWC, code splitting, tree shaking, HMR.
- CSS optimization (PostCSS, minification).
- CI/CD integration (GitHub Actions, GitLab CI).
- Configuration documentation.
- Team training (1 hour).
Common Webpack configuration mistakes
- Incorrect resolve.alias settings — paths don't work.
- Forgetting to configure splitChunks — libraries duplicated in every chunk.
- Not using tree shaking — dead code remains.
- Disabling source maps in production — hard to debug errors.
- Not adding contenthash — browser doesn't cache updates.
Conclusion
Proper Webpack configuration is not a one-time task but an investment in development speed and user experience. We have configured builds for 50+ projects, reducing bundles on average by 40% and speeding up compilation 20x. Contact us for an audit of your current build. Order custom Webpack configuration — we evaluate your project and propose the optimal solution. Get a consultation from an engineer right now.







