Rollup Tree Shaking: Optimize JavaScript Bundles
Welcome to TopperBlog! 👋
I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.
🎯 What I Write About:
• AI/ML Engineering & LLMs
• Web3 & Blockchain Development
• System Design & Architecture
• Interview Preparation (FAANG)
• Freelancing & Remote Work
• Modern Tech Stacks (Next.js, React, Rust, TypeScript)
• Performance Optimization & Best Practices
💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.
📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.
🌐 Let's connect and grow together in this amazing tech journey!
#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering
Rollup Tree Shaking: Optimize JavaScript Bundles
The Build That Took 20 Minutes (Now Takes 30 Seconds)
Our CI pipeline was killing productivity. Then we switched build tools. Here's what happened.
Table of Contents
- Modern Build Tools 2026
- Architecture Overview
- 5 Optimization Strategies
- Configuration Guide
- Performance Benchmarks
- Migration Path
- Troubleshooting
- FAQ
- Production Setup
Modern Build Tools in 2026
Speed is no longer negotiable.
Build Time Impact
// Business cost of slow builds
interface BuildCost {
developerTime: number; // $100/hour
ciMinutes: number; // $0.10/minute
deploymentDelay: number; // Lost revenue
}
const monthlyWaste = {
developerTime: 40 * 100, // $4,000
ciMinutes: 1000 * 0.10, // $100
deploymentDelay: 'priceless'
};
Evolution of Bundlers
# 2018: Webpack (slow but powerful)
Build time: 5-20 minutes
# 2022: Vite (fast dev, slower prod)
Build time: 1-5 minutes
# 2026: Next-gen bundlers (instant everything)
Build time: 10-60 seconds
Why Speed Matters
Fast feedback loops = happy developers.
Architecture Overview
Understanding how bundlers work.
Build Pipeline
// Modern build pipeline
interface BuildPipeline {
parse: 'AST generation';
transform: 'Transpilation';
bundle: 'Code splitting';
optimize: 'Minification';
output: 'File writing';
}
const pipeline: Record<keyof BuildPipeline, number> = {
parse: 10, // ms
transform: 50, // ms
bundle: 100, // ms
optimize: 200, // ms
output: 40 // ms
};
// Total: 400ms vs 5min with old tools
Parallelization
// Concurrent processing
import { Worker } from 'worker_threads';
class ParallelBundler {
private workers: Worker[];
async bundle(files: string[]) {
const chunks = this.splitIntoChunks(files);
const results = await Promise.all(
chunks.map(chunk =>
this.processChunk(chunk)
)
);
return this.mergeResults(results);
}
}
Caching Strategy
Incremental builds save time.
Strategy 1: Configuration
Minimal Setup
// Modern bundler config
import { defineConfig } from 'bundler';
export default defineConfig({
entry: './src/index.ts',
output: {
dir: './dist',
format: 'esm'
},
plugins: [
typescript(),
minify()
]
});
Advanced Config
// Production optimization
export default defineConfig({
build: {
target: 'es2022',
minify: 'esbuild',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
'vendor': ['react', 'react-dom'],
'utils': ['lodash-es', 'date-fns']
}
}
}
},
optimizeDeps: {
include: ['heavy-package']
}
});
Environment Variables
// .env handling
import { loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd());
return {
define: {
'import.meta.env.API_URL': JSON.stringify(env.VITE_API_URL)
}
};
});
Strategy 2: Code Splitting
Dynamic Imports
// Route-based splitting
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
Vendor Splitting
// Separate vendor bundles
export default {
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
// Split by package
const match = id.match(/node_modules\/(.+?)\//);
return match ? `vendor-${match[1]}` : 'vendor';
}
}
}
}
}
};
Lazy Loading
Load heavy features on demand.
Strategy 3: Performance
Parallel Processing
// Multi-core utilization
export default {
build: {
// Use all CPU cores
minify: {
parallel: true,
workers: os.cpus().length
}
}
};
Cache Configuration
// Persistent caching
export default {
cacheDir: '.bundler-cache',
build: {
cache: {
// Cache compiled modules
module: true,
// Cache dependencies
dependencies: true
}
}
};
Asset Optimization
// Image optimization
export default {
build: {
assetsInlineLimit: 4096, // 4kb
rollupOptions: {
output: {
assetFileNames: 'assets/[name]-[hash][extname]'
}
}
}
};
Strategy 4: Tree Shaking
ES Modules
// Proper imports for tree shaking
// ❌ Bad: Imports everything
import _ from 'lodash';
// ✅ Good: Only imports what's used
import { debounce } from 'lodash-es';
// ✅ Better: Direct import
import debounce from 'lodash-es/debounce';
Side Effects
// package.json
{
"name": "my-library",
"sideEffects": false,
// Or specify files with side effects
"sideEffects": [
"*.css",
"*.scss",
"./src/polyfills.ts"
]
}
Dead Code Elimination
Mark unused code clearly.
Strategy 5: Monorepo Setup
Workspace Configuration
// pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
- 'tools/*'
Shared Configuration
// packages/config/bundler.config.ts
export const sharedConfig = {
plugins: [
react(),
typescript()
],
build: {
minify: true,
sourcemap: true
}
};
// apps/web/bundler.config.ts
import { sharedConfig } from '@config/bundler';
export default {
...sharedConfig,
// App-specific overrides
};
Task Dependencies
// turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"]
}
}
}
Performance Benchmarks
| Tool | Dev Start | Build Time | HMR | Bundle Size |
| Webpack | 30s | 5min | 500ms | 1.2MB |
| Vite | 1s | 2min | 50ms | 1.0MB |
| Turbopack | 0.3s | 30s | 10ms | 950KB |
| esbuild | 0.1s | 10s | N/A | 900KB |
Migration Path
From Webpack
// 1. Install new bundler
npm install vite -D
// 2. Update package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
// 3. Create config
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
// Migrate webpack config here
});
Gradual Migration
Move one app at a time in monorepo.
Troubleshooting
Common Issues
// Error: Module not found
// Fix: Update import paths
// Before
import Component from 'src/Component';
// After
import Component from '@/Component';
// Error: Circular dependency
// Fix: Restructure imports or use dynamic imports
const Module = await import('./circular-dep');
Performance Problems
# Analyze bundle
npx vite-bundle-analyzer
# Check dependencies
npx depcheck
# Audit bundle size
npx bundlephobia
FAQ
Q1: Which bundler to choose?
Vite for apps, esbuild for libraries, Turbopack for Next.js.
Q2: How to reduce bundle size?
Tree shaking, code splitting, compression, and analyze dependencies.
Q3: HMR not working?
Check file watchers, exclude node_modules, restart dev server.
Q4: Build taking too long?
Enable caching, upgrade Node.js, use faster bundler.
Q5: Monorepo setup complexity?
Use Turborepo or Nx for enterprise-grade setup.
Production Setup
CI/CD Optimization
# GitHub Actions
- name: Cache dependencies
uses: actions/cache@v3
with:
path: |
~/.pnpm-store
.bundler-cache
key: ${{ runner.os }}-deps-${{ hashFiles('**/pnpm-lock.yaml') }}
- name: Build
run: pnpm build
Deployment
#!/bin/bash
# Production build script
# Clean
rm -rf dist
# Build
NODE_ENV=production pnpm build
# Verify
ls -lh dist/
# Deploy
aws s3 sync dist/ s3://bucket/ --delete
Conclusion
Fast builds enable fast iteration.
Key takeaways:
- Choose modern tools
- Configure caching
- Split code intelligently
- Monitor bundle size
- Optimize continuously
Speed is a feature.
Resources:
- Bundler Documentation
- Performance Guides
- Migration Tools
- Community Plugins
Next Steps:
- Audit current build
- Choose new bundler
- Configure caching
- Migrate gradually
- Measure improvements
Speed up your builds today.