React Deep Dive 12강

RookieAND·2024년 4월 20일
0

React Deep Dive

목록 보기
7/8
post-thumbnail

✒️ 모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표

✏️ 웹사이트와 성능

사용자가 웹사이트에 접속할 때 공통적으로 기대하는 사항은?

  1. 웹사이트 방문 목적을 쉽게 달성
  2. 목적을 달성하기 위해 걸리는 시간이 짧아야 함
  3. 개인정보 누출 관련한 보안 이슈가 없어야 함

웹 사이트 성능은 아래와 같은 영향을 미친다고 한다.

  1. 1초 내로 로딩되는 사이트는 5초 내로 로딩되는 사이트보다 목적 달성률이 높다.
  2. 0 ~ 5초 범위 내에서 1초 로딩이 지연될 수록 전환률은 4.42% 떨어진다
  3. 0 ~ 2초 내외의 페이지 로드 시간인 곳에서 목적 달성률이 높다.

개발 환경에서 측정한 성능 지표와 실제 운영 환경의 지표는 차이가 크다.

  1. 개발자가 사용하는 디바이스는 사용자의 기기보다 월등히 좋다
  2. 모바일 디바이스의 경우 데스크탑보다 성능이 좋지 못하다는 사실을 망각한다.
  3. 네트워크 환경 또한 개발 환경이 압도적으로 좋기에 실제 환경을 간과한다.

이러한 웹사이트의 성능을 측정할 수 있는 방식으로 구글은 Core Web Vital (핵심 웹 지표) 를 제시하고 있다.

✏️ 핵심 웹 지표란?

  1. 정의
  • 웹사이트에서 좋은 사용자 경험을 제공하기 위해 필요한 지표를 Core Web Vital 이라 한다.
  1. 핵심 지표

    1. LCP (Largest Contentful Paint) : 사용자에게 표기되는 가장 큰 이미지 혹은 텍스트 블럭의 렌더링 시간
    2. FID (First Input Delay) : 사용자가 페이지와 최초로 상호작용하기까지 걸린 시간
    3. CLS (Cumulative Layout Shift) : 페이지 내에서 발생하는 예상치 못한 레이아웃 변경에 대한 지표
  2. 부가 지표

  • 아래의 지표는 핵심 요소는 아니지만 특정 문제를 진단할 때 쓰인다.

    1. TTFB (Time To First Byte) : 화면에 첫 번째 Bit 를 찍기까지 걸리는 시간
    2. FCP (First Contentful Paint) : 화면에 최초로 특정 이미지 혹은 텍스트 블럭이 보여지기까지 걸리는 시간

구글에서 정의한 사용자 경험 (User Experience) RAIL 에 대해 알아보자

구글은 사용자 경험을 4가지 범주로 구분지었는데 이를 줄여 RAIL 이라 한다.

  1. Response : 사용자의 입력에 대한 반응 속도를 50ms 미만으로 처리할 것
  2. Animation : 애니메이션 간의 프레임을 10ms 로 생성할 것
  3. Idle : 페이지가 50ms 이내에 사용자 입력에 응답하도록 할 것
  4. Load : 5초 이내에 컨텐츠를 전달하고 상호 작용을 준비할 것

