모던 리액트 Deep Dive 스터디

12장 - 모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표

려낭 2024. 12. 19. 02:16

12.1 웹사이트와 성능

 

리액트가 아무리 좋은 프레임워크라고 해도,

그 중요성을 제아무리 설파하더라도 웹사이트의 성능이 뒤떨어지면 개발자를 제외한 실제 서비스 이용자들의 호응을 얻기 어렵다.

 

모든 서비스가 그렇듯 웹 서비스도 마찬가지로 사용자가 느끼는 성능이 제일 중요하다.

 

구글은 요즘의 웹사이트의 성능에 대해 다음과 같은 내용의 글을 남기기도 했다.

전 세계 사용자의 대부분이 모바일을 3G가 아닌 4G로 사용하고 있음에도 불구하고, 대부분의 모바일 사이트는 여전히 느리고 너무 많은 요소 때문에 비대해졌다.

 

 

웹사이트 개발자라면 웹사이트의 성능에도 주의를 기울여야 한다.

웹사이트 성능 또한 개발자의 책임이며, 웹사이트의 성능은 조직이 이루고자 하는 목표와 직결된다고 봐도 무방하다.

 

 

 

12.2 핵심 웹 지표란?

 

핵심 웹 지표 (외국에서는 Core Web Vital로 알려져 있다) 란 구글에서 만든 지표로,

웹사이트에서 뛰어난 사용자 경험을 제공하는 데 필수적인 지표를 일컫는 용어다.

 

사이트에서 핵심적인 웹 지표를 몇 가지로 요약하고, 이를 측정할 수 있는 방법,

그리고 '좋은 웹사이트'로 분류할 수 있는 기준을 명확하게 제시했다.

 

구글에서 핵심 웹 지표로 꼽는 지표

  • 최대 콘텐츠풀 페인트(LCP: Largest Contentful Paint)
  • 최초 입력 지연(FID: First Input Delay)
  • 누적 레이아웃 이동(CLS: Cumulative Layout Shift)

그리고 다음 두 지표는 핵심까지는 아니지만, 특정 문제를 진단하는 데 사용될 수 있다고 언급했다.

  • 최초 바이트까지의 시간(TTFB: Time To First Byte)
  • 최초 컨텐츠풀 시간(FCP: First Contentful Paint)

이러한 지표가 의미하는 바는 무엇이고, 또 이 지표들이 웹사이트의 성능에 어떠한 영향을 미치는지 각각 살펴보자.

 

 

12.3 최대 콘텐츠풀 페인트(LCP)

 

12.3.1 정의

 

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

페이지가 처음으로 로드를 시작한 시점부터 뷰포인트 내부에서 가장 큰 이미지 또는 텍스트를 렌더링하는 데 걸리는 시간

 

뷰포트 : 사용자에게 현재 노출되는 화면

 

사용자에게 노출되는 영역은 기기에 의존하므로 뷰포트 크기는 기기마다 다르다.

이 뷰포트 내부에서 '큰 이미지와 텍스트'는 다음과 같이 정의돼 있다.

 

  • <img>
  • <svg> 내부의 <image>
  • poster 속성을 사용하는 <video>
  • url() 을 통해 불러온 배경 이미지가 있는 요소
  • 텍스트와 같이 인라인 텍스트 요소를 포함하고 있는 블록 레벨 요소
    • 이 블록 레벨 요소에는 <p>,<div> 등이 포함된다.

쉽게 말해 최대 콘텐츠풀 페인트란 사용자의 기기가 노출하는 뷰포트 내부에서 가장 큰 영역으로 차지하는 요소가

렌더링되는 데 얼마나 걸리는지를 측정하는 지표이다.

 

실제 크기가 크다고 하더라도 뷰포트 영역 밖에 넘치는 요소가 있다면 해당 영역의 크기는 고려되지 않는다/

 

