Claude Code Plugins

Community-maintained marketplace

Feedback

bundle-optimization

@IvanTorresEdge/molcajete.ai
0
0

Bundle size optimization including tree shaking, code splitting, and dependency analysis. Use when reducing bundle size.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

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