✏️ LCP (Largest Contentful Paint)

  1. 정의
  • LCP (Largest Contentful Paint) 는 페이지가 처음으로 로드를 시작한 시점부터 Viewport 내부에서 가장 큰 이미지 혹은 텍스트 블럭이 렌더링되기까지 걸리는 시간이다.
  • 즉, LCP 란 사용자의 기기가 노출하는 Viewport 내부에서 가장 큰 영역을 차지하는 요소가 렌더링되기까지 걸리는 시간을 의미한다.
  1. Viewport란?
  • Viewport 는 사용자에게 현재 노출하는 화면을 의미한다.
  • 사용자가 현재 쓰는 기기에 따라서 사이즈가 다르며, 모바일 기기가 PC 보다 작은 Viewport 를 가진다.
  1. 가장 큰 이미지 혹은 텍스트 블럭의 종류
  • <img> 태그
  • <svg> 태그 내의 <image> 요소
  • poster 속성을 사용하는 <video> (재생 이전에 보여줄 이미지)
  • url() 함수를 통해 불러온 배경 이미지가 있는 요소
  • 인라인 텍스트 요소를 포함한 Block Element (<p>, <div>)
  1. 의미
  • 사용자의 페이지 정보를 화면에 전달하는 속도를 객관적으로 판단하기 위해 LCP 지표가 탄생했다.
  • 사용자가 "페이지가 어느 정도 로딩되었다" 라고 인식하는 시점은 Viewport 내부에 컨텐츠가 로딩되는 시점이다.
  • Viewport 내부가 아닌 영역이 아직 로딩되지 않더라도 우선 사용자가 보는 영역이 로딩된다면 사용자는 페이지 로딩이 완료되었다고 느낄 확률이 매우 높기 때문이다.
  1. 기준 지표

alt text

  • 보통 Lighthouse 를 통해 LCP 를 측정할 때 2.5초 내외의 LCP 를 보이면 훌륭하고, 4초 이상이 걸리면 나쁨으로 판단한다.
  1. 개선 방안
  • LCP 예상 영역에 텍스트를 넣는다면 이미지를 로딩하는 시간보다 압도적으로 빠르기에 해당 영역을 Text 로 채우는 것이 좋다.
  • <img> 태그의 경우 브라우저의 Pre-load Scanner 로 인해 자원을 빠르게 로드하기 때문에 HTML 파싱이 완료되기 전에 이미지를 병렬적으로 받아온다.
  • <svg> 내부의 <image> 태그의 경우 모든 리소스를 받아온 후에 이미지를 불러오기 때문에 상대적으로 불리하다.
  • <video> 의 poster 속성의 경우 존재하지 않는다면 비디오의 첫번째 frame 으로 대체하기에 가급적이면 해당 속성을 추가하는 것이 좋다.
  • background-image 속성의 경우 CSS 내부에 존재하기 때문에 해당 리소스를 필요로 하는 DOM 을 그리기 전까지는 로딩되지 않는다. 따라서 LCP 에 악영향을 미친다.
  1. 그 외 추가 개선 사항
  • loading=lazy 속성의 경우 리소스가 필요할 때만 로딩하는 전략이지만, LCP 이미지는 빠르게 불러오는 것이 유리하기에 지표에 도움이 되지 않는다.
  • fadein 과 같은 CSS 애니메이션을 추가할 경우 그만큼 로딩 속도가 느리므로 LCP 지표에 악영향을 준다.
  • LCP 에 해당되는 영역은 클라이언트 단에서 조건부 렌더링으로 처리하기 보단 가급적 서버 단에서 사전에 Preload 하는 것이 좋다.
  • LCP 의 경우 동일한 Origin 이 그렇지 않은 경우보다 훨씬 유리하다. 새로운 Origin 에 대한 Connection 을 다시 맺어 리소스를 로드하기 때문이다.

✏️ FID (First Input Delay)

  1. 정의
  • 사용자가 페이지와 처음 상호작용할 때부터 해당 상호 작용에 대한 응답으로 브라우저가 이벤트 핸들러 처리를 시작하기까지 걸리는 시간 을 의미한다.
  • 즉, 페이지는 로드되었지만 아직 이벤트 핸들러가 부착되지 않아 상호작용이 불가능한 시간이 얼마나 큰지를 확인하는 지표다.
  • TTV (Time to View) 와 TTI (Time to Interact) 의 차이를 FID 라고 생각하면 편하다.
  1. 왜 Interaction 이 지연되는가?
  • 사용자로부터 특정 입력이 들어오면 브라우저의 메인 스레드에서 이를 처리해야 하는데, 스레드에 할당된 작업이 많이 쌓이면 그만큼 처리가 늦어진다.
  • 따라서 이벤트가 발생하기 전에 최대한 많은 태스크를 처리하여 즉각적인 상호작용이 가능하도록 해야 한다.
  • 따라서 FID 가 높을수록 사용자가 웹페이지에서 상호작용을 수행했을 때 이벤트에 대한 반응 속도가 느림을 의미한다.
  1. 기준 지표

