본문 바로가기
Frontend2026년 4월 23일10분 읽기

Web Performance 2026 — INP 최적화 + Speculation Rules 실전

YS
김영삼
조회 1
Web Performance 2026 — INP 최적화 + Speculation Rules 실전

핵심 요약

2024년 3월부터 INP가 FID를 대체. 2026년 시점 INP 최적화는 SEO·UX의 baseline. Speculation Rules는 사용자가 클릭하기 전에 다음 페이지를 미리 받아 거의 0초 전환을 만든다.

  • INP 좋음: ≤ 200ms / 개선 필요: 200~500ms / 나쁨: > 500ms
  • Speculation Rules: Chrome 121+ (2024-01)부터 안정
  • 최신 트렌드: View Transitions API + INP + 이미지 최적화 종합

1. INP 측정·디버깅

// web-vitals 라이브러리
import { onINP } from 'web-vitals'

onINP((metric) => {
  console.log('INP:', metric.value, 'ms')
  // 분석 도구로 전송
})

Chrome DevTools Performance

  • Interaction 트랙으로 가장 느린 인터랙션 식별
  • script 작업이 50ms 넘는 것 찾기 (Long Tasks)
  • main thread blocking 추적

2. INP 주요 원인 5가지

1) 무거운 JS 핸들러

// ❌ 동기 무거운 작업
button.addEventListener('click', () => {
  const result = heavyComputation(data)  // 200ms
  render(result)
})

// ✅ scheduler.yield() 또는 setTimeout으로 yield
button.addEventListener('click', async () => {
  await scheduler.yield()  // 메인 스레드 양보
  const result = await heavyComputation(data)
  render(result)
})

2) 큰 React 트리 재렌더

// ❌ 모든 리스트 재렌더
function List({ items }) {
  return items.map(i => <Item data={i} />)
}

// ✅ memoization + virtualization
import { memo } from 'react'
import { FixedSizeList } from 'react-window'

const Item = memo(({ data }) => ...)

function List({ items }) {
  return (
    <FixedSizeList height={600} itemCount={items.length} itemSize={50}>
      {({ index }) => <Item data={items[index]} />}
    </FixedSizeList>
  )
}

3) 동기 네트워크 호출

// ❌ navigator.sendBeacon에 큰 동기 데이터
// ✅ 작은 단위로 분할 + Background Tasks API
async function trackEvent(data) {
  if ('requestIdleCallback' in window) {
    requestIdleCallback(() => {
      navigator.sendBeacon('/track', JSON.stringify(data))
    })
  }
}

4) Layout Thrashing

// ❌ read-write-read-write
for (const el of elements) {
  const h = el.offsetHeight  // read (forces layout)
  el.style.height = (h + 10) + 'px'  // write
  // 다음 read가 layout을 다시 트리거
}

// ✅ batch read first, then write
const heights = elements.map(el => el.offsetHeight)
elements.forEach((el, i) => {
  el.style.height = (heights[i] + 10) + 'px'
})

5) 큰 이미지 디코딩

<img
  src="photo.jpg"
  decoding="async"
  loading="lazy"
  width="800" height="600"
/>

3. Speculation Rules — 사전 로드

<script type="speculationrules">
{
  "prerender": [
    {
      "source": "list",
      "urls": ["/popular", "/about"]
    },
    {
      "source": "document",
      "where": { "href_matches": "/article/*" },
      "eagerness": "moderate"
    }
  ]
}
</script>

eagerness 옵션:

  • immediate: 페이지 로드 즉시
  • eager: 호버·근접 시
  • moderate: 약간의 호버·터치 후
  • conservative: 거의 클릭 직전만

실측: 대부분 클릭이 거의 0초 전환. LCP 평균 70% 감소.

4. View Transitions API

// 페이지 전환 애니메이션
document.startViewTransition(() => {
  updateDOMSomehow()
})
/* CSS */
@view-transition {
  navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.3s;
}

.hero {
  view-transition-name: hero-image;
}

5. 이미지 최적화 체크리스트

  • WebP·AVIF 사용 (PNG·JPG 대비 30~50% 작음)
  • responsive: srcset + sizes 명시
  • LCP 이미지에는 fetchpriority="high" + preload
  • 나머지는 loading="lazy" + decoding="async"
  • width·height 명시 (CLS 방지)
  • placeholder (blur·shimmer)
<link rel="preload" as="image" href="hero.webp" fetchpriority="high" />

<img
  src="hero.webp"
  srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
  sizes="(max-width: 600px) 100vw, 50vw"
  width="1200" height="675"
  fetchpriority="high"
  alt="..."
/>

6. JS 분할 — Dynamic Import

// 라우트 단위
const Heavy = lazy(() => import('./HeavyChart'))

// 인터랙션 시점
button.addEventListener('click', async () => {
  const { generatePDF } = await import('./pdf-gen')
  generatePDF()
})

7. 폰트 최적화

<link rel="preload" href="Pretendard.woff2" as="font" type="font/woff2" crossorigin />

<style>
@font-face {
  font-family: 'Pretendard';
  src: url('Pretendard.woff2') format('woff2');
  font-display: swap;  /* 폰트 로드 전 fallback 즉시 표시 */
}
</style>

8. 측정·모니터링

도구용도
PageSpeed Insights실측 + 진단
WebPageTest네트워크별 시뮬레이션
Lighthouse CIPR 단위 회귀 감지
Real User Monitoring (Sentry·Datadog)실제 사용자 INP·LCP

9. 종합 효과 사례

지표beforeafter
INP340ms120ms
LCP2.4초0.8초
전환율baseline+18%
SEO 트래픽baseline+24% (3개월 후)

자주 묻는 질문

모든 페이지에 Speculation Rules 적용?고트래픽 링크에만. 모든 링크 prerender하면 서버 부하·낭비 큼.

INP 측정이 정확한 도구?

Real User Monitoring (실제 사용자 데이터). Lighthouse는 lab 환경이라 실측과 다를 수 있음.

React가 INP에 불리한가?큰 트리는 그렇다. 작은 컴포넌트 + memo + virtualization으로 대부분 해결. Solid·Svelte가 약간 유리하지만 큰 차이 아님.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록