Docs
README
14.4 Bundlers & Build Tools
π Introduction
Bundlers transform your modular source code into optimized bundles for production. They resolve dependencies, transpile modern JavaScript, and optimize assets for fast loading.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BUNDLER WORKFLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β SOURCE FILES BUNDLED OUTPUT β
β ββββββββββββ ββββββββββββββ β
β β
β src/ dist/ β
β βββ index.js ββ βββ bundle.js (optimized) β
β βββ utils.js β βββ vendor.js (dependencies) β
β βββ api.js βββΆ BUNDLER βββββββΆβββ styles.css (processed) β
β βββ styles.css β βββ images/ (optimized) β
β βββ images/ ββ βββ index.html (injected) β
β β
β WHAT BUNDLERS DO: β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β 1. Resolve imports β Build dependency graph β β
β β 2. Transform code β Babel, TypeScript, JSX β β
β β 3. Bundle modules β Combine into fewer files β β
β β 4. Tree-shake β Remove unused exports β β
β β 5. Minify β Reduce file size β β
β β 6. Code-split β Lazy-load chunks β β
β β 7. Process assetsβ CSS, images, fonts β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π― Learning Objectives
By the end of this section, you will:
- β’β Understand why bundlers are necessary
- β’β Configure Webpack for real projects
- β’β Use Vite for fast development
- β’β Build libraries with Rollup
- β’β Leverage esbuild for speed
- β’β Implement tree-shaking and code-splitting
1οΈβ£ Why Bundlers?
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WHY WE NEED BUNDLERS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β WITHOUT BUNDLER: β
β β
β Browser loads 100 separate files: β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β GET /index.js ββ β β
β β GET /utils.js β β β
β β GET /api.js βββ 100 HTTP requests! β β
β β GET /components/A.js β Waterfall loading β β
β β GET /components/B.js β Slow initial load β β
β β ... ββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β WITH BUNDLER: β
β β
β Browser loads few optimized files: β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β GET /bundle.js ββ β β
β β GET /vendor.js βββ 2-3 requests β β
β β GET /styles.css ββ Parallel loading β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ADDITIONAL BENEFITS: β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β’ Transpilation β Use latest JS features everywhere β β
β β β’ Minification β Smaller file sizes β β
β β β’ Tree-shaking β Remove unused code β β
β β β’ Code-splitting β Load code on demand β β
β β β’ Hot Reload β Instant dev updates β β
β β β’ Asset handling β Images, CSS, fonts β β
β β β’ Environment varsβ Dev/prod configurations β β
β β β’ Source maps β Debug production code β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2οΈβ£ Bundler Comparison
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BUNDLER COMPARISON β
βββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬ββββββββββββββββββββββββββ€
β Feature β Webpack β Vite β Rollup β esbuild β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Speed β Slow β β‘ Fast β Medium β β‘β‘ Fastest β
β β (JS-based) β (ESM+Go) β (JS-based) β (Go-based) β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Best For β Complex β Modern β Libraries β Simple/Fast β
β β apps β apps β packages β builds β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Config β Complex β Minimal β Medium β Minimal β
β β Flexible β Convention β Plugins β API-driven β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Dev Mode β Dev Server β Native ESM β Watch mode β Watch mode β
β β HMR β Instant HMRβ β β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Tree- β β
Yes β β
Yes β β
Best β β
Yes β
β Shaking β β (Rollup) β β β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Code β β
Yes β β
Yes β β
Yes β β
Yes β
β Splitting β (powerful) β β β (basic) β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Plugins β Thousands β Rollup + β Many β Limited β
β Ecosystem β β Custom β β Growing β
βββββββββββββββΌβββββββββββββββΌβββββββββββββββΌβββββββββββββββΌββββββββββββββββββββββββββ€
β Learning β Steep β Easy β Medium β Easy β
β Curve β β β β β
βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄ββββββββββββββββββββββββββ
RECOMMENDATION:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β’ New web apps β Vite (fast dev, Rollup production) β
β β’ Library/Package β Rollup (best tree-shaking) β
β β’ Complex enterprise app β Webpack (most plugins/flexibility) β
β β’ Speed-critical builds β esbuild (fastest, less features) β
β β’ Legacy projects β Webpack (stable, documented) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
3οΈβ£ Webpack Configuration
Basic Setup
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// webpack.config.js - Basic configuration
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// Entry point(s)
entry: {
main: './src/index.js',
// Multiple entries for code splitting
admin: './src/admin.js',
},
// Output configuration
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js', // main.abc123.js
clean: true, // Clean dist folder before build
},
// Mode: 'development' | 'production' | 'none'
mode: process.env.NODE_ENV || 'development',
// Source maps for debugging
devtool: 'source-map',
// Module rules (loaders)
module: {
rules: [
// JavaScript/JSX with Babel
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
// CSS
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
},
// SCSS/SASS
{
test: /\.s[ac]ss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
},
// Images
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset/resource',
generator: {
filename: 'images/[name].[hash][ext]',
},
},
// Fonts
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[name].[hash][ext]',
},
},
],
},
// Plugins
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
chunks: ['main'],
}),
new MiniCssExtractPlugin({
filename: 'styles/[name].[contenthash].css',
}),
],
// Resolve configuration
resolve: {
extensions: ['.js', '.jsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
},
},
// Dev server
devServer: {
static: './dist',
port: 3000,
hot: true,
open: true,
historyApiFallback: true,
},
// Optimization
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
};
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WEBPACK CONCEPTS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ENTRY OUTPUT β
β βββββ ββββββ β
β Entry points Where to emit β
β to start bundling the bundles β
β β
β entry: './src/index.js' output: { β
β β path: 'dist/', β
β β filename: 'bundle.js' β
β βΌ } β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β β
β β LOADERS (Transform files) β β
β β βββββββββββ βββββββββββ βββββββββββ β β
β β β Babel β β CSS β β Image β β β
β β β Loader β β Loader β β Loader β β β
β β βββββββββββ βββββββββββ βββββββββββ β β
β β β β
β β PLUGINS (Extend functionality) β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββ β β
β β β HtmlWebpack β β MiniCssExt β β DefinePlugin β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββ β β
β β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β MODE: β
β β’ development: Fast builds, readable output β
β β’ production: Minified, tree-shaken β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Advanced Webpack Features
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// webpack.config.js - Production optimizations
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
mode: 'production',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // Remove console.log
},
},
}),
new CssMinimizerPlugin(),
],
// Split chunks for caching
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 244000,
cacheGroups: {
// Vendor chunk
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
},
// React chunk
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
priority: 20,
},
// Common code chunk
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
},
},
// Runtime chunk for long-term caching
runtimeChunk: 'single',
// Module IDs for stable hashes
moduleIds: 'deterministic',
},
plugins: [
// Gzip compression
new CompressionPlugin({
algorithm: 'gzip',
test: /\.(js|css|html|svg)$/,
}),
// Bundle analysis
process.env.ANALYZE && new BundleAnalyzerPlugin(),
].filter(Boolean),
// Performance hints
performance: {
hints: 'warning',
maxEntrypointSize: 250000,
maxAssetSize: 250000,
},
};
4οΈβ£ Vite Configuration
Basic Setup
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// vite.config.js - Modern, fast bundler
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
// Plugins
plugins: [react()],
// Dev server
server: {
port: 3000,
open: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
},
},
},
// Build options
build: {
outDir: 'dist',
sourcemap: true,
minify: 'terser',
// Chunk splitting
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
lodash: ['lodash'],
},
},
},
},
// Resolve aliases
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
},
},
// CSS options
css: {
modules: {
localsConvention: 'camelCase',
},
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`,
},
},
},
// Environment variables
define: {
__APP_VERSION__: JSON.stringify(process.env.npm_package_version),
},
});
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β WHY VITE IS FAST β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β TRADITIONAL BUNDLER (Webpack): β
β β
β ββββββββββββ ββββββββββββββββββββ ββββββββββββββββ β
β β Source β ββΆ β Bundle ALL β ββΆ β Serve β β
β β Files β β files first β β bundle β β
β ββββββββββββ ββββββββββββββββββββ ββββββββββββββββ β
β β² β
β β β
β SLOW on large projects! β
β β
β VITE (Native ESM): β
β β
β ββββββββββββ ββββββββββββββββββββ ββββββββββββββββ β
β β Source β ββΆ β Transform β ββΆ β Browser β β
β β Files β β on demand β β loads ESM β β
β ββββββββββββ ββββββββββββββββββββ ββββββββββββββββ β
β β² β
β β β
β Only transform what's needed! β
β β
β KEY INNOVATIONS: β
β β’ Native ES modules in browser (no bundling for dev) β
β β’ esbuild for dependency pre-bundling (100x faster) β
β β’ Hot Module Replacement that scales β
β β’ Rollup for production (optimized output) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
5οΈβ£ Rollup Configuration
Library Building
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// rollup.config.js - Best for libraries
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
import { dts } from 'rollup-plugin-dts';
import pkg from './package.json' assert { type: 'json' };
const input = 'src/index.js';
export default [
// ESM build (for modern bundlers)
{
input,
output: {
file: pkg.module, // dist/index.esm.js
format: 'esm',
sourcemap: true,
},
external: Object.keys(pkg.peerDependencies || {}),
plugins: [
resolve(),
commonjs(),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
}),
],
},
// CommonJS build (for Node.js)
{
input,
output: {
file: pkg.main, // dist/index.cjs.js
format: 'cjs',
sourcemap: true,
exports: 'named',
},
external: Object.keys(pkg.peerDependencies || {}),
plugins: [
resolve(),
commonjs(),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
}),
],
},
// UMD build (for browsers / CDN)
{
input,
output: {
file: pkg.browser, // dist/index.umd.js
format: 'umd',
name: 'MyLibrary', // window.MyLibrary
sourcemap: true,
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
},
external: ['react', 'react-dom'],
plugins: [
resolve(),
commonjs(),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
}),
terser(), // Minify for production
],
},
// TypeScript declarations
{
input: 'src/index.ts',
output: {
file: 'dist/index.d.ts',
format: 'es',
},
plugins: [dts()],
},
];
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// package.json for the library
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"browser": "dist/index.umd.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"exports": {
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js",
"types": "./dist/index.d.ts"
}
},
"files": ["dist"],
"peerDependencies": {
"react": ">=17.0.0"
}
}
6οΈβ£ esbuild Configuration
Ultra-Fast Building
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// build.js - esbuild API
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
import * as esbuild from 'esbuild';
// Simple build
await esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
minify: true,
sourcemap: true,
outfile: 'dist/bundle.js',
target: ['es2020'],
format: 'esm',
});
// Build with plugins and watch mode
const ctx = await esbuild.context({
entryPoints: ['src/index.js'],
bundle: true,
outdir: 'dist',
splitting: true,
format: 'esm',
// External dependencies (not bundled)
external: ['react', 'react-dom'],
// Loaders for different file types
loader: {
'.png': 'file',
'.svg': 'dataurl',
'.css': 'css',
},
// Define replacements
define: {
'process.env.NODE_ENV': '"production"',
},
// Plugins
plugins: [
// Custom plugin example
{
name: 'example-plugin',
setup(build) {
build.onStart(() => {
console.log('Build started...');
});
build.onEnd((result) => {
console.log(`Build finished with ${result.errors.length} errors`);
});
},
},
],
});
// Watch mode
await ctx.watch();
// Serve mode (dev server)
const { host, port } = await ctx.serve({
servedir: 'dist',
port: 3000,
});
console.log(`Server running at http://${host}:${port}`);
# esbuild CLI usage
# Basic bundle
esbuild src/index.js --bundle --outfile=dist/bundle.js
# Production build
esbuild src/index.js --bundle --minify --sourcemap --outfile=dist/bundle.js
# With external deps and splitting
esbuild src/index.js --bundle --splitting --format=esm --outdir=dist
# Watch mode
esbuild src/index.js --bundle --watch --outfile=dist/bundle.js
7οΈβ£ Tree-Shaking
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β TREE-SHAKING β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Tree-shaking = Dead code elimination for ES Modules β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β β
β β // utils.js // After tree-shaking β β
β β export function add() {...} function add() {...} β β
β β export function sub() {...} // sub is removed! β β
β β export function mul() {...} // mul is removed! β β
β β export function div() {...} // div is removed! β β
β β β β
β β // app.js β β
β β import { add } from './utils' // Only add is used β β
β β add(1, 2); β β
β β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β REQUIREMENTS FOR TREE-SHAKING: β
β β
β β
Use ES Modules (import/export) β
β β
Use static imports (not dynamic require) β
β β
Mark package as side-effect free β
β β
Avoid circular dependencies β
β β
Don't use export default object β
β β
β β PREVENTS TREE-SHAKING: β
β β
β // Bad: Object default export β
β export default { β
β add: () => {}, β
β sub: () => {} // Can't be shaken! β
β }; β
β β
β // Good: Named exports β
β export const add = () => {}; β
β export const sub = () => {}; β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Side Effects Configuration
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// package.json - Mark side effects for tree-shaking
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
{
"name": "my-package",
"sideEffects": false, // Package is pure, tree-shake everything
// Or specify files with side effects
"sideEffects": [
"*.css",
"*.scss",
"./src/polyfills.js"
]
}
8οΈβ£ Code-Splitting
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Dynamic imports for code-splitting
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Route-based splitting
const routes = {
'/': () => import('./pages/Home.js'),
'/about': () => import('./pages/About.js'),
'/dashboard': () => import('./pages/Dashboard.js'),
};
async function navigate(path) {
const loadModule = routes[path];
if (loadModule) {
const module = await loadModule();
renderPage(module.default);
}
}
// Component-based splitting (React)
import React, { lazy, Suspense } from 'react';
const HeavyChart = lazy(() => import('./components/HeavyChart'));
const AdminPanel = lazy(() => import('./components/AdminPanel'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
{isAdmin && <AdminPanel />}
<HeavyChart data={data} />
</Suspense>
);
}
// Magic comments for chunk naming (Webpack)
const Analytics = import(
/* webpackChunkName: "analytics" */
/* webpackPreload: true */
'./analytics.js'
);
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CODE SPLITTING STRATEGIES β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. ROUTE-BASED SPLITTING β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β / βββββββββββββββΆ main.js (small) β β
β β /dashboard ββββββΆ dashboard.chunk.js (lazy loaded) β β
β β /settings βββββββΆ settings.chunk.js (lazy loaded) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β 2. COMPONENT-BASED SPLITTING β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Core UI βββββββββΆ main.js β β
β β Chart Library βββΆ chart.chunk.js (loaded when needed) β β
β β Editor ββββββββββΆ editor.chunk.js (loaded when needed) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β 3. VENDOR SPLITTING β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Your code βββββββΆ main.js (changes often) β β
β β node_modules ββββΆ vendor.js (cached long-term) β β
β β React βββββββββββΆ react.js (cached very long) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β LOADING STRATEGIES: β
β β’ Prefetch: Load when browser is idle (might need later) β
β β’ Preload: Load immediately (will need soon) β
β β’ Lazy: Load on demand (when route/component accessed) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
9οΈβ£ Summary
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β KEY TAKEAWAYS β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β CHOOSE YOUR BUNDLER: β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Vite β Modern apps, fast development β β
β β Webpack β Complex apps, extensive ecosystem β β
β β Rollup β Libraries, optimal tree-shaking β β
β β esbuild β Speed-critical, simple builds β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β OPTIMIZATION CHECKLIST: β
β β
β β‘ Enable tree-shaking (ES Modules + sideEffects: false) β
β β‘ Split vendor code (separate chunk for node_modules) β
β β‘ Lazy load routes (dynamic import for pages) β
β β‘ Analyze bundles (webpack-bundle-analyzer, rollup-plugin-viz) β
β β‘ Minify code (Terser, esbuild) β
β β‘ Compress assets (gzip, brotli) β
β β‘ Use content hashes (cache busting) β
β β‘ Set performance budgets β
β β
β BEST PRACTICES: β
β β
β β’ Keep bundles under 250KB (before gzip) β
β β’ Cache vendor chunks long-term β
β β’ Prefetch important chunks β
β β’ Monitor bundle size in CI/CD β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Next Steps
Continue to 14.5 Module Patterns to learn:
- β’Singleton pattern with modules
- β’Factory modules
- β’Facade pattern
- β’Dependency injection
- β’Module best practices