alt text

FID 의 경우에는 100ms 이하의 응답 속도를 보이면 좋음, 300ms 이상의 응답 속도를 보이면 나쁘다고 판단한다.

  1. 개선 방안
  • 실행이 오래 걸리는 긴 작업은 여러 작은 태스크로 분리하여 처리가 가능한지를 고려해보자.
  • 웹 페이지 최초 로딩에 필요하지 않은 작업은 대체로 나중에 가져오도록 코드를 작성해보자.
  • Chrome 개발자 도구 내 Coverage 옵션을 사용해서 웹페이지에서 당장 사용하지 않는 코드를 확인한 후 이를 Lazy 하게 가져오는 전략을 취해보자.
  • Polyfill 을 지원하는 경우 해당 Polyfill 이 필요한지, 그리고 Polyfill 이 필요한 환경인지를 고려하여 JS 코드의 양을 줄이자.
  1. 추가 개선 방안
  • Third-Party Module 에서 삽입한 JS Script 코드를 불러오는 경우 async 혹은 defer 옵션을 사용하여 병렬로 리소스를 불러오도록 한다.
  • 만약 실제 사용자의 Viewport 위치에 따라 불러오는 컴포넌트라면 Intersection Observer 를 사용하여 Viewport 와 요소가 교차하는 시점에 리소스를 불러오자.

✏️ CLS (Cumulative Layouy Shift)

  1. 정의
  • 페이지의 생명주기 동안 발생하는 예기치 못한 이동에 대한 지표를 CLS 라고 한다.
  • 사용자가 보려고 했던 컨텐츠의 위치가 애플리케이션 내 동작으로 인해 예상치 못하게 밀리는 경우가 빈번한지를 주로 체크한다.
  • 사용자의 가시적인 컨텐츠에 영향을 주기에 Viewport 내부의 요소에 대해서만 측정한다.
  1. CLS 지표에 영향을 주는 케이스는 어떤 경우인가?
  • 예를 들어 첫 페이지가 로드된 이후에 비동기로 배너에 대한 정보를 받아와 이를 노출시키면 레이아웃 변경이 일어난다.
  • 사용자는 화면과 어떠한 상호작용도 하지 않았음에도 기존에 보고 있던 컨텐츠의 위치가 변경되는 불편함을 겪게 된다.
  • 혹은 특정 요소와 상호작용을 시도하려는 찰나에 해당 요소가 위치했던 자리에 배너가 새롭게 로드된다면 이 또한 UX 저하로 이어진다.
  • 따라서 사용자의 액션에 의해 Layout 이 변경되거나, 요소가 추가되더라도 다른 요소의 시작 위치에 영향을 미치지 않는 경우를 제외하고는 전부 CLS 의 지표에 영향을 준다.
  1. 해결 방법
  • 사용자에게 어떤 컨텐츠를 보여줄지 결정하지 않은 상황에서는 서버 단에서 사전에 컨텐츠 노출이 예상되는 부분에 대한 공간을 확보 하는 것이 좋다.
  • 컨텐츠가 뒤늦게 로드되어 새롭게 요소가 추가된다면 예상치 못하게 Layout 이 변경되지만, 기존 요소를 대체하는 방식은 움직임에 영향을 주지 않기 때문이다.
  • 애플리케이션에서 쓰이는 폰트를 Preload 하여 폰트 변경으로 인한 레이아웃 변경을 방지할 수 있다.
  • 이미지의 사이즈를 적절히 설정하여 Viewport 사이즈에 따라 동적으로 변경하는 방식을 탈피하여 aspect-ratio 와 고정된 width, height 속성을 명시해야 한다.

왜 폰트를 뒤늦게 불러오는 것이 레이아웃을 움직이게 하는 원인이 되는가?