아무리 콘텐츠 높이가 길어도, 최대 콘텐츠풀 페인트에 영향을 미치는 부분은 오직 뷰포트 영역 뿐이다.

 

 

12.3.2 의미

 

'웹 페이지가 로딩이 완료되어 사용자에게 노출되기까지 걸리는 시간'

은 무엇을 기준으로 측정하면 될까?

 

가장 먼저 떠오르는 것은 DOMContentLoaded 이벤트가 호출되는 시간일 것이다.

 

DOMContentLoaded

HTML문서를 완전히 불러오고 파싱했을 때 발생하는 이벤트.
페이지의 document를 대상으로 일어나며 단 한 번만 호출된다.

 

DOMContentLoaded 이벤트는 '스타일시트, 이미지, 하위 프레임의 로딩은 기다리지 않는다' 는 제한이 있기 때문에

이미지의 크기가 커서 로딩이 오래 걸린다면 이 이벤트가 발생했다고 해서 사용자는 페이지의 로딩이 끝났다고 생각하지 않을 것이다.

 

즉, 개발자가 측정하기 쉬운 DOMContentLoaded로 측정한다면 개발자가 예상한 페이지 로딩 시간과

사용자가 체감한 페이지 로딩 시간에는 현격한 차이가 있을 것이다.

 

그렇다면 사용자가 페이지가 어느 정도 로딩됐다고 인식하는 시점은 언제일까?

 

사용자에게 있어서 로딩이란 단순히  뷰포트 영역에 보이는 부분을 기준으로 할 것이므로

뷰포트에 메인 콘텐츠가 화면에 완전히 전달되는 속도를 기준으로 한다면 사용자는 페이지가 로딩이 완료됐다고 체감하는 시간과 비슷하게 측정할 수 있을 것이다. 

 

>> 사용자에게 페이지의 정보를 화면에 전달하는 속도를 객관적으로 판단하기 위한 지표로 만들어진 것이 바로

최대 컨텐츠풀 페인트(LCP) 이다.

 

12.3.4 기준 점수

 

 

최대 콘텐츠풀 페인트에서 좋은 점수란 해당 지표가 2.5초 내로 응답이 오는 것이다.

4초 이내로 응답이 온다면 보통, 그 이상이 걸리면 나쁨으로 판단된다.

 

 

12.3.5 개선 방안

 

이 점수를 높일 수 있는 방법을 알아보자.

 

텍스트는 언제나 옳다

 

좋은 점수를 얻는 가장 확실한 방법은 뷰포트 최대 영역, 즉 최대 콘텐츠풀 페인트 예상 영역에 이미지가 아닌 문자열을 넣는 것이다.

이미지보다 텍스트 노출이 훨씬 더 빠르기 대문에 가능한 한 해당 영역은 텍스트로 채우는 것이 좋다.

 

이미지는 어떻게 불러올 것인가?

 

텍스트로 최대 콘텐츠풀 페인트를 최적화 하려는 개발자의 노력에도 불구하고,

사용자에게 좀 더 강렬한 인상을 주기 위해서는 이미지 사용을 추구할 것이다.

이때 개발자가 선택할 수 있는 이미지를 노출하는 방법에는 여러가지가 있다.

 

1)
<img src="lcp.jpg".../>
2)
<svg xmlns="http://www.w3.org/1000/svg">
	<image href="lcp.jpg" />
</svg>
3)
<video poster="lcp.jpg"></video>
4)
<div style="background-image: url(lcp.jpg)">...</div>

 

 

각 방법을 사용했을 때 이미지 로딩 속도 차이

 

1번과 3번의 예제 코드가 더 빠르게 완성되는 것을 볼 수 있다.

 

 

