Webpack 3 코드 스플리팅으로 번들 사이즈 40% 줄인 후기
문제 상황
운영 중인 관리자 페이지의 초기 로딩 시간이 5초를 넘어가기 시작했다. 번들 사이즈를 확인해보니 main.js가 2.3MB에 달했다. 모든 라우트의 컴포넌트와 라이브러리가 하나의 파일로 묶여있었다.
해결 과정
1. webpack-bundle-analyzer 도입
먼저 어떤 모듈이 용량을 차지하는지 파악했다.
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
moment.js의 로케일 파일들과 lodash 전체가 포함되어 있었다.
2. CommonsChunkPlugin 설정
vendor 번들을 분리했다.
module.exports = {
entry: {
app: './src/index.js',
vendor: ['react', 'react-dom', 'react-router']
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity
})
]
};
3. 라우트별 코드 스플리팅
React Router와 dynamic import를 조합했다.
import Loadable from 'react-loadable';
const Dashboard = Loadable({
loader: () => import('./pages/Dashboard'),
loading: () => <div>Loading...</div>
});
const UserManagement = Loadable({
loader: () => import('./pages/UserManagement'),
loading: () => <div>Loading...</div>
});
4. 불필요한 모듈 제거
moment.js는 IgnorePlugin으로 불필요한 로케일을 제외했다.
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]
lodash는 필요한 함수만 개별 import로 변경했다.
// Before
import _ from 'lodash';
// After
import debounce from 'lodash/debounce';
import throttle from 'lodash/throttle';
결과
- main.js: 2.3MB → 850KB
- vendor.js: 550KB (새로 생성)
- 초기 로딩: 5.2초 → 2.1초
- 라우트별 chunk: 50~200KB
캐싱 효과까지 고려하면 재방문 시 로딩 속도는 더 개선되었다. 코드 스플리팅은 이제 프로젝트 초기부터 고려해야 할 필수 요소라는 것을 체감했다.