bundle-analysis
About
This skill analyzes and optimizes JavaScript bundle sizes to improve application load times. It helps identify large dependencies, investigate performance issues, and optimize frontend assets using tools like the Next.js Bundle Analyzer. Developers should use it when dealing with large bundles, slow page loads, or when needing to understand bundle composition.
Documentation
Bundle Analysis Skill
This skill helps you analyze and optimize JavaScript bundle sizes for Next.js and web applications.
When to Use This Skill
- Large bundle sizes (>500KB)
- Slow initial page loads
- High First Contentful Paint (FCP)
- Investigating bundle composition
- Identifying duplicate dependencies
- Optimizing production builds
- Reducing Time to Interactive (TTI)
Bundle Size Goals
- Initial bundle: <200KB (gzipped)
- First Load JS: <300KB total
- Route chunks: <100KB each
- Vendor chunks: <150KB
- Time to Interactive: <3s on 3G
Next.js Bundle Analyzer
Setup
# Install bundle analyzer
pnpm add -D @next/bundle-analyzer
# Or as dev dependency in web app
cd apps/web
pnpm add -D @next/bundle-analyzer
Configuration
// apps/web/next.config.ts
import type { NextConfig } from "next";
import withBundleAnalyzer from "@next/bundle-analyzer";
const bundleAnalyzer = withBundleAnalyzer({
enabled: process.env.ANALYZE === "true",
});
const nextConfig: NextConfig = {
// ... your config
};
export default bundleAnalyzer(nextConfig);
Running Analysis
# Analyze production bundle
cd apps/web
ANALYZE=true pnpm build
# Opens two HTML reports in browser:
# - client.html: Client-side bundle
# - server.html: Server-side bundle
# Analyze specific environment
ANALYZE=true NODE_ENV=production pnpm build
# Save report to file
ANALYZE=true pnpm build > bundle-report.txt
Reading Bundle Reports
Bundle Analyzer Output
Page Size First Load JS
┌ ○ / 5.2 kB 120 kB
├ /_app 0 B 115 kB
├ ○ /404 3.1 kB 118 kB
├ λ /api/cars 0 B 115 kB
├ ○ /blog 8.5 kB 128 kB
├ ○ /blog/[slug] 12.3 kB 132 kB
└ ○ /charts 45.2 kB 165 kB
+ First Load JS shared by all 115 kB
├ chunks/framework-[hash].js 42 kB
├ chunks/main-[hash].js 28 kB
├ chunks/pages/_app-[hash].js 35 kB
└ chunks/webpack-[hash].js 10 kB
○ (Static) automatically rendered as static HTML
λ (Server) server-side renders at runtime
Key Metrics:
- Size: Page-specific JavaScript
- First Load JS: Total JS loaded for initial render
- Shared chunks: Code shared across pages
Interactive Report
Open client.html or server.html in browser:
- Large boxes: Heavy dependencies
- Colors: Different packages
- Hover: See exact sizes
- Click: Drill down into dependencies
Common Issues
1. Large Dependencies
# Find large packages
cd apps/web
pnpm list --depth=0 | sort -k2 -n
# Example output:
# lodash 1.2 MB
# moment 500 KB
# recharts 300 KB
# @heroui/react 250 KB
Solutions:
// ❌ Import entire library
import _ from "lodash";
import moment from "moment";
// ✅ Import only what you need
import debounce from "lodash/debounce";
import groupBy from "lodash/groupBy";
// ✅ Use lighter alternatives
import { format } from "date-fns"; // Instead of moment
import dayjs from "dayjs"; // Smaller than moment
2. Duplicate Dependencies
# Check for duplicates
pnpm list <package-name>
# Example: Multiple versions of react
pnpm list react
# Output:
# @sgcarstrends/web
# ├── [email protected]
# └─┬ some-package
# └── [email protected] # Duplicate!
Solutions:
// package.json
{
"pnpm": {
"overrides": {
"react": "18.3.0",
"react-dom": "18.3.0"
}
}
}
3. Missing Code Splitting
// ❌ Import heavy component directly
import Chart from "@/components/Chart";
export default function Page() {
return <Chart data={data} />;
}
// ✅ Dynamic import with code splitting
import dynamic from "next/dynamic";
const Chart = dynamic(() => import("@/components/Chart"), {
loading: () => <div>Loading chart...</div>,
ssr: false, // Client-side only if needed
});
export default function Page() {
return <Chart data={data} />;
}
4. Large JSON/Data Files
// ❌ Import large JSON files
import brands from "@/data/car-brands.json"; // 500KB
// ✅ Load dynamically
export async function getBrands() {
const response = await fetch("/api/brands");
return response.json();
}
// ✅ Or use dynamic import
export async function getBrands() {
const { default: brands } = await import("@/data/car-brands.json");
return brands;
}
Optimization Techniques
1. Tree Shaking
// ✅ Named imports enable tree shaking
import { Button, Card } from "@heroui/react";
// ❌ Default import includes everything
import HeroUI from "@heroui/react";
Verify tree shaking:
// package.json
{
"sideEffects": false // Enable aggressive tree shaking
}
// Or specify side-effect files
{
"sideEffects": ["*.css", "*.scss"]
}
2. Code Splitting by Route
// Next.js automatically code-splits by route
// Each page becomes a separate chunk
// app/page.tsx -> chunk for /
// app/blog/page.tsx -> chunk for /blog
// app/charts/page.tsx -> chunk for /charts
// ✅ Additional manual splitting
const HeavyComponent = dynamic(() => import("./HeavyComponent"));
3. Lazy Loading
// ✅ Load components on interaction
"use client";
import { useState } from "react";
import dynamic from "next/dynamic";
const CommentForm = dynamic(() => import("./CommentForm"));
export default function BlogPost() {
const [showComments, setShowComments] = useState(false);
return (
<div>
<article>{/* post content */}</article>
<button onClick={() => setShowComments(true)}>
Show Comments
</button>
{showComments && <CommentForm />}
</div>
);
}
4. Optimize Dependencies
# Replace heavy packages with lighter alternatives
# ❌ moment (500KB)
pnpm remove moment
# ✅ date-fns (30KB) or dayjs (7KB)
pnpm add date-fns
# ❌ lodash (full library)
# ✅ lodash-es (ESM with tree-shaking)
pnpm add lodash-es
# ❌ axios (for simple requests)
# ✅ native fetch or ky (12KB)
pnpm add ky
5. Image Optimization
// ✅ Use Next.js Image component
import Image from "next/image";
export default function Logo() {
return (
<Image
src="/logo.png"
alt="Logo"
width={200}
height={100}
priority // For above-fold images
quality={75} // Reduce quality if acceptable
/>
);
}
// ✅ Use modern formats
// - WebP: 25-35% smaller than JPEG/PNG
// - AVIF: 50% smaller than JPEG (if supported)
6. Font Optimization
// app/layout.tsx
import { Inter } from "next/font/google";
// ✅ Load only needed weights and subsets
const inter = Inter({
subsets: ["latin"],
weight: ["400", "600", "700"], // Only load what you use
display: "swap",
preload: true,
});
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
);
}
Advanced Analysis
Webpack Bundle Analyzer
# For custom webpack configs
pnpm add -D webpack-bundle-analyzer
# View detailed dependency tree
ANALYZE=true pnpm build
Source Map Explorer
# Analyze source maps
pnpm add -D source-map-explorer
# Generate production build with source maps
pnpm build
# Analyze
npx source-map-explorer '.next/static/chunks/*.js'
Bundle Buddy
# Visualize bundle relationships
npx bundle-buddy '.next/**/*.js.map'
Monitoring Bundle Size
CI Bundle Size Check
# .github/workflows/bundle-size.yml
name: Bundle Size Check
on:
pull_request:
branches: [main]
jobs:
bundle-size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm -F @sgcarstrends/web build
- name: Analyze bundle
run: |
BUNDLE_SIZE=$(du -sh apps/web/.next/static | cut -f1)
echo "Bundle size: $BUNDLE_SIZE"
# Fail if bundle exceeds limit
SIZE_KB=$(du -sk apps/web/.next/static | cut -f1)
if [ $SIZE_KB -gt 500 ]; then
echo "Bundle size exceeds 500KB!"
exit 1
fi
- name: Comment PR
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '📦 Bundle size: ${{ env.BUNDLE_SIZE }}'
})
Bundle Size Tracking
# Track bundle size over time
echo "$(date +%Y-%m-%d),$(du -sk apps/web/.next/static | cut -f1)" >> bundle-history.csv
# Plot with gnuplot or spreadsheet
Performance Budgets
next.config.ts
// apps/web/next.config.ts
const nextConfig: NextConfig = {
// Warn if bundles exceed limits
onDemandEntries: {
maxInactiveAge: 25 * 1000,
pagesBufferLength: 2,
},
// Set performance budgets
experimental: {
optimizeCss: true,
optimizePackageImports: ["@heroui/react", "recharts"],
},
};
Lighthouse CI
# .lighthouserc.json
{
"ci": {
"collect": {
"startServerCommand": "pnpm start",
"url": ["http://localhost:3000", "http://localhost:3000/charts"]
},
"assert": {
"assertions": {
"categories:performance": ["error", { "minScore": 0.9 }],
"resource-summary:script:size": ["error", { "maxNumericValue": 300000 }],
"total-byte-weight": ["error", { "maxNumericValue": 500000 }]
}
}
}
}
Best Practices
1. Measure Before Optimizing
# ✅ Always measure first
ANALYZE=true pnpm build
# Identify actual bottlenecks
# Don't prematurely optimize
2. Prioritize Critical Path
// ✅ Load critical resources first
// Above-fold content, essential JS/CSS
// ❌ Don't block initial render
// Defer analytics, chat widgets, etc.
3. Use External CDN
// For heavy third-party libraries
// Load from CDN instead of bundling
// next.config.ts
const nextConfig: NextConfig = {
experimental: {
externalDir: true,
},
};
4. Regular Audits
# ✅ Run bundle analysis regularly
# - Before each release
# - When adding dependencies
# - After major refactors
ANALYZE=true pnpm build
Troubleshooting
Bundle Size Not Reducing
# Issue: Optimizations not working
# Solution: Check production build
# Ensure building for production
NODE_ENV=production pnpm build
# Verify minification
cat .next/static/chunks/main-*.js | head -n 1
# Should be minified (single line)
Analyzer Not Opening
# Issue: Bundle analyzer not showing reports
# Solution: Check environment variable
# Ensure ANALYZE is set
echo $ANALYZE # Should print "true"
# Run explicitly
cd apps/web
ANALYZE=true pnpm build
# Check for errors in build output
Large Unexplained Bundle
# Issue: Bundle larger than expected
# Solution: Investigate with source-map-explorer
pnpm build
npx source-map-explorer '.next/static/chunks/*.js' --html bundle-report.html
# Open bundle-report.html to see breakdown
References
- Next.js Bundle Analyzer: https://www.npmjs.com/package/@next/bundle-analyzer
- Webpack Bundle Analyzer: https://github.com/webpack-contrib/webpack-bundle-analyzer
- Web.dev Bundle Size: https://web.dev/your-first-performance-budget/
- Next.js Optimization: https://nextjs.org/docs/app/building-your-application/optimizing
- Related files:
apps/web/next.config.ts- Next.js configuration- Root CLAUDE.md - Performance guidelines
Best Practices Summary
- Analyze Regularly: Check bundle size before releases
- Code Split: Use dynamic imports for heavy components
- Tree Shake: Use named imports, mark side effects
- Optimize Dependencies: Replace heavy packages with lighter alternatives
- Lazy Load: Defer non-critical resources
- Monitor: Set up CI checks and performance budgets
- Use CDN: Offload heavy third-party libraries
- Image Optimization: Use Next.js Image with WebP/AVIF
Quick Install
/plugin add https://github.com/sgcarstrends/sgcarstrends/tree/main/bundle-analysisCopy and paste this command in Claude Code to install this skill
GitHub 仓库
Related Skills
subagent-driven-development
DevelopmentThis skill executes implementation plans by dispatching a fresh subagent for each independent task, with code review between tasks. It enables fast iteration while maintaining quality gates through this review process. Use it when working on mostly independent tasks within the same session to ensure continuous progress with built-in quality checks.
algorithmic-art
MetaThis Claude Skill creates original algorithmic art using p5.js with seeded randomness and interactive parameters. It generates .md files for algorithmic philosophies, plus .html and .js files for interactive generative art implementations. Use it when developers need to create flow fields, particle systems, or other computational art while avoiding copyright issues.
executing-plans
DesignUse the executing-plans skill when you have a complete implementation plan to execute in controlled batches with review checkpoints. It loads and critically reviews the plan, then executes tasks in small batches (default 3 tasks) while reporting progress between each batch for architect review. This ensures systematic implementation with built-in quality control checkpoints.
cost-optimization
OtherThis Claude Skill helps developers optimize cloud costs through resource rightsizing, tagging strategies, and spending analysis. It provides a framework for reducing cloud expenses and implementing cost governance across AWS, Azure, and GCP. Use it when you need to analyze infrastructure costs, right-size resources, or meet budget constraints.