구체적인 타임라인으로 살펴보자

 

  • <img> : 이미지는 브라우저의 프리로드 스캐너에 의해서 먼저 발견되어 빠르게 요청이 일어난다. 
    • 프리로드 스캐너: HTML을 파싱하는 단계를 차단하지 않고 이미지와 같이 빠르게 미리 로딩하면 좋은 리소스를 먼저 찾아 로딩하는 브라우저의 기능
  • <svg> 내부의 <img>: 테스트 결과를 잘 보면 <img>가 미처 로딩되지 않은 시점, <svg>만 로딩된 시점에 이미 최대 콘텐츠풀 페인트가 완료된 것으로 간주한다. 이는 크롬 102 버전 이하의 버그로, 이후 버전에서는 수정된 것으로 보인다. 수정된 버전에서는 <svg> 내부의 <Img>가 로딩이 완료되기 전까지는 최대 콘텐츠풀 페인트가 완료되지 않는다. <svg> 내부의 <img>는 프리로드 스캐너에 의해 발견되지 않아 병렬적으로 다운로드가 일어나지 않는다. > 악영향을 미치기 때문에 이러한 방식은 삼가하는게 좋다
  • <video> 의 poster: poster는 사용자가 video 요소를 재생하거나 탐색하기 전까지 노출되는 요소. 마찬가지로 프리로드 스캐너에 의해 조기에 발견되어 <img>와 같은 성능을 나타낸다. poster가 없는 video는 video를 실제로 로딩해 첫 번째 프레임을 해당 poster로 대체할 예정이다. video 가 최대 콘텐츠풀 페인트에 영향을 받을 것 같다면 poster를 반드시 넣어주는 것이 좋다.
  • background-image: url() : background-image 를 비롯해서 CSS에 있는 리소스는 항상 느리다. 브라우저가 해당 리소스를 필요로 하는 DOM을 그릴 준비가 될 때까지 리소스 요청을 뒤로 미루기 때문이다. >> 최대 콘텐츠풀 페인트에 좋은 영향을 미치지 않기 때문에 중요한 리소스에는 사용하지 않는 것이 좋다.

 

그 밖에 조심해야 할 사항

  • 이미지 무손실 압축: 웹으로 서비스할 이미지는 가능한 한 무손실 형식으로 압축해 최소한의 용량으로 서비스하는 것이 좋다.
  • loading=lazy 주의: loading=lazy 는 리소스를 중요하지 않음으로 표시하고 필요할 때만 로드하는 전략으로, <img>,<frame> 등에 적용할 수 있지만 문제는 최대 콘텐츠풀 콘텐츠의 이미지는 중요하지 않은 리소스로 분류해서는 안된다는 것이다. 이는 로딩 속도만 늦출 뿐 지표 점수에는 도움이 되지 않는다.
  • fadein과 같은 각종 애니메이션: 이미지가 그냥 뜨는 것보다 fadeIn ease 10s와 같이 처리한다면 최대 콘텐츠풀 페인트도 그만큼 늦어진다.
  • 최대 콘텐츠풀 리소스는 직접 호스팅: 최대 콘텐츠풀 리소스는 같은 도메인에서 직접 호스팅하는 것이 좋다.

 

 

12.4 최초 입력 지연(FID)

 

12.4.1 정의

 

최초 입력 지연(FID: First Input Delay)
웹사이트의 반응성을 측정하는 지표

 

쉽게 말해 사용자가 얼마나 빠르게  웹페이지와의 상호작용에 대한 응답을 받을 수 있는지 측정하는 지표다.

모든 입력에 대해 측정하는 것이 아니라, 최초의 입력 하나에 대해서만 그 응답 지연이 얼마나 걸리는지 판단한다.

 

12.4.2 의미

 

최초 입력 지연을 이해하기 위해 알아야 하는 것은 바로 '사용자의 입력' 이다.

이 최초 입력 지연에 대한 정의를 살펴보면 이처럼 다양한 이벤트 중에서도 반응성에 해당하는 클릭, 터치, 타이핑 등 사용자의 개별 입력 작업에 초점을 맞추고 측정한다.

 

