[성능 개선] 홈 화면 성능 개선하기: 2. 코드 스플리팅 (1)

HBSPS·2023년 12월 27일
0

AlgoITNi

목록 보기
2/13

Home 화면의 성능을 개선하는 이유?

우리 서비스는 특성상 Room 페이지 안에 대부분의 기능이 위치하게 된다.
결론적으로 Room 페이지에서는 우리 서비스의 거의 모든 코드가 로드 되어서 실행되어야 한다.

하지만, 이와 반대로 Home에서는 특별한 기능이 없다.
단순히 uuid를 갖는 방을 생성하거나 이미 만들어진 방에 참여하는 기능밖에 없다.

또한, 사용자가 우리 서비스를 사용할 때 가장 먼저 마주하는 페이지가 Home 화면이기 때문에 Home 화면을 개선하고자 했다.
우리 서비스의 반응성이 좋고 좋은 UX를 제공하기 위해서는 Home 화면을 개선시켜 사용자에게 좋은 인식을 심어줘야 한다고 생각했기 때문이다.
따라서, 서비스의 Home 화면을 개선하고자 했으며 앞으로의 내용은 그 과정에 관한 것이다.

Home 화면의 문제점?

우선 Home 화면에서 개선할 수 있는 것이 무엇인지 파악해야 했다.
이를 위해 LightHouse를 사용하여 분석을 진행한다.

(초기) 좌: 개발환경 / 우: 프로덕션

Home에서 정말 필요한 것

Room에서 필요한 것 (Home에서는 필요 없음)

초기 (개발환경; 캐시 사용 안함)

초기 (프로덕션; 캐시 사용 안함)

초기 빌드 결과

import ReactDOM from 'react-dom/client';
import { QueryClientProvider } from '@tanstack/react-query';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

import '@styles/index.css';
import Home from '@pages/Home.tsx';
import Room from '@pages/Room.tsx';

import Modals from './components/modal/Modals';
import reactQueryClient from './configs/reactQueryClient';
import { CRDTProvider } from './contexts/crdt';

const router = createBrowserRouter([
  {
    path: '/',
    element: <Home />,
  },
  {
    path: '/:roomId',
    element: <Room />,
  },
]);

function Main() {
  return (
    <QueryClientProvider client={reactQueryClient}>
      <CRDTProvider>
        <RouterProvider router={router} />
        <Modals />
      </CRDTProvider>
    </QueryClientProvider>
  );
}
ReactDOM.createRoot(document.getElementById('root')!).render(<Main />);

기존 코드는 단순히 Home과 Room을 모두 import 하여 사용하고 있다.
이 과정에서 Home에 불필요한 JS를 다운로드 받아야 했으며 성능에 영향을 준다고 판단했다.
이를 개선하기 위해 코드 스플리팅을 수행했으며 Room 컴포넌트에서 React의 lazy를 사용하도록 수정했다.

lazy

lazy – React

리액트의 지연 로딩을 사용하게 되면 사용자가 필요한 리소스만 그때그때 가져올 수 있다.
이를 이용해 Home에서 사용하지 않는 코드(Room에서 사용하는 코드)를 지연 로딩시킬 수 있다.
또한, 지연 로딩을 사용하면서 발생하는 딜레이 시간 동안 보여줄 Suspense 컴포넌트를 활용하여 로딩 중인 동안 보여줄 내용을 설정할 수 있다.

결과

(개선) 좌: 개발환경 / 우: 프로덕션

Home에서 필요한 것들만 다운로드

개발환경

  • DOMContentLoaded: 720ms → 230ms (약 68% 감소)
  • Load: 894ms → 393ms (약 56% 감소)

프로덕션

  • DOMContentLoaded: 260ms → 78ms (약 70% 감소)
  • Load: 644ms → 219ms (약 65% 감소)

청크가 분할된 것을 볼 수 있다.

import ReactDOM from 'react-dom/client';
import { QueryClientProvider } from '@tanstack/react-query';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

import '@styles/index.css';
import Home from '@pages/Home.tsx';
import Room from '@pages/Room.tsx';

import Modals from './components/modal/Modals';
import reactQueryClient from './configs/reactQueryClient';
import { CRDTProvider } from './contexts/crdt';
import { lazy, Suspense } from 'react';

const RoomPage = lazy(() => import('./pages/Room'));

const router = createBrowserRouter([
  {
    path: '/',
    element: <Home />,
  },
  {
    path: '/:roomId',
    element: (
      <Suspense fallback={<span>Loading...</span>}>
        <RoomPage />
      </Suspense>
    ),
  },
]);

function Main() {
  return (
    <QueryClientProvider client={reactQueryClient}>
      <CRDTProvider>
        <RouterProvider router={router} />
        <Modals />
      </CRDTProvider>
    </QueryClientProvider>
  );
}
ReactDOM.createRoot(document.getElementById('root')!).render(<Main />);

React의 lazySuspense를 도입했다.

그 결과, 더 이상 Home에서 Room에 관한 코드를 다운로드 하지 않을 수 있었고 기존에는 단일 청크로 구성되었던 빌드 파일이 Room과 Home 두 청크로 분리되었음을 확인할 수 있다.
또한, 네트워크 탭에서 각 지표가 개선 되었음을 확인할 수 있고 LightHouse의 점수가 프로덕션 기준 7점 증가했다.

네트워크 탭의 지표

위에서 개선 여부를 판단하기 위해 사용한 두 지표는 어떤 정보를 나타낼까?

DOMContentLoaded: DOM 트리를 그리는데 걸리는 시간
Load: DOM 트리 구조를 포함하여 이미지까지 화면에 로드되는 시간

두 지표는 사용자 경험을 판단하는 기준 중 가장 기본이 되는 것으로 프론트엔드 개발에 활용되는 중요한 지표 중 일부라고 한다.

profile
대체로 맑음

0개의 댓글