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만으로 성능 개선이 가능했다.