구글은 사용자 경험을 크게 4가지로 분류해 정의한다 (RAIL)

  • Response: 사용자의 입력에 대한 반응 속도, 50ms 미만으로 이벤트를 처리할 것
  • Animation: 애니메이션의 각 프레임을 10ms 이하로 생성할 것
  • ldle: 유휴 시간을 극대화해 페이지가 50ms 이내에 사용자 입력에 응답하도록 할 것
  • Load: 5초 이내에 콘텐츠를 전달하고 인터렉션을 준비할 것

 

이 가운데 최초 입력 지연은 R에 해당하는 응답에 초점을 맞추고 있다.

 

정리하자면, 최초 입력 지연이란 화면에 최초에 그려지고 난 뒤, 사용자가 웹페이지에서 클릭 등

상호작용을 수행했을 때 메인 스레드가 이 이벤트에 대한 반응을 할 수 있을 때까지 걸리는 시간을 의미한다.

이 시간은 메인 스레드가 처리해야 하는 다른 작업이 많을수록 느려진다.

 

 

12.4.4 기준 점수

 

최초 입력 지연의 좋은 점수를 얻기 위해서는 100ms 이내로 응답이 와야 하며, 300ms 이내인 경우 보통, 그 이후의 경우에는 나쁨으로 처리된다.

 

 

12.4.5 개선 방안

 

최초 입력 지연을 개선하는 방법을 구체적으로 살펴보자

 

실행에 오래 걸리는 긴 작업을 분리

 

긴 작업이란 말 그대로 실행을 완료하는 데 오래 걸리는 작업을 의미한다.

 

메인 스레드가 처리에 오래 걸리는 작업을 있으면 긴 작업이 있다는 경고가 뜬다.

 

메인 스레드를 오래 점유해야 하는 긴 작업은 최초 입력 지연뿐만 아니라 웹페이지 전반에 악영향을 미친다.

 

실행에 오래 걸리는 작업이 있다면 몇 가지 대안을 연구해야 한다.

  • 꼭 웹페이지에서 해야 하는 작업인가( 크롬의 개발자 도구 활용하기)
  • 긴 작업을 여러개로 분리하기

자바스크립트 코드 최소화

 

사용되지 않는 필요 없는 코드는 크롬 개발자 도구를 통해 확인할 수 있다.

이러한 코드들은 당장에 급하지 않은 코드로 간주해 지연 로딩 기법, 사용자가 필요로 하는 순간에 불러오거나 우선순위를 낮춰서 불러오는 것이 좋다.

 

폴리필(polyfill)
브라우저에서 지원하지 않는 기능을 사용하기 위해 웹페이지에서 직접 구현하고 집어넣는 코드를 의미한다.

 

폴리필을 집어넣기 전에는 반드시 두 가지를 먼저 확인해 봐야 한다.

  • 폴리필이 필요한 환경인가?
  • 꼭 필요한 폴리필인가?
    • 여러 군데에서 자주 사용되는 코드인지 반드시 확인

 

타사 자바스크립트 코드 실행의 지연

 

타사 스크립트는 대부분 웹페이지 로드에 중요한 자원이 아니므로 <script> 의 async 와 defer를 이용햐 지연 불러오기를 하는 것이 좋다.

  • defer: script 에 defer 속성이 있다면 먼저 해당 스크립트를 다른 리소스와 함께 병렬로 다운로드 한다. 다운로드가 완료돼도 이 스크립트의 실행은 페이지가 완전히 로딩된 이후 맨 마지막에 실행된다.
  • async: script에 async속성이 있다면 마찬가지로 해당 스크립트를 다른 리소스와 함께 병렬로 다운로드한다. async리소스의 다운로드가 완료되어 버리면 다른 리소스의 다운로드가 완료되는 것을 기다리지 않고 바로 실행한다. async 리소스의 실행 순서는 다운로드가 완료된 순서대로 실행한다.
  • 둘 다 없는 경우: script를 만나는 순간 다운로드가 우선되며, 다운로드가 완료되면 코드 실행이 우선된다. 다른 작업은 다운로드와 실행이 끝날 때 까지 미뤄진다.

