--- name: frontend-bundle-analysis-and-optimization version: "1.0" description: > Bundle analysis and optimization strategies for Next.js applications using Webpack and Turbopack. PROACTIVELY activate for: (1) Analyzing bundle size, (2) Implementing code splitting, (3) Configuring tree shaking, (4) Dynamic imports, (5) Webpack/Turbopack configuration. Triggers: "bundle size", "webpack", "turbopack", "code splitting", "tree shaking", "lazy loading", "bundle analyzer", "dynamic import" core-integration: techniques: primary: ["systematic_analysis"] secondary: ["structured_evaluation"] contracts: input: "none" output: "none" patterns: "none" rubrics: "none" --- # Frontend Bundle Analysis and Optimization This skill provides actionable strategies for analyzing and reducing JavaScript bundle size using Webpack or Turbopack, focusing on code splitting, tree shaking, and dependency analysis. ## Bundle Analysis with @next/bundle-analyzer Visual bundle analysis is the first step in any optimization effort. It shows which modules contribute most to bundle size. ### Setup ```bash npm install @next/bundle-analyzer --save-dev ``` ```js // next.config.js const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }) module.exports = withBundleAnalyzer({ // Your Next.js config }) ``` ### Usage ```bash ANALYZE=true npm run build ``` This opens an interactive treemap showing: - Which dependencies are largest - Duplicate packages across chunks - Opportunities for code splitting ### Reading the Treemap - **Large blocks**: Heavy dependencies (consider alternatives or lazy loading) - **Duplicate colors**: Same package in multiple chunks (configure splitChunks) - **Vendor chunks**: Third-party libraries (good candidates for caching) ## Dynamic Imports Dynamic imports enable code splitting, loading JavaScript only when needed. ### Component-Based Code Splitting ```tsx // BAD: Loads heavy component immediately import HeavyChart from '@/components/HeavyChart' export default function Dashboard() { return } // GOOD: Loads only when rendered import dynamic from 'next/dynamic' const HeavyChart = dynamic(() => import('@/components/HeavyChart'), { loading: () => , ssr: false, // Disable SSR if component uses browser APIs }) export default function Dashboard() { return } ``` ### Conditional Loading ```tsx // Load component only when needed import dynamic from 'next/dynamic' import { useState } from 'react' const AdminPanel = dynamic(() => import('@/components/AdminPanel')) export default function Dashboard({ isAdmin }: { isAdmin: boolean }) { const [showAdmin, setShowAdmin] = useState(false) return (

Dashboard

{isAdmin && ( )} {/* Only loads when button is clicked */} {showAdmin && }
) } ``` ### Named Exports ```tsx // For named exports, use an object with 'default' const DynamicComponent = dynamic(() => import('@/components/Hello').then((mod) => mod.Hello) ) ``` ### Multiple Components ```tsx // BAD: Import entire library import { ComponentA, ComponentB } from 'heavy-library' // GOOD: Split into separate chunks const ComponentA = dynamic(() => import('heavy-library/ComponentA')) const ComponentB = dynamic(() => import('heavy-library/ComponentB')) ``` ### With Custom Loading State ```tsx const HeavyEditor = dynamic(() => import('@/components/RichTextEditor'), { loading: () => (
), ssr: false, }) ``` ## Route-Based Code Splitting Next.js automatically code-splits by route, but you can optimize further. ### Lazy Route Components ```tsx // app/dashboard/page.tsx import dynamic from 'next/dynamic' // Heavy components loaded only on this route const Analytics = dynamic(() => import('@/components/Analytics')) const UserTable = dynamic(() => import('@/components/UserTable')) export default function DashboardPage() { return (
) } ``` ### Shared Layouts ```tsx // app/layout.tsx // Common layout code shared across routes export default function RootLayout({ children }) { return (
{/* Shared, in main bundle */} {children} {/* Route-specific, code-split */}