Claude Code Plugins

Community-maintained marketplace

Feedback

Optimize Next.js bundle size with code splitting, tree shaking, lazy loading, and build configuration. Apply when improving performance, reducing bundle size, analyzing dependencies, or optimizing load times.

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 Performance Optimization
description Optimize Next.js bundle size with code splitting, tree shaking, lazy loading, and build configuration. Apply when improving performance, reducing bundle size, analyzing dependencies, or optimizing load times.
allowed-tools Read, Write, Edit, Bash
version 1.0.0

Performance Optimization

Systematic performance optimization for faster load times and reduced resource consumption.

Overview

This Skill enforces:

  • Code splitting and lazy loading
  • Tree shaking unused code
  • Bundle size analysis
  • Dynamic imports
  • Image optimization
  • Build configuration tuning
  • Compression strategies
  • Caching headers

Apply when optimizing performance, reducing bundle size, or improving load times.

Code Splitting

Route-Based Splitting

// Next.js automatically splits by route
app/
├── dashboard/page.tsx    // bundle-1.js
├── settings/page.tsx     // bundle-2.js
└── analytics/page.tsx    // bundle-3.js

// Only loaded when user visits that route

Component-Level Splitting

// ✅ GOOD: Lazy load heavy components
import dynamic from 'next/dynamic';

const HeavyChart = dynamic(() => import('@/components/Chart'), {
  loading: () => <div>Loading chart...</div>,
  ssr: false  // Don't render on server
});

export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <HeavyChart />  {/* Loaded only when page loads */}
    </div>
  );
}

// ❌ BAD: Import everything upfront
import { HeavyChart } from '@/components/Chart';
// Included in main bundle even if user doesn't need it

Dynamic Imports

// Load module only when needed
app.get('/api/reports', async (req, res) => {
  const { generateReport } = await import('@/lib/report-generator');
  const result = await generateReport();
  res.json(result);
});

// ✅ GOOD: Module loaded only for /api/reports
// ❌ BAD: Module loaded at startup
const { generateReport } = require('@/lib/report-generator');

Tree Shaking

Configure package.json

{
  "name": "myapp",
  "sideEffects": false,  // No side effects, safe to remove
  "exports": {
    ".": "./dist/index.js",
    "./utils": "./dist/utils.js"
  }
}

Use Named Exports

// ✅ GOOD: Tree shakeable (named exports)
export function usedFunction() { }
export function unusedFunction() { }

// Only used functions included in bundle
import { usedFunction } from './module';

// ❌ BAD: Not tree shakeable (default export)
export default {
  usedFunction,
  unusedFunction
};

// Everything included in bundle
import module from './module';
module.usedFunction();

Import Only What You Need

// ✅ GOOD: Import specific function
import { debounce } from 'lodash-es';

// ❌ BAD: Import entire library
import * as _ from 'lodash';
const debounce = _.debounce;
// Entire library included

Bundle Analysis

Analyze Bundle Size

# Install analyzer
npm install -D @next/bundle-analyzer

# Configure next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});

module.exports = withBundleAnalyzer({
  // Next.js config
});

# Analyze
ANALYZE=true npm run build

Tools for Analysis

# webpack-bundle-analyzer
npm install -D webpack-bundle-analyzer

# esbuild
npm install -D esbuild

# Source map explorer
npm install -D source-map-explorer
npm run source-map-explorer 'dist/**/*.js.map'

Image Optimization

Next.js Image Component

// ✅ GOOD: Optimized images
import Image from 'next/image';

export function UserAvatar({ src, alt }) {
  return (
    <Image
      src={src}
      alt={alt}
      width={200}
      height={200}
      priority  // Preload critical images
      quality={80}  // 80% quality (good trade-off)
      placeholder="blur"  // Blur while loading
    />
  );
}

// ❌ BAD: Unoptimized
<img src={imageUrl} alt={alt} />
// No lazy loading, no optimization

Image Formats

// ✅ GOOD: Modern formats with fallback
<picture>
  <source srcSet={image.webp} type="image/webp" />
  <img src={image.jpg} alt="" />
</picture>

// ✅ GOOD: WebP with Next.js
<Image
  src={image}
  alt={alt}
  quality={80}
  format="webp"
/>

Build Configuration

next.config.js Optimization

/** @type {import('next').NextConfig} */
const nextConfig = {
  // Enable SWC minification (faster)
  swcMinify: true,

  // Optimize packages
  optimizePackageImports: [
    '@mui/material',
    '@mui/icons-material',
    'lodash-es'
  ],

  // Image optimization
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com'
      }
    ],
    formats: ['image/avif', 'image/webp'],
    imageSizes: [16, 32, 48, 64, 96, 128, 256],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920]
  },

  // Compression
  compress: true,

  // Generate source maps only in dev
  productionBrowserSourceMaps: false
};

module.exports = nextConfig;

Lazy Loading Components

React Suspense

import { Suspense } from 'react';

async function SlowComponent() {
  // Simulate slow operation
  await new Promise(r => setTimeout(r, 3000));
  return <div>Loaded after 3 seconds</div>;
}

export default function Page() {
  return (
    <div>
      <h1>Dashboard</h1>
      
      {/* Show immediately */}
      <p>Quick stats</p>
      
      {/* Lazy load with fallback */}
      <Suspense fallback={<div>Loading...</div>}>
        <SlowComponent />
      </Suspense>
    </div>
  );
}

Dynamic Suspense

import dynamic from 'next/dynamic';
import { Suspense } from 'react';

const LazyChart = dynamic(
  () => import('@/components/Chart'),
  { 
    loading: () => <div>Loading chart...</div>,
    ssr: false
  }
);

export default function Dashboard() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyChart />
    </Suspense>
  );
}

Performance Metrics

Web Vitals

// lib/web-vitals.ts
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

function sendToAnalytics(metric) {
  console.log(metric);
  // Send to analytics service
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);

Caching Strategies

HTTP Caching Headers

// ✅ GOOD: Cache static assets long-term
response.headers.set('Cache-Control', 'public, max-age=31536000, immutable');

// ✅ GOOD: Cache HTML (revalidate frequently)
response.headers.set('Cache-Control', 'public, max-age=3600, s-maxage=3600');

// ✅ GOOD: No cache for API responses
response.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate');

Service Worker Caching

// lib/service-worker.ts
const CACHE_NAME = 'v1';
const urlsToCache = [
  '/',
  '/offline.html',
  '/styles/main.css',
  '/scripts/main.js'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(urlsToCache);
    })
  );
});

self.addEventListener('fetch', (event) => {
  if (event.request.method !== 'GET') return;
  
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

Compression

// ✅ GOOD: Enable compression
import compression from 'compression';

app.use(compression());

// Middleware in Next.js
export async function middleware(request: NextRequest) {
  const response = NextResponse.next();
  response.headers.set('Content-Encoding', 'gzip');
  return response;
}

Anti-Patterns

// ❌ BAD: Import entire library
import _ from 'lodash';
_.debounce(fn, 300);

// ✅ GOOD: Import specific function
import { debounce } from 'lodash-es';
debounce(fn, 300);

// ❌ BAD: Large unoptimized image
<img src={largeImage} alt="" />

// ✅ GOOD: Optimized with Next.js Image
<Image src={optimizedImage} alt="" quality={80} />

// ❌ BAD: No code splitting
import * from './all-components';

// ✅ GOOD: Lazy load
const Component = dynamic(() => import('./heavy-component'));

// ❌ BAD: No caching
response.headers.set('Cache-Control', 'no-cache');

// ✅ GOOD: Cache appropriately
response.headers.set('Cache-Control', 'public, max-age=31536000');

Verification Before Production

  • Bundle size analyzed
  • Code splitting enabled for routes
  • Heavy components lazy loaded
  • Tree shaking configured
  • Images optimized (Next.js Image)
  • Unused packages removed
  • Build optimized (SWC, minification)
  • Caching headers set
  • Service Worker (if offline support needed)
  • Web Vitals monitored

Integration with Project Standards

Enforces performance optimization:

  • Fast page loads (better UX)
  • Reduced bandwidth usage
  • Improved SEO (Core Web Vitals)
  • Better mobile experience

Resources