사례 연구: React 번들 크기를 68% 줄인 방법
Source: Dev.to
Introduction
저는 B2B 애플리케이션을 작업하면서 흔히 있는 오해를 마주했습니다. “사용자는 사무실 PC에서 빠른 인터넷을 사용하니 구글 코어 웹 바이탈스와 번들 크기가 커도 괜찮다”는 생각이었습니다. 실제로는 주요 사용자가 모바일 인터넷을 사용하는 스마트폰으로 애플리케이션에 접속하고 있었습니다. 이를 알게 된 뒤 최적화가 급선무가 되었습니다.
시작점: 프로덕션 번들 크기는 1,542 KB(gzip 압축)였습니다.
목표: 500 KB (업계 모범 사례에 따름)
Step 1: Compression – Already Optimized
첫 번째 당연한 단계는 Brotli 압축을 적용하는 것이었습니다. Brotli는 일반적으로 gzip보다 15–25 % 정도 더 절감해 줍니다. 하지만 인프라에 이미 Brotli가 적용돼 있었기 때문에 여기서는 추가 이득을 얻을 수 없었습니다.
Step 2: Route‑Based Code Splitting
React Router는 기본적으로 lazy loading을 지원합니다. 모든 라우트에 동적 import를 적용했습니다:
// Before
import Dashboard from './Dashboard';
// After
const Dashboard = React.lazy(() => import('./Dashboard'));
결과: 번들이 37 % 감소해 971 KB가 되었습니다.
Step 3: Dependency Analysis & Vendor Splitting
Webpack Bundle Analyzer를 사용해 번들을 장악하고 있던 무거운 서드파티 라이브러리를 발견했습니다:
- 날짜 선택/캘린더 라이브러리
- Feature‑flag 관리
- Analytics SDK
- PDF 편집기
- WYSIWYG 편집기
- 파일 업로드 위젯
이들 라이브러리는 여러 모듈에서 직접 import되고 있었습니다. 동적 import를 이용한 래퍼 모듈을 만들었습니다:
// Before – Direct imports everywhere
import { DatePicker } from 'heavy-date-library';
// After – Wrapper with lazy loading
export const loadDatePicker = () =>
import('heavy-date-library').then(module => module.DatePicker);
결과: 번들이 원본의 **57 %**인 879 KB로 감소했습니다.
Step 4: Module Decoupling & Dependency Chains
번들 분석 결과, 의존성 체인이 매우 촘촘히 엮여 있음을 확인했습니다. 예시:
// ❌ Tightly coupled
// Module A imported Module B, which imported Module C,
// which imported a heavy utility library
// All loaded together even if only one piece was needed
// ✅ Solution: Extract shared code to independent modules
// Created small, focused modules with only necessary shared code
// Broke circular dependencies
이러한 체인을 식별하고 분리해, 필요한 공유 코드만 포함한 작고 집중된 모듈을 만들었습니다.
결과: 63 % 감소한 571 KB가 되었습니다.
Step 5: Localization Optimization
애플리케이션은 여러 언어를 지원했지만, 사용자 선호와 무관하게 모든 번역 파일을 동기식으로 로드하고 있었습니다.
Before: 모든 언어 파일이 하나의 번들에 포함되어 있었음(≈ 120 KB JSON).
After: 사용자가 선택한 언어만 초기 로드하도록 변경:
// Dynamic locale loading
const loadLocale = (locale) =>
import(`./locales/${locale}.json`);
최종 결과: 493 KB – 68 % 감소로 500 KB 목표를 초과 달성했습니다!
Key Takeaways
- 가정은 위험하다: 데이터 없이 사용자 상황을 추정하지 마세요.
- 분석 후 최적화: Webpack Bundle Analyzer가 큰 도움이 되었습니다.
- 서드파티 라이브러리는 비용이 크다: 무거운 의존성을 전략적으로 관리하세요.
- 의존성 체인이 중요하다: 촘촘한 결합은 번들 부피를 늘립니다.
- 현지화도 무거울 수 있다: 언어 파일을 동적으로 로드하세요.