← Back to list

bundle-optimization
by IvanTorresEdge
⭐ 0🍴 1📅 Jan 13, 2026
SKILL.md
name: bundle-optimization description: Bundle size optimization including tree shaking, code splitting, and dependency analysis. Use when reducing bundle size.
Bundle Optimization Skill
This skill covers techniques for optimizing JavaScript bundle size.
When to Use
Use this skill when:
- Reducing initial load time
- Analyzing bundle contents
- Implementing code splitting
- Replacing heavy dependencies
Core Principle
SHIP LESS JAVASCRIPT - Every kilobyte counts. Remove what you don't need, defer what you don't need immediately.
Bundle Analysis
Vite Bundle Analyzer
npm install -D rollup-plugin-visualizer
// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
react(),
visualizer({
filename: 'stats.html',
open: true,
gzipSize: true,
brotliSize: true,
}),
],
});
Next.js Bundle Analyzer
npm install -D @next/bundle-analyzer
// next.config.ts
import bundleAnalyzer from '@next/bundle-analyzer';
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
});
export default withBundleAnalyzer(config);
ANALYZE=true npm run build
Source Map Explorer
npx source-map-explorer dist/**/*.js
Code Splitting
Route-Based Splitting
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
function App(): React.ReactElement {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
Component-Level Splitting
const HeavyChart = lazy(() => import('./components/HeavyChart'));
function Dashboard(): React.ReactElement {
const [showChart, setShowChart] = useState(false);
return (
<div>
<button onClick={() => setShowChart(true)}>Show Chart</button>
{showChart && (
<Suspense fallback={<ChartSkeleton />}>
<HeavyChart />
</Suspense>
)}
</div>
);
}
Manual Chunks (Vite)
// vite.config.ts
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
'vendor-ui': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
'vendor-charts': ['recharts'],
},
},
},
},
Tree Shaking
Import Specific Functions
// ❌ Imports entire library
import _ from 'lodash';
_.debounce(fn, 300);
// ✅ Imports only what's needed
import debounce from 'lodash/debounce';
debounce(fn, 300);
// ✅ Or use lodash-es for better tree shaking
import { debounce } from 'lodash-es';
Icon Libraries
// ❌ Imports all icons
import * as Icons from 'lucide-react';
// ✅ Imports specific icons
import { Home, Settings, User } from 'lucide-react';
Date Libraries
// ❌ moment.js (330KB)
import moment from 'moment';
// ✅ date-fns (tree-shakeable)
import { format, parseISO } from 'date-fns';
// ✅ dayjs (2KB)
import dayjs from 'dayjs';
Heavy Dependency Alternatives
| Heavy Library | Size | Alternative | Size |
|---|---|---|---|
| moment.js | 330KB | date-fns | ~20KB |
| lodash | 530KB | lodash-es (specific) | ~5KB |
| axios | 40KB | fetch (native) | 0KB |
| uuid | 18KB | crypto.randomUUID() | 0KB |
| classnames | 1.8KB | clsx | 0.3KB |
Dynamic Imports
Conditional Loading
async function loadPolyfill(): Promise<void> {
if (!('IntersectionObserver' in window)) {
await import('intersection-observer');
}
}
async function loadAnalytics(): Promise<void> {
if (process.env.NODE_ENV === 'production') {
const { initAnalytics } = await import('./analytics');
initAnalytics();
}
}
Feature-Based Loading
const PDFViewer = lazy(() => import('./PDFViewer'));
const VideoPlayer = lazy(() => import('./VideoPlayer'));
function MediaViewer({ type, src }: MediaViewerProps): React.ReactElement {
if (type === 'pdf') {
return (
<Suspense fallback={<Loading />}>
<PDFViewer src={src} />
</Suspense>
);
}
if (type === 'video') {
return (
<Suspense fallback={<Loading />}>
<VideoPlayer src={src} />
</Suspense>
);
}
return <img src={src} alt="" />;
}
Prefetching
Link Prefetching
// React Router
import { Link } from 'react-router-dom';
function Nav(): React.ReactElement {
const prefetchDashboard = (): void => {
import('./pages/Dashboard');
};
return (
<Link to="/dashboard" onMouseEnter={prefetchDashboard}>
Dashboard
</Link>
);
}
Next.js Prefetching
import Link from 'next/link';
// Automatic prefetching (default)
<Link href="/dashboard">Dashboard</Link>
// Disable prefetching
<Link href="/dashboard" prefetch={false}>Dashboard</Link>
CSS Optimization
Tailwind CSS Purging
// tailwind.config.ts
export default {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
// Tailwind automatically purges unused styles in production
};
CSS-in-JS Extraction
Use build-time extraction for CSS-in-JS:
// Use vanilla-extract for zero-runtime CSS
import { style } from '@vanilla-extract/css';
export const button = style({
backgroundColor: 'blue',
color: 'white',
});
Image Optimization
// Use next/image for automatic optimization
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // For LCP images
placeholder="blur"
blurDataURL="..."
/>
// Or use vite-imagetools
import heroImage from './hero.jpg?w=1200&format=webp';
Monitoring Bundle Size
Size Limits
npm install -D size-limit @size-limit/preset-app
// package.json
{
"size-limit": [
{
"path": "dist/**/*.js",
"limit": "200 KB"
}
],
"scripts": {
"size": "size-limit",
"size-check": "size-limit --ci"
}
}
CI Integration
# .github/workflows/size.yml
- name: Check bundle size
run: npm run size-check
Bundle Size Targets
| Metric | Target | Good | Critical |
|---|---|---|---|
| Initial JS | < 100KB | < 150KB | > 200KB |
| Per-route JS | < 50KB | < 100KB | > 150KB |
| Total JS | < 500KB | < 750KB | > 1MB |
Optimization Checklist
- Analyze bundle with visualizer
- Implement route-based code splitting
- Import specific functions (tree shaking)
- Replace heavy dependencies
- Lazy load heavy components
- Optimize images
- Set up size limits in CI
- Monitor bundle size over time
Notes
- Always analyze before optimizing
- Focus on initial load first
- Use lazy loading for below-the-fold content
- Consider server components (Next.js) to reduce client JS
Score
Total Score
60/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon