Web Vital에 대하여

#web

#web vitals

Written by Paul

Web Vital이란?

  • 웹 바이탈(Web vitals)은 구글이 제공하는 사용자 경험 지표이다
  • 웹사이트 성능 및 사용자 경험 측정 및 개선하기 위해 설계된 중요한 기준
  • 페이지 로딩 속도, 인터랙션, 시각적 안정성과 관련된 요소를 강조
  • 주요 목표는 사용자에게 보다 빠르고 직관적인 웹 경험을 제공하는 것

주요 web vitals 요소

웹 바이탈은 코어 웹 바이탈(Core web vitals)이라는 핵심 지표 세트로 구성되어 있다.
  1. LCP (Largest Contentful Paint)
    1. 페이지에서 가장 큰 컨텐츠(주로 이미지나 텍스트 블록)가 로드되고 표시되는데 걸리는 시간
    2. 목표: 2.5초 이내 (모바일과 데스크톱에서 동일)
    3. 중요성: 페이지가 얼마나 빠르게 주요 내용을 사용자에게 제공하는지 나타낸다
  1. FID (First Input Delay)
    1. 사용자가 첫 번째로 상호작용(ex. 클릭, 스크롤, 키보드 입력 등)한 후 브라우저가 실제로 반응하기까지의 시간
    2. 목표: 100ms 이하
    3. 중요성: 사용자가 웹사이트와 얼마나 빠르게 상호작용 할 수 있는지를 측정
  1. CLS (Cumulative Layout Shift)
    1. 페이지의 레이아웃이 예상이 못하게 변경되는 정도를 측정하는 지표
    2. 목표: 0.1 이하
    3. 중요성: 불안정한 페이지 레이아웃이 사용자 경험을 방해하지 않도록 보장. ex: 텍스트가 갑자기 움직이거나 버튼 위치가 바뀌는 문제

웹 바이탈 측정 도구

  1. Google PageSpeed Insights
      • 페이지 성능 및 코어 웹 바이탈 점수를 제공합니다.
  1. Lighthouse
      • 개발자 도구에서 직접 웹사이트 성능을 분석할 수 있는 도구입니다.
  1. Search Console (웹마스터 도구)
      • 코어 웹 바이탈 리포트를 통해 사이트 전체의 성능 상태를 확인할 수 있습니다.
  1. Chrome DevTools
      • 브라우저 내에서 실시간으로 성능을 분석하고 디버깅할 수 있습니다.
  1. Web Vitals Chrome Extension
      • 간단한 브라우저 확장 프로그램으로 실시간 측정이 가능합니다.

웹 바이탈 최적화 팁

  • LCP 개선:
    • 서버 응답 시간을 줄입니다.
    • 렌더링 차단 리소스를 최소화합니다.
    • 중요한 이미지와 텍스트는 초기에 로드되도록 설정합니다.
  • FID 개선:
    • JavaScript 실행 시간을 줄입니다.
    • 웹 워커(Web Worker)를 활용하여 백그라운드 작업을 최적화합니다.
    • 메인 스레드의 차단 시간을 단축시킵니다.
  • CLS 개선:
    • 이미지 크기를 명시적으로 지정합니다.
    • 동적 컨텐츠를 미리 예약된 공간에 배치합니다.
    • 광고나 삽입형 비디오의 크기를 미리 정의합니다.

javascript static file과 web vitals

Static JS 파일을 불러오는 방식은 Web Vitals 지표, 특히 **LCP (Largest Contentful Paint)**와 **FID (First Input Delay)**에 큰 영향을 미칩니다. JS 파일의 로드 및 실행이 느리면 주요 콘텐츠 렌더링이 지연되거나, 사용자 상호작용 응답이 느려질 수 있습니다.
아래와 같은 최적화 기법들이 있습니다.

1. JavaScript 파일의 로딩 최적화

(1) 비동기 로드 (async 또는 defer)

  • async: 파일 로드를 비동기적으로 수행하며, 로드가 끝나면 바로 실행합니다.
    • 장점: 병렬 로드 가능.
    • 단점: 로드 완료 순서에 따라 실행 순서가 달라질 수 있음.
  • defer: 파일 로드를 비동기적으로 수행하며, DOM 파싱이 끝난 후 실행합니다.
    • 권장: HTML 파싱과 병렬로 진행되며 실행 순서가 보장됩니다.
<script src="example.js" async></script> <!-- async --> <script src="example.js" defer></script> <!-- defer -->
  • LCP/FID 개선 이유: JS 로드로 인해 DOM 파싱이 지연되는 문제를 방지하여 주요 콘텐츠 렌더링이 빨라집니다.

(2) 필요한 JS만 로드 (코드 스플리팅)

  • 불필요한 JS 파일을 로드하지 않도록 **코드 스플리팅(Code Splitting)**을 사용하세요.
  • 방법: Webpack, Rollup과 같은 번들러에서 사용자가 현재 페이지에서 필요한 스크립트만 제공.
// 예: 동적 import를 활용한 코드 스플리팅 if (someCondition) { import('./feature.js').then((module) => { module.initFeature(); }); }
  • LCP/FID 개선 이유: 불필요한 리소스를 줄이면 로드 및 실행 시간이 단축됩니다.

(3) 지연 로딩 (Lazy Loading)

  • 초기 로드에 반드시 필요한 JS만 로드하고, 나머지는 사용자가 특정 동작을 했을 때 로드합니다.
  • 라이브러리나 대규모 스크립트는 초기 페이지 로딩에 포함시키지 않고 필요 시 동적 로드합니다.
