スキル一覧に戻る
IvanTorresEdge

bundle-optimization

by IvanTorresEdge

0🍴 1📅 2026年1月13日
GitHubで見るManusで実行

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 LibrarySizeAlternativeSize
moment.js330KBdate-fns~20KB
lodash530KBlodash-es (specific)~5KB
axios40KBfetch (native)0KB
uuid18KBcrypto.randomUUID()0KB
classnames1.8KBclsx0.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

// 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

MetricTargetGoodCritical
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

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

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

レビュー

💬

レビュー機能は近日公開予定です