Files
2nd/10_Wiki/Topics/Frontend/웹 프론트엔드 성능 최적화.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

5.8 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-웹-프론트엔드-성능-최적화 웹 프론트엔드 성능 최적화 10_Wiki/Topics verified self
Frontend performance
Web perf
Core Web Vitals
none A 0.95 applied
performance
frontend
core-web-vitals
optimization
2026-05-10 pending
language framework
TypeScript Next.js / Vite

웹 프론트엔드 성능 최적화

매 한 줄

"매 LCP/INP/CLS 의 3 metric 을 따라 image, JS, layout 을 deliberate optimize". 2026 매 INP (Interaction to Next Paint) 가 FID 대체 → 매 long task 의 적극 splitting. 매 RUM 으로 매 측정, lab data 의 보완.

매 핵심

매 Core Web Vitals (2026)

  • LCP (Largest Contentful Paint): ≤ 2.5s — 매 hero image/text 의 render 시간.
  • INP (Interaction to Next Paint): ≤ 200ms — 매 user interaction 의 response.
  • CLS (Cumulative Layout Shift): ≤ 0.1 — 매 layout 안정성.

매 optimization layer

  1. Network: HTTP/3, CDN, preload, prefetch, brotli.
  2. JS: code splitting, tree shake, defer, async, lazy import.
  3. CSS: critical CSS inline, remove unused, contain.
  4. Image: AVIF/WebP, responsive srcset, lazy, dimension hints.
  5. Render: Server Components, streaming SSR, partial hydration.

매 응용

  1. Next.js App Router 매 RSC + streaming.
  2. Astro 매 island architecture.
  3. Image CDN (Cloudinary, Cloudflare Images) 매 auto format/size.

💻 패턴

Image — 매 next/image

import Image from 'next/image';

<Image
  src="/hero.jpg"
  alt="Hero"
  width={1600}
  height={900}
  priority // 매 above-fold
  sizes="(max-width: 768px) 100vw, 80vw"
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,..."
/>

Code splitting — 매 dynamic import

// 매 route-level: Next.js 자동
// 매 component-level: dynamic
import dynamic from 'next/dynamic';

const HeavyChart = dynamic(() => import('./HeavyChart'), {
  loading: () => <Skeleton />,
  ssr: false, // 매 client-only
});

LCP — 매 preload critical

<link rel="preload" as="image" href="/hero.avif"
  imagesrcset="/hero-mobile.avif 480w, /hero.avif 1600w"
  imagesizes="100vw" fetchpriority="high">

<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<link rel="dns-prefetch" href="https://analytics.example.com">

INP — 매 long task splitting

async function processLargeList(items: Item[]) {
  for (const [i, item] of items.entries()) {
    process(item);
    if (i % 50 === 0) {
      await new Promise((r) => setTimeout(r, 0)); // 매 yield
    }
  }
}

// 매 또는 scheduler API
import { scheduler } from 'scheduler';
await scheduler.yield();

CLS — 매 dimension reserve

/* 매 aspect-ratio */
.thumb {
  aspect-ratio: 16 / 9;
  width: 100%;
  background: #eee;
}

/* 매 font-display: optional → CLS 0 */
@font-face {
  font-family: 'Inter';
  src: url('/inter.woff2') format('woff2');
  font-display: optional; /* 매 swap 매 layout shift, optional 매 안정 */
}

Server Components — 매 zero-JS by default

// app/products/page.tsx — Server Component
async function ProductsPage() {
  const products = await db.products.findAll();
  return (
    <ul>
      {products.map((p) => <ProductCard key={p.id} {...p} />)}
    </ul>
  );
}
// 매 client component 만 JS 의 hydrate

RUM — 매 web-vitals 수집

import { onLCP, onINP, onCLS } from 'web-vitals';

function send(metric) {
  navigator.sendBeacon('/rum',
    JSON.stringify({ name: metric.name, value: metric.value, id: metric.id })
  );
}

onLCP(send);
onINP(send);
onCLS(send);

Critical CSS — 매 inline

<head>
<style>
  /* 매 above-fold critical CSS — beasties/critters 등으로 추출 */
  body { margin: 0; font-family: system-ui; }
  .header { background: #fff; height: 64px; }
</style>
<link rel="preload" href="/main.css" as="style" onload="this.rel='stylesheet'">
</head>

Service Worker — 매 stale-while-revalidate

// sw.js
self.addEventListener('fetch', (e) => {
  if (e.request.destination === 'image') {
    e.respondWith((async () => {
      const cache = await caches.open('img-v1');
      const cached = await cache.match(e.request);
      const networked = fetch(e.request).then((res) => {
        cache.put(e.request, res.clone()); return res;
      });
      return cached || networked;
    })());
  }
});

매 결정 기준

상황 Approach
매 hero image priority + preload + AVIF
매 below-fold widget dynamic import + ssr:false
매 long table virtualization (react-window)
매 large list iteration scheduler.yield
매 third-party script next/script with strategy

기본값: RSC + next/image + dynamic + Web Vitals RUM.

🔗 Graph

🤖 LLM 활용

언제: 매 perf audit (Lighthouse JSON 분석), 매 bundle size review, 매 RUM data triage. 언제 X: 매 actual measurement (lab/RUM 도구 가 더 정확).

안티패턴

  • 모든 component client: 매 RSC 무시 매 JS bundle 폭발.
  • lazy load hero image: 매 LCP 악화.
  • fixed-pixel layout: 매 mobile 매 CLS.
  • synchronous third-party: 매 main thread block.

🧪 검증 / 중복

  • Verified (web.dev, Next.js docs, Chrome DevRel).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — Core Web Vitals (LCP/INP/CLS), RSC, RUM 패턴 정리