Bundle Size Optimization - Complete Guide
Published: September 25, 2024 | Reading time: 22 minutes
Bundle Optimization Overview
Bundle size optimization improves application performance and loading speed:
Optimization Benefits
# Bundle Optimization Benefits
- Faster loading times
- Reduced bandwidth usage
- Better user experience
- Improved performance
- Lower hosting costs
- Better SEO rankings
- Mobile optimization
Bundle Analysis
Analyzing Bundle Size
Bundle Analysis Tools
# Bundle Analysis Tools
# 1. Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
# webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'server',
openAnalyzer: true,
})
]
};
# 2. Webpack Bundle Analyzer CLI
npx webpack-bundle-analyzer dist/main.js
# 3. Source Map Explorer
npm install --save-dev source-map-explorer
npx source-map-explorer 'dist/*.js'
# 4. Bundle Analyzer Script
# package.json
{
"scripts": {
"analyze": "webpack-bundle-analyzer dist/main.js",
"analyze:source": "source-map-explorer 'dist/*.js'"
}
}
# 5. Webpack Stats
# webpack.config.js
module.exports = {
stats: {
chunks: true,
chunkModules: true,
modules: true,
reasons: true,
usedExports: true,
providedExports: true,
optimizationBailout: true,
errorDetails: true,
colors: true,
hash: true,
timings: true,
assets: true,
cached: true,
cachedAssets: true,
children: true,
chunksSort: 'size',
modulesSort: 'size',
assetsSort: 'size'
}
};
# 6. Bundle Size Monitoring
# bundle-size.js
const fs = require('fs');
const path = require('path');
const bundlePath = path.join(__dirname, 'dist', 'main.js');
const stats = fs.statSync(bundlePath);
const sizeInKB = Math.round(stats.size / 1024);
console.log(`Bundle size: ${sizeInKB} KB`);
# 7. CI/CD Bundle Size Check
# .github/workflows/bundle-size.yml
name: Bundle Size Check
on: [push, pull_request]
jobs:
bundle-size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm run build
- run: npm run analyze
# 8. Bundle Size Budget
# webpack.config.js
module.exports = {
performance: {
hints: 'warning',
maxEntrypointSize: 512000,
maxAssetSize: 512000,
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.js');
}
}
};
# 9. Bundle Size Comparison
# compare-bundles.js
const fs = require('fs');
const path = require('path');
function getBundleSize(filePath) {
const stats = fs.statSync(filePath);
return Math.round(stats.size / 1024);
}
const currentSize = getBundleSize('dist/main.js');
const previousSize = getBundleSize('dist-previous/main.js');
const difference = currentSize - previousSize;
console.log(`Current: ${currentSize} KB`);
console.log(`Previous: ${previousSize} KB`);
console.log(`Difference: ${difference} KB`);
# 10. Bundle Size Report
# bundle-report.js
const fs = require('fs');
const path = require('path');
function generateReport() {
const bundlePath = path.join(__dirname, 'dist', 'main.js');
const stats = fs.statSync(bundlePath);
const sizeInKB = Math.round(stats.size / 1024);
const report = {
timestamp: new Date().toISOString(),
bundleSize: sizeInKB,
threshold: 500
};
fs.writeFileSync('bundle-report.json', JSON.stringify(report, null, 2));
}
generateReport();
Webpack Optimization
Webpack Configuration
Webpack Optimization
# Webpack Optimization
# 1. Production Mode
# webpack.config.js
module.exports = {
mode: 'production',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
}),
],
},
};
# 2. Code Splitting
# webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
enforce: true,
},
},
},
},
};
# 3. Tree Shaking
# webpack.config.js
module.exports = {
optimization: {
usedExports: true,
sideEffects: false,
},
};
# 4. Module Concatenation
# webpack.config.js
module.exports = {
optimization: {
concatenateModules: true,
},
};
# 5. Minification
# webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log'],
},
mangle: {
safari10: true,
},
},
}),
],
},
};
# 6. CSS Optimization
# webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
optimization: {
minimizer: [
new CssMinimizerPlugin(),
],
},
};
# 7. Asset Optimization
# webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[contenthash].[ext]',
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65,
},
optipng: {
enabled: false,
},
pngquant: {
quality: [0.65, 0.90],
speed: 4,
},
gifsicle: {
interlaced: false,
},
},
},
],
},
],
},
};
# 8. Dynamic Imports
# webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
async: {
test: /[\\/]node_modules[\\/]/,
chunks: 'async',
name: 'async-vendors',
},
},
},
},
};
# 9. Preloading
# webpack.config.js
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
preload: {
rel: 'preload',
as: 'script',
href: 'runtime.js',
},
}),
],
};
# 10. Compression
# webpack.config.js
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionPlugin({
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
threshold: 8192,
minRatio: 0.8,
}),
],
};
Code Splitting Strategies
Advanced Code Splitting
Code Splitting Strategies
# Code Splitting Strategies
# 1. Route-based Splitting
# App.js
import React, { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));
function App() {
return (
Loading... Component loaded
;
}
# 7. Webpack Magic Comments
# Component.js
const Component = lazy(() =>
import(/* webpackChunkName: "component" */ './Component')
);
# 8. Bundle Splitting
# webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 244000,
cacheGroups: {
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: -10,
chunks: 'all',
},
},
},
},
};
# 9. Runtime Splitting
# webpack.config.js
module.exports = {
optimization: {
runtimeChunk: 'single',
},
};
# 10. CSS Splitting
# webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
chunkFilename: '[id].[contenthash].css',
}),
],
};
Performance Best Practices
Optimization Guidelines
Best Practices
- Code splitting
- Tree shaking
- Minification
- Compression
- Lazy loading
- Bundle analysis
- Performance monitoring
Common Mistakes
- Large bundle sizes
- Unused dependencies
- Poor code splitting
- Missing minification
- No compression
- Inefficient imports
- Poor caching
Summary
Bundle size optimization involves several key components:
- Bundle Analysis: Tools and techniques for analyzing bundle size
- Webpack Optimization: Configuration and optimization strategies
- Code Splitting: Advanced splitting techniques and strategies
- Best Practices: Guidelines and common mistakes to avoid
Need More Help?
Struggling with bundle size optimization or need help implementing performance improvements? Our performance experts can help you optimize your application.
Get Bundle Optimization Help