React 16.6 lazy와 Suspense로 코드 스플리팅 적용하기

문제 상황

관리자 대시보드 프로젝트의 초기 번들 크기가 1.2MB를 넘어서면서 첫 로딩이 느려지는 문제가 발생했다. 사용자가 실제로 접근하지 않는 페이지들까지 모두 초기 번들에 포함되어 있었다.

기존에는 react-loadable을 사용해 코드 스플리팅을 고려했으나, React 16.6에서 공식적으로 lazy와 Suspense가 추가되면서 이를 활용하기로 결정했다.

적용 방법

기존 라우팅 코드를 다음과 같이 변경했다.

import React, { lazy, Suspense } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';

const Dashboard = lazy(() => import('./pages/Dashboard'));
const UserManagement = lazy(() => import('./pages/UserManagement'));
const Statistics = lazy(() => import('./pages/Statistics'));

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<div>Loading...</div>}>
        <Switch>
          <Route path="/" exact component={Dashboard} />
          <Route path="/users" component={UserManagement} />
          <Route path="/stats" component={Statistics} />
        </Switch>
      </Suspense>
    </BrowserRouter>
  );
}

개선 결과

  • 초기 번들 크기: 1.2MB → 380KB
  • 첫 페이지 로딩 시간: 3.2초 → 1.1초
  • Lighthouse 점수: 62점 → 84점

Webpack의 청크 분리가 자동으로 이루어지면서 각 페이지별로 별도 번들이 생성되었다.

주의사항

lazy는 default export만 지원한다. named export를 사용하는 경우 중간 모듈을 만들어야 한다.

// NamedExportWrapper.js
export { UserManagement as default } from './UserManagement';

// App.js
const UserManagement = lazy(() => import('./NamedExportWrapper'));

또한 Suspense는 현재 서버사이드 렌더링을 지원하지 않는다. SSR 프로젝트라면 여전히 react-loadable을 사용해야 한다.

결론

React 16.6의 lazy와 Suspense는 간단한 API로 효과적인 코드 스플리팅을 구현할 수 있게 해준다. 추가 라이브러리 없이 공식 API만으로 성능 개선이 가능했다.

React 16.6 lazy와 Suspense로 코드 스플리팅 적용하기