폰트는 고유한 높이와 너비를 가지고 있다. 그리고 브라우저는 지정된 폰트가 다운로드 되기 전에 노출된 텍스트에 대해서는 기본 폰트를 적용한다.

이로 인해 발생할 수 있는 사용성 경험 저하 문제는 아래와 같다. 둘 다 이후에 폰트가 적용됨으로서 두 프레임 간의 Layout 이동을 유발한다.

  1. FOUT (Flash Of Unstyled Text) : HTML 내에서 지정된 폰트가 아닌 기본 폰트가 적용되었다가 뒤늦게 폰트가 적용되면서 순간 텍스트가 "깜빡" 이는 현상
  2. FOIT (Flash of Invisible Text) : HTML 내에서 적용 가능한 폰트가 없어 텍스트가 없는 채로 있다가 뒤늦게 폰트가 적용되며 페이지에 렌더링 되는 현상

이를 해결하는 방법은 아래와 같다.

  1. <link> 태그의 preload 속성 사용
<link
  rel="preload"
  as="font"
  type="font/woff2"
  crossorigin=""
  href="/font/Pretendard-Black.subset.woff2"
  />
  • rel=preload 속성의 경우 페이지 렌더링에 필요한 중요 요소로 체크되어 브라우저에서 더욱 빠르게 해당 리소스를 불러온다.
  • 추가로 가능하다면 subset 폰트를 사용하여 경량화된 Font 파일을 로드하도록 한다.
  1. font-family 속성에서 폰트를 불러올 때, optional 속성을 적용
  • optional 속성의 경우 100ms 간 텍스트가 보이지 않고 이후 0.1초 이내로 폰트가 다운로드 되거나 Cache 되어 있지 않은 경우에만 fallback 폰트를 사용하도록 한다.
  • 이후 브라우저 단에서 폰트를 다운로드 하지 않는다면 연결을 취소하여 fallback 폰트를 그대로 사용하도록 둔다.

이미지 width 와 height 를 auto 로 두는 것이 왜 Layout 이동을 유발하는가?

img {
    width: 100%;
    height: auto;
}
  • 상단의 CSS 의 경우 width 는 기기의 너비, 즉 Viewport 의 너비대로 설정하고 높이는 그림이 width 를 가진다면 이에 비례해서 설정함을 의미한다.
  • 하지만 이미지가 완전히 다운로드 되기 전까지는 정확한 height 를 알 수 없으므로, 그전까지는 높이를 높게 잡아둔다.
  • 이후 이미지가 완전히 로드 되었을 때 기기의 너비만큼 높이를 계산하여 동적으로 height 를 지정하므로 프레임 간의 Layout 이 변경되는 결과를 낳는다.

이를 해결하는 방법은 아래와 같다.

  1. 고정된 width, height 세팅
  • 상단의 예제와 함께 <img> 태그에 width, height 비율을 명시하면 aspect-ratio 속성으로 인해 이미지의 가로 - 세로 비율을 설정된 값으로 맞춰준다.
  1. 사용자 Viewport 에 맞춰 다른 이미지를 제공할 경우 <srcset> 사용
  • 사용자의 Viewport 에 따라 사전에 여러 이미지를 로드한 후, 상황에 맞게 적절한 이미지를 제공할 수 있다.

✏️ CLS 를 계산할 때 포함되는 지표

레이아웃 변경 점수를 계산하는 공식은 (표시 영역의 크기)(렌더링 된 두 프레임 간 표시 영역 내 불안정한 요소의 이동) 을 곱한다.
이는 곧 영향 비율거리 비율 의 곱을 의미한다.

alt text

  1. 영향 비율
    • 예상치 못하게 움직인 요소가 두 프레임 간의 표시 영역 (Viewport) 에 미치는 영향을 측정한다.
    • 위의 사진에서는 특정 요소가 Viewport 높이의 25% 정도 아래로 내려간 상황을 표현했다.
    • 빨간색 점선 영역은 두 프레임에서 요소가 표시된 영역을 나타냈고, 총 표시 영역은 전체 Viewport 의 75% 이므로 영향 비율은 0.75 로 계산된다.

