Communitygithub.com

Blaise1030/astro-marketing

필드 및 실험실 증거를 사용하여 Core Web Vitals(LCP, INP, CLS)를 최적화하여 더 나은 페이지 경험을 제공합니다. 'Core Web Vitals 개선', 'LCP 수정', 'CLS 감소', 'INP 최적화', '페이지 경험 최적화', '레이아웃 시프트 수정'과 같은 요청이 있을 때 사용하세요.

astro-marketing란 무엇인가요?

이 스킬은 Core Web Vitals(LCP, INP, CLS)를 최적화하기 위한 체계적인 워크플로우와 진단 기술을 제공합니다. Chrome 사용자 경험 보고서(CrUX)의 필드 데이터를 통해 실제 사용자 영향을 파악하고, 브라우저 성능 트레이스를 분석하여 근본 원인을 진단합니다. Google이 75번째 백분위수 임계값을 사용하여 측정한다는 점을 강조하며, 최적화 전후에 항상 측정할 것을 권장합니다. Next.js, React, Vue/Nuxt와 같은 주요 프레임워크에 대한 구체적인 수정 사항과 함께 LCP 리소스 최적화, INP 상호작용 지연 분석, CLS 레이아웃 시프트 방지 전략을 다룹니다. Chrome 전용이지만 점진적 개선으로 사용할 수 있는 Speculation Rules API(사전 렌더링)에 대한 지침도 포함되어 있습니다. 이 스킬은 Chrome DevTools MCP, Lighthouse, PageSpeed Insights, 자체 RUM(Real User Monitoring)과 같은 다양한 측정 소스와 통합되어 개발자와 AI 에이전트가 성능 병목 지점을 정확히 찾아내고 해결할 수 있도록 지원합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Blaise1030/astro-marketing/tree/HEAD/.agents/skills/core-web-vitals

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

미리보기

스킬 README에서

astro-marketing preview

문서

Core Web Vitals 최적화

필드 데이터를 사용하여 사용자 영향을 식별하고 브라우저 트레이스를 통해 원인을 진단하여 세 가지 Core Web Vitals를 집중적으로 최적화합니다.

최적화 전에 측정하세요

실행 가능한 URL이 제공되면 성능 측정 워크플로우를 읽으세요. 다음 순서를 선호합니다:

  1. 페이지 수준 CrUX p75 데이터를 확인하고, 페이지 데이터를 사용할 수 없는 경우 출처(origin) 대체 데이터를 명확히 표시합니다.
  2. 명시된 조건에서 브라우저 성능 트레이스를 기록합니다. Chrome DevTools MCP를 사용하면 트레이스 요약에 관찰된 실험실 메트릭과 함께 CrUX를 포함할 수 있습니다.
  3. 실패하는 메트릭과 관련된 인사이트만 분석한 다음, 관련 코드와 리소스를 검사합니다.
  4. 수정 후 동등한 실험실 측정을 다시 실행합니다. 즉각적인 필드 개선을 주장하지 마세요. CrUX 및 자체 RUM에는 새로운 사용자 방문이 필요합니다.

소스 코드만 사용 가능한 경우, 잠재적 원인을 식별할 수는 있지만 런타임 증거 없이 LCP, INP 또는 CLS가 실패했다고 주장하지 마세요.

세 가지 메트릭

메트릭측정 항목우수개선 필요나쁨
LCP로딩≤ 2.5초2.5초 – 4초> 4초
INP상호작용≤ 200ms200ms – 500ms> 500ms
CLS시각적 안정성≤ 0.10.1 – 0.25> 0.25

Google은 75번째 백분위수로 측정합니다. 즉, 페이지 방문의 75%가 "우수" 임계값을 충족해야 합니다.


LCP: Largest Contentful Paint (최대 콘텐츠풀 페인트)

LCP는 가장 큰 가시 콘텐츠 요소가 렌더링되는 시점을 측정합니다. 일반적으로 다음 항목입니다:

  • 히어로 이미지 또는 비디오
  • 큰 텍스트 블록
  • 배경 이미지
  • <svg> 요소

일반적인 LCP 문제

1. 느린 서버 응답 (TTFB > 800ms)

수정: CDN, 캐싱, 최적화된 백엔드, 엣지 렌더링

2. 렌더링 차단 리소스

<!-- ❌ 렌더링 차단 -->
<link rel="stylesheet" href="/all-styles.css">

<!-- ✅ 중요 CSS는 인라인, 나머지는 지연 -->
<style>/* 중요 접경(above-fold) CSS */</style>
<link rel="preload" href="/styles.css" as="style" 
      onload="this.onload=null;this.rel='stylesheet'">

3. 느린 리소스 로드 시간

<!-- ❌ LCP 이미지가 스타일시트 로드 후에야 발견됨 -->
<div class="hero"></div>

<!-- ✅ 초기 HTML에서 발견 가능하고 우선순위가 지정됨 -->
<link rel="preload" href="/hero.webp" as="image" fetchpriority="high">
<img src="/hero.webp" alt="Hero" fetchpriority="high">

fetchpriority="high"가 포함된 발견 가능한 <img>를 선호하세요. 트레이스에서 리소스가 늦게 발견될 것으로 보이는 경우에만 preload를 추가하세요. 중복되거나 추측성 preload는 대역폭 경합을 유발할 수 있습니다.

4. 클라이언트 측 렌더링 지연

// ❌ JavaScript 이후에 콘텐츠 로드
useEffect(() => {
  fetch('/api/hero-text').then(r => r.json()).then(setHeroText);
}, []);

// ✅ 서버 측 또는 정적 렌더링
// SSR, SSG 또는 스트리밍을 사용하여 콘텐츠가 포함된 HTML 전송
export async function getServerSideProps() {
  const heroText = await fetchHeroText();
  return { props: { heroText } };
}

5. Speculation Rules API로 탐색을 즉시 만들기

예측 가능한 동일 출처(same-origin) 여정이 있는 사이트의 경우, 다음 페이지를 사전 렌더링하면 성공적인 후속 탐색 속도를 크게 높일 수 있습니다. 이는 현재 페이지의 LCP를 수정하는 대체재가 아닌, 측정된 탐색 최적화로 취급하세요.

<script type="speculationrules">
{
  "prerender": [{
    "where": { "href_matches": "/*" },
    "eagerness": "moderate"
  }]
}
</script>

현재 Chrome 동작은 선택을 안내하기에 충분히 구체적입니다:

eagerness트리거
conservative포인터 또는 터치 다운
moderate데스크탑: 200ms 호버, 또는 이전 포인터 다운; 모바일: 뷰포트 휴리스틱
eagerChrome 143+: 데스크탑 10ms 호버; 모바일 앵커가 뷰포트에 진입한 후 50ms
immediate규칙이 관찰되는 즉시

규칙을 확장하기 전에 보수적으로 시작하고 예측 적중률, 전송된 바이트, 서버 부하, 탐색 개선을 측정하세요. 시간에 민감한 동작을 하드코딩하기 전에 Chrome의 유지 관리되는 eagerness 문서를 다시 확인하세요.

주의사항:

  • 대역폭/CPU 비용. 각 사전 렌더링은 대략 전체 페이지 로드와 같습니다. where를 신중하게 범위를 지정하고 (href_matches 패턴, 로그아웃/체크아웃 제외) 소규모 사이트 외에는 immediate를 피하세요.
  • 부작용이 조기에 발생합니다. 분석, 광고 및 로드 시 실행되는 모든 코드는 사용자가 탐색할 때가 아닌 사전 렌더링이 시작될 때 실행됩니다. prerenderingchange 이벤트 또는 document.prerendering에서 부작용을 게이트하세요.
  • Chromium 전용. Safari와 Firefox는 스크립트를 무시합니다. 이는 점진적 개선(progressive enhancement)이며, 절대 회귀(regression)가 아닙니다.

LCP 최적화 체크리스트

- [ ] TTFB < 800ms (CDN, 엣지 캐싱 사용)
- [ ] LCP 리소스가 초기 HTML에서 발견 가능하고 우선순위가 지정됨; 트레이스에서 늦은 발견을 보여주는 경우에만 preload
- [ ] LCP 이미지 최적화 (WebP/AVIF, 올바른 크기)
- [ ] 중요 CSS 인라인 (< 14KB)
- [ ] <head>에 렌더링 차단 JavaScript 없음
- [ ] 글꼴이 텍스트 렌더링을 차단하지 않음 (font-display: swap)
- [ ] LCP 요소가 초기 HTML에 있음 (JS로 렌더링되지 않음)
- [ ] 다음 탐색 가능성을 위해 Speculation Rules 추가 (moderate eagerness)

LCP 요소 식별

이 스니펫은 현재 페이지 세션을 진단합니다. 필드 데이터가 아닙니다.

// LCP 요소 찾기
new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];
  console.log('LCP element:', lastEntry.element);
  console.log('LCP time:', lastEntry.startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });

INP: Interaction to Next Paint (상호작용에서 다음 페인트까지)

INP는 방문 중 클릭, 탭, 키 누름에 대한 응답성을 측정합니다. 입력 지연, 처리 시간, 프레젠테이션 지연을 별도로 진단하세요. 느린 상호작용은 핸들러 전 메인 스레드 경합, 값비싼 애플리케이션 작업 또는 그 이후의 지연된 렌더링과 관련될 수 있습니다.

필드 INP가 좋지 않거나 트레이스에서 느린 상호작용을 식별한 경우, 트레이스 해석, 양보(yielding) 패턴, 타사 및 렌더링 원인, 단일 세션 관찰자, 자사 기여도에 대한 INP 참조를 읽으세요.


CLS: Cumulative Layout Shift (누적 레이아웃 시프트)

CLS는 페이지 방문 전반에 걸친 예상치 못한 레이아웃 시프트를 측정합니다. 필드 속성 또는 트레이스를 사용하여 시프트된 노드와 트리거를 식별하세요. 보이는 피해자가 시프트를 유발했다고 가정하지 마세요.

필드 CLS가 좋지 않거나 트레이스에서 시프트를 보고하는 경우, 예약 공간 패턴, 동적 콘텐츠, 글꼴 및 애니메이션 수정, 디버깅 관찰자, 확인 체크리스트에 대한 CLS 참조를 읽으세요.


측정 소스

소스용도
브라우저 성능 트레이스 (Chrome DevTools MCP: performance_start_trace)하나의 로드 또는 상호작용을 관찰하고 집중된 인사이트를 진단합니다. 사용 가능한 경우 포함된 CrUX 컨텍스트 사용
CrUX 또는 Search Consolep75에서 집계된 실제 사용자 결과를 우선시합니다
Lighthouse CLI 또는 PageSpeed InsightsDevTools 도구를 사용할 수 없을 때 통제된 실험실 대체
자사 RUM현재 프로덕션 경험을 경로, 기기, 릴리스 및 속성별로 세분화
원시 PerformanceObserver디버깅 중 하나의 페이지 세션 검사

성능을 Chrome DevTools MCP의 lighthouse_audit를 통해 라우팅하지 마세요. 해당 기능은 의도적으로 성능 이외의 Lighthouse 범주를 다룹니다. 단일 실험실 값을 필드 p75와 동등한 샘플인 것처럼 직접 비교하지 마세요.

프로덕션 수집을 추가하거나 검토할 때는 자사 RUM 참조를 읽으세요. web-vitals 라이브러리를 선호하세요. 원시 브라우저 API는 자체적으로 모든 Core Web Vital의 수명 주기 및 보고 규칙을 구현하지 않기 때문입니다.


프레임워크 빠른 수정

Next.js

// LCP: priority와 함께 next/image 사용
import Image from 'next/image';
<Image src="/hero.jpg" priority fill alt="Hero" />

// INP: 동적 임포트 사용
const HeavyComponent = dynamic(() => import('./Heavy'), { ssr: false });

// CLS: Image 컴포넌트가 자동으로 치수 처리

React

// LCP: head에서 preload
<link rel="preload" href="/hero.jpg" as="image" fetchpriority="high" />

// INP: 메모이제이션 및 useTransition 사용
const [isPending, startTransition] = useTransition();
startTransition(() => setExpensiveState(newValue));

// CLS: img 태그에 항상 치수 지정

Vue/Nuxt

<!-- LCP: preload와 함께 nuxt/image 사용 -->
<NuxtImg src="/hero.jpg" preload loading="eager" />

<!-- INP: 비동기 컴포넌트 사용 -->
<component :is="() => import('./Heavy.vue')" />

<!-- CLS: aspect-ratio CSS 사용 -->
<img :style="{ aspectRatio: '16/9' }" />

참조

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

관련 스킬