document.addEventListener('DOMContentLoaded', () => { const script = document.createElement('script'); script.src = 'large-library.js'; document.body.appendChild(script); });
  • LCP/FID 개선 이유: 초기 렌더링 시간 단축 및 메인 스레드 차단 시간 감소.

2. JavaScript 파일 크기 줄이기

(1) Minification

  • JS 파일의 불필요한 공백, 주석, 줄바꿈을 제거하여 파일 크기를 줄입니다.
  • 도구: UglifyJS, Terser, Webpack의 minimize 플러그인 등.

(2) 압축 (Gzip/Brotli 사용)

  • 서버에서 JS 파일을 전송하기 전에 Gzip 또는 Brotli로 압축하세요.
  • LCP/FID 개선 이유: 파일 크기를 줄여 네트워크 전송 속도를 향상.

(3) Tree Shaking

  • 사용되지 않는 코드(Dead Code)를 제거하여 번들 크기를 줄입니다.
  • 도구: Webpack, Rollup.

3. 캐싱 및 CDN 활용

(1) 브라우저 캐싱

  • 정적 JS 파일에 긴 캐시 만료 시간을 설정하세요.
  • 예: Cache-Control: max-age=31536000, immutable.

(2) CDN(Content Delivery Network) 활용

  • JS 파일을 CDN으로 제공하여 전 세계적으로 짧은 지연 시간으로 로드할 수 있도록 합니다.
  • LCP/FID 개선 이유: 네트워크 지연 시간 단축.

4. JavaScript 실행 최적화

(1) Main Thread Blocking 시간 줄이기

  • JS 실행이 메인 스레드를 차단하지 않도록 코드를 최적화합니다.
  • 큰 작업은 Web Workers를 활용하여 백그라운드에서 실행합니다.
const worker = new Worker('worker.js'); worker.postMessage('data'); worker.onmessage = function(event) { console.log(event.data); };

(2) Critical Path JS를 분리

  • 페이지 초기 렌더링에 중요한 JS(예: 레이아웃 조정)에 우선순위를 둡니다.

(3) Third-Party Scripts 최적화

  • 서드파티 스크립트(예: 광고, 분석 도구)는 비동기 로드로 처리하거나, 필요하지 않으면 제거합니다.

NextJS의 dynamic import와 최적화

Next.js의 dynamic import는 브라우저의 defer 동작과 유사합니다. 하지만 특정 동작에 따라 다소 차이가 있을 수 있습니다. 이를 이해하려면 dynamic import의 작동 방식과 deferasync 스크립트의 차이점을 살펴봐야 합니다.

defer vs async 차이점

  1. defer
      • 스크립트는 HTML 파싱과 동시에 로드되지만, HTML 파싱이 끝난 뒤 실행됩니다.
      • 실행 순서는 HTML에 선언된 순서를 따릅니다.
  1. async
      • 스크립트는 HTML 파싱과 동시에 로드되며, 로드가 끝나는 즉시 실행됩니다.
      • 실행 순서는 스크립트 로드 완료 순서에 따릅니다 (HTML 선언 순서와 무관).

Next.js dynamic Import

Next.js의 dynamic import는 서버 사이드 렌더링(SSR)과 클라이언트 사이드 렌더링(CSR)에 따라 작동 방식이 약간 다릅니다:
  1. 기본 동작
      • Next.js는 dynamic으로 로드한 모듈을 클라이언트 사이드에서 비동기로 로드합니다.
      • 이 과정에서 HTML 파싱과 병렬로 JS 파일을 로드하고, HTML 파싱이 완료된 뒤에 실행됩니다.
      따라서 dynamic import는 브라우저의 defer 속성과 유사하게 동작합니다.
  1. 특정 조건에서 로드 지연
      • dynamic import에 ssr: false 옵션을 추가하면, 해당 컴포넌트는 클라이언트에서만 렌더링됩니다.
      • 이런 경우, 컴포넌트는 페이지 초기 렌더링에 포함되지 않고, 로드가 지연되며 필요 시 비동기적으로 추가됩니다.
import dynamic from 'next/dynamic'; const DynamicComponent = dynamic(() => import('./DynamicComponent'), { ssr: false, }); export default function Home() { return <DynamicComponent />; }

dynamic Import와 Web Vitals

  1. LCP (Largest Contentful Paint)
      • dynamic import를 사용하면 초기 로드 시 중요하지 않은 JS 파일이 지연되므로, LCP가 개선될 수 있습니다.
      • 그러나 중요한 요소가 dynamic import된 컴포넌트에 포함되어 있다면, 초기 렌더링이 지연될 수 있어 LCP가 나빠질 수 있습니다.→ 중요한 컴포넌트는 정적으로 로드하는 것이 좋습니다.
  1. FID (First Input Delay)
      • dynamic import는 JavaScript 로드 및 실행을 비동기로 처리하므로, 메인 스레드 차단 시간이 줄어들어 FID를 개선할 수 있습니다.
  1. CLS (Cumulative Layout Shift)
      • 동적 로딩된 컴포넌트가 로드된 후 레이아웃 이동을 발생시킬 수 있습니다.→ 미리 공간 예약(CSS를 통한 고정 높이/너비 설정)이 필요합니다.

결론: dynamic import는 defer와 유사한가?

네, Next.js의 dynamic import는 브라우저에서 defer 동작과 가장 유사합니다. HTML 파싱과 동시에 스크립트를 비동기로 로드하고, HTML 파싱이 완료된 뒤에 실행되기 때문입니다. 다만, 조건에 따라 지연 로드(필요할 때만 로드) 방식으로도 동작하므로 상황에 맞는 최적화를 적용하는 것이 중요합니다.
← Go home