스크립트는 async,defer 로 갈수록 실행은 뒤로 미뤄지지만 성능은 좋아진다.

따라서 타사 자바스크립트는 가능하면 async를, 더 가능하다면 defer로 지연하는 것이 좋다.

 

 

 

12.5 누적 레이아웃 이동(CLS)

 

12.5.1 정의

 

누적 레이아웃 이동(CLS: Cumulative Layout Shift)
페이지의 생명주기 동안 발생하는 모든 예기치 않은 이동에 대한 지표를 계산하는 것

 

이 지표가 낮을수록, 즉 사용자가 겪는 예상치 못한 레이아웃 이동이 적을수록 더 좋은 웹사이트다.

 

12.5.2 의미

 

useEffect는 렌더링이 한 번 끝난 이후에 콜백 함수를 실행하는 훅이다.

useEffect가 많을수록 클라이언트에서 처리해야 하는 작업이 많아진다.

useEffect 내부에 UI의 레이아웃을 변경하는 작업이 있다면 어떨까?

 

최초 렌더링 이후에 실행되는 useEffect가 많을수록, 그리고 이 useEffect가 렌더링에 영향을 미칠수록 이 누적 레이아웃 이동에 좋지 못한 점수를 받을 가능성이 커진다.

 

누적 레이아웃 이동은 사용자의 가시적인 콘텐츠에 영향을 미쳐야 하기 때문에 뷰포트 내부의 요소에 대해서만 측정하며,

뷰포트 밖의 요소에 대해서는 측정하지 않는다.

 

최초 렌더링이 시작된 위치에서 레이아웃의 이동이 발생한다면 누적 레이아웃 이동 점수로 기록한다.

 

요소가 추가됐다 하더라도 다른 요소의 시작 위치에 영향을 미치지 않았다면 레이아웃 이동으로 간주되지 않는다.

 

사용자 액션으로 인해 발생한 레이아웃 이동은 점수에 포함되지 않는다.

사용자가 아무런 동작을 하지 않았음에도 불구하고 레이아웃 이동이 발생하는 경우에는 점수에 포함된다.

 

점수를 계산할 때 포함되는 내용

  • 영향분율: 레이아웃 이동이 발생한 요소의 전체 높이와 뷰포트 높이의 비율
  • 거리분율: 레이아웃 이동이 발생한 요소가 뷰포트 대비 얼마나 이동했는지 

이 두 가지 점수를 곱해서 최종 점수를 계산한다.

 

12.5.4 기준 점수

 

0.1 이하인 경우 좋음, 0.25 이하인 경우 보통이며 그 외에는 개선이 필요한 나쁜 점수로 보고된다.

 

 

12.5.5 개선 방안

 

  • 삽입이 예상되는 요소를 위한 추가적인 공간 확보
  • 폰트 로딩 최적화
  • 적절한 이미지 크기 설정

 

12.5.6 핵심 웹 지표는 아니지만 성능 확인에 중요한 지표들

 

  • 최초 바이트까지의 시간(Time To First Byte, TTFB)
    • 브라우저가 웹페이지의 첫 번째 바이트를 수신하는 데 걸리는 시간
  • 최초 콘텐츠풀 페인트 (First Contentful Paint, FCP)
    • 페이지가 로드되기 시작한 시점부터 페이지 콘텐츠의 일부가 화면에 렌더링될 때까지의 시간 측정

 

'모던 리액트 Deep Dive 스터디' 카테고리의 다른 글

15장  (2) 2024.12.28
12장 발표자료  (1) 2024.12.22
11장 - Next.js 13과 리액트 18  (1) 2024.12.13
10장 - 리액트 17과 18의 변경 사항 살펴보기  (1) 2024.12.12
9장 발표자료  (2) 2024.12.08