프론트엔드 웹사이트 초기 렌더링 시간 줄이기

gyujae·2022년 8월 18일
1

Web Vitals

Web Vitals는 웹에서 우수한 사용자 경험을 제공하는 데 필수적인 품질 신호에 대한 통합 지침을 제공하기 위한 Google의 이니셔티브입니다.
https://web.dev/vitals/

생각해야 하는 것들

초기 렌더링

  • 번들 사이즈
    애플리케이션에 기능이 추가되면서 번들 사이즈가 커졌고 이로 인해 초기 렌더링이 늦어지는 문제가 발생하게 됩니다. 네트워크 비용을 줄이기 위해 Webpack으로 번들링했던 소스코드를 다시 적절한 단위로 코드 스플리팅(Code Splitting)을 하기도 하고 사용되지 않는 코드, 불필요한 코드들을 덜어내기 위한 트리 세이킹(Tree Shaking)을 위한 작업을 하기도 합니다. 이러한 노력을 하더라도 개선할 수 있는 부분엔 한계가 존재했습니다. 초기에 렌더링되는 index.html 자체가 비어있는 문서(Document)이기 때문에 스크립트가 실행되어 실제로 렌더링이 되기까지의 시간이 존재하기 때문입니다.
  • 렌더링 시점
    그렇다면 이제 렌더링 시점을 어떻게 앞당길 것인가에 대한 문제를 해결해야 됩니다. 사용자가 웹사이트 에 접근했을 때, 사용자가 최종적으로 볼 수 있는 화면을 서버에서 미리 그리고 그 화면을 브라우저에 전달해주면 초기 렌더링 시점이 앞당겨지지 않을까요? 물론 인터랙션이 가능해지기 까지는 하이드레이트(Hydrate) 시간이 필요하지만, 사용자 입장에서는 우선 화면이 보여지는 것이 중요합니다. 초기에 렌더링 되는 index.html이 비어있는 문서가 아니라 무언가 렌더링되어 있는 문서라면 LCP(Largest Contentful Paint) 시점을 크게 앞당길 수 있을 것입니다

    토스에서 초기 렌더링 시간 줄인 방법

    JAM Stack

    JAM Stack이란 JavaScript와 Markup에 해당하는 HTML, CSS 정적 리소스들을 활용하여 웹 애플리케이션을 구성하는 스택을 말합니다. 그리고 이 정적 리소스들을 CDN(Content Delivery Network)에 배포하여 서버 관리를 최소화 할 수 있습니다.
    https://jbee.io/web/jam-stack/

SSG

Static Site Generation이라는 개념인데요, 앱을 빌드하는 시점에 미리 그려두고 이를 서빙(serving)하는 방식을 말합니다. JAM Stack에서 정적 리소스를 생성하는 용도로 사용합니다. 컴파일 단계에서 미리 그릴 수 있는 부분을 최대한 그려서 사용자에게 도달하는 최초 index.html 파일이 비어있지 않도록 합니다. 미리 그릴 수 있다는 것은 말 그대로 컴파일 단계에서 리액트 코드를 읽어 HTML로 렌더링 할 수 있는 부분을 말합니다. 정적인 부분을 포함하여 인증이 필요하지 않은 데이터 또한 서버로부터 가져와 미리 그릴 수 있습니다.

How?

  • Next.js
    Next.js 라는 프레임워크를 사용하고 있습니다. Next.js는 서버 사이드 렌더링은 물론이고 앞서 설명드린 Static Site Generate 또한 지원합니다.
  • Suspense
    우선 토스 대부분의 프런트엔드 애플리케이션 제품은 React의 Suspense를 통해 비동기를 제어하고 있으며 토스페이먼츠 제품 또한 예외가 아니었습니다. 이와 동시에 에러 핸들링 또한 ErrorBoundary를 통해 제어하면서 비동기 상황을 제어하고 있습니다.
  • 컴포넌트 배치 되돌아보기
    우선 Suspense가 정말 필요한 컴포넌트인지, 레이아웃 영역인지 되돌아 볼 필요가 있습니다. 정말 Suspense가 필요한 영역이라면 fallback 컴포넌트를 정의해줄 때 로딩 컴포넌트만 정의해주지 않는다면 어떨까요? API 응답이 돌아오고 결국 그려질 컴포넌트와 응답이 오지 않았을 경우 보여줄 이 fallback 컴포넌트를 최대한 비슷하게 구성해주는 겁니다. 그렇다면 컴파일 시점에 그릴 수 있는 영역이 늘어나지 않을까요? 즉, 위와 같이 Loading 컴포넌트만 렌더링하지 않으려면 API 응답이 돌아왔을 때 그려져야 할 컴포넌트와 응답이 아직 돌아오지 않았을 때 보여줄 컴포넌트 두 벌이 최대한 비슷하게 구성되어 있어야 합니다.
  • 컴포넌트와 API를 가깝게
    너무나 당연하게도 이 모든 API 응답은 제각각으로 올 것이고 모든 응답이 돌아오기를 기다렸다가 그려주는 것은 정말 낭비입니다.
  1. 각각의 API들을 따로 격리시켜 서로의 렌더링을 block하지 않도록 합니다.
  2. 데이터가 필요한 곳에서 가장 가까운 곳에서 API를 호출합니다. client caching이 이젠 너무나도 자연스럽기 때문에 이를 최대한 활용해줍니다.
  • React Server Component
    지난 Next.js Conf에서 공식적으로 React의 Server Component를 사용한 렌더링 방식이 공개되었습니다. React 18도 알파 단계이니 프런트엔드 애플리케이션을 개발하면서 성능 상 이점을 많이 챙길 수 있는 환경으로 뒤바꿈 될 것 같습니다. ISR 방식과 컴포넌트 단위의 캐싱이 적용되어 웹이 더 빨라질 수 있을 것이라 기대합니다.

0개의 댓글