Chuyển đến nội dung chính

Bài 20: Performance Optimization

Core Web Vitals optimization. React.lazy, dynamic imports. Bundle analysis, tree shaking. Memoization patterns. Image/font optimization, CDN strategies.

💻 Lập trình — Bài 20 Bài 20: Performance Optimization

React & Next.js: Từ Cơ bản đến Nâng cao

Phần 6: Testing, Deployment & Production

xdev.asia

1. Core Web Vitals

MetricMô tảGoodCách cải thiện
LCPLargest Contentful Paint< 2.5sPriority images, preload fonts
INPInteraction to Next Paint< 200msReduce JS, use transitions
CLSCumulative Layout Shift< 0.1Set image sizes, avoid FOUT

2. Dynamic Imports & Code Splitting

import dynamic from 'next/dynamic';

// Lazy load heavy component
const CodeEditor = dynamic(() => import('@/components/CodeEditor'), {
  loading: () => <div>Loading editor...</div>,
  ssr: false, // Client-only component
});

// Conditional dynamic import
const AdminPanel = dynamic(() => import('@/components/AdminPanel'));

export default function Page({ isAdmin }: { isAdmin: boolean }) {
  return (
    <div>
      <CodeEditor />
      {isAdmin && <AdminPanel />}
    </div>
  );
}

3. Memoization Patterns

import { memo, useMemo, useCallback } from 'react';

// memo — skip re-render if props unchanged
const ExpensiveList = memo(function ExpensiveList({ items }: { items: Item[] }) {
  return (
    <ul>
      {items.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  );
});

// useMemo — cache expensive computation
function Dashboard({ data }: { data: number[] }) {
  const stats = useMemo(() => ({
    total: data.reduce((a, b) => a + b, 0),
    average: data.reduce((a, b) => a + b, 0) / data.length,
    max: Math.max(...data),
  }), [data]);

  return <div>Total: {stats.total}</div>;
}

// useCallback — stable function reference
function Parent() {
  const handleClick = useCallback((id: string) => {
    console.log('Clicked:', id);
  }, []);

  return <ExpensiveChild onClick={handleClick} />;
}

4. Bundle Analysis

npm install -D @next/bundle-analyzer
// next.config.ts
import withBundleAnalyzer from '@next/bundle-analyzer';

const config = withBundleAnalyzer({
  enabled: process.env.ANALYZE === 'true',
})({
  // ...other config
});

export default config;
# Analyze bundle
ANALYZE=true npm run build

5. Font Optimization

// app/layout.tsx
import { Inter, JetBrains_Mono } from 'next/font/google';

const inter = Inter({
  subsets: ['latin', 'vietnamese'],
  display: 'swap',
  variable: '--font-inter',
});

const mono = JetBrains_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-mono',
});

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="vi" className={`${inter.variable} ${mono.variable}`}>
      <body className="font-sans">{children}</body>
    </html>
  );
}

6. Caching Headers

// next.config.ts
const config = {
  async headers() {
    return [
      {
        source: '/images/:path*',
        headers: [
          { key: 'Cache-Control', value: 'public, max-age=31536000, immutable' },
        ],
      },
      {
        source: '/api/:path*',
        headers: [
          { key: 'Cache-Control', value: 'public, s-maxage=60, stale-while-revalidate=300' },
        ],
      },
    ];
  },
};

7. React Compiler (Experimental)

// next.config.ts
const config = {
  experimental: {
    reactCompiler: true, // Auto-memoize components
  },
};

Bài tiếp theo: Docker & CI/CD — containerization, GitHub Actions, Vercel deployment.