alt text

  1. 이동 거리 비율
    • 예상치 못하게 움직인 요소가 이동한 가장 큰 거리 (가로 혹은 세로 중) 를 Viewport 의 최대 크기 (width, height 중 큰 값) 로 나눈 값이다.
    • 위의 사진에서는 특정 요소가 Viewport 높이의 25% 정도 아래로 내려간 상황을 표현했다.
    • 현재 Viewport 의 최대 크기는 높이이며, 해당 높이를 기준으로 25% 이동했으므로 거리 비율은 0.25 로 계산된다.

두 기준으로 산정된 값을 곱하여 상단의 예시에서 보여진 레이아웃 변경 점수를 산출한다.

  • 따라서 0.75의 영향 비율과 0.25의 거리 비율은 0.75 * 0.25 = 0.1875 의 레이아웃 변경 점수를 생성합니다.

✏️ TTFB (Time To First Byte)

  1. 정의
  • TTFB (Time To First Byte) 는 브라우저가 웹 페이지의 첫번째 바이트를 수신하는데 걸리는 시간을 의미한다.
  • 페이지를 요청하고 서버로부터 최초의 응답이 오는 바이트까지 얼마나 걸리는지를 측정하는 지표다.

  1. 기준 지표
  • 600ms 이하일 시 준수한 성능을 보이며, 1800ms 이상 걸릴 시 개선이 필요한 것으로 간주된다.
  1. 어떨 때 주의깊게 봐야 하는가?
  • SSR 기반의 웹 애플리케이션에서 주의 깊게 봐야 한다. 서버에서 HTML 을 생성하는 작업이 느릴수록 TTFB 가 길어지기 때문이다.
  • 웹페이지의 서버와 사용자가 멀리 떨어져 있어 데이터 서빙 속도가 느린 경우에 대해서도 Edge Server 를 고려하기 위한 지표가 된다.
  1. 개선 방안
  • SSR 로직을 최적화하여 불필요한 과정 없이 데이터가 빠르게 전달될 수 있도록 설계해야 한다.
  • 웹 페이지를 주로 방문하는 사용자의 국적을 확인하여 해당 Region 에 Edge Server 를 두는 것이 좋다.
  • React 기반의 SSR 이라면 renderToString 보다는 renderToPipeableStream 같이 Stream 기반의 전송 방식을 추천한다. (한번에 보내지 않고 나누어 연속적으로 전송)

✏️ FCP (First Contentful Paint)

  1. 정의
  • FCP (First Contentful Paint) 페이지가 로드되기 시작한 시점부터 컨텐츠의 일부가 화면에 보이기까지 걸리는 시간을 의미한다.
  • 지표 측정에 쓰이는 컨텐츠의 경우 이미지, 텍스트, SVG 등이 모두 포함된다.
  1. 기준 지표

alt text

  • 일반적으로 FCP 는 1.8초 내에 이루어지면 좋고, 3초 이상 걸릴 경우 개선이 필요하다고 본다.
  1. 개선 방안
  • 서버로부터 빠르게 컨텐츠를 받아야 하므로 TTFB 지표의 개선이 선행되어야 한다.
  • 가급적 렌더링 차단 요소를 최소화 하여 화면에 유의미한 컨텐츠가 보이도록 한다.
  • 사용자에게 보여지는 요소에 대해서만 렌더링을 수행하고, 숨겨진 영역은 Lazy 하게 데이터를 가져온다.
  • 전체 DOM 노드는 1500개, Depth 는 32단계까지, 자식 노드는 60개를 최대로 가지도록 하여 DOM 크기를 최소화 한다.
  • 페이지 리다이렉트를 최소화 하여 서버로부터 다시 데이터를 인계받는 일이 적도록 한다.
profile
항상 왜 이걸 써야하는지가 궁금한 사람

0개의 댓글