FE 프로젝트 빌드 파일 크기가 커지면 초기 로딩 속도가 느려지고 dev 서버 구동 시에도 시간이 오래 걸린다.
용량을 줄일 수 있는 방법은 뭐가 있을까? 코드 스플리팅 설정은 되어있는데 실제로 잘 적용되고 있을까?
webpack-bundle-analyzer를 사용하여 빌드 설정을 분석하고 개선해보자.
webpack-bundle-analyzer는 Webpack이 만든 번들 결과물을 트리맵(Tree Map) 형태로 시각화하여 보여주는 도구이다.
어플리케이션이 어떤 라이브러리에 의해 얼마나 무거워졌는지 한눈에 볼 수 있다.
⚙️ 설치 및 설정 방법 (vue.config.js 기준)
npm install --save-dev webpack-bundle-analyzer
// vue.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
// configureWebpack에 설정할 수도 있는데 기존에 chainWebpack을 사용 중에서 아래처럼 설정했다.
chainWebpack(config) {
...
config
.plugin('webpack-bundle-analyzer')
.use(BundleAnalyzerPlugin, [
{ analyzerMode: 'static', openAnalyzer: true, reportFilename: 'bundle-report.html' },
]);
...
},
}
위와 같이 설정하면 끝인데 작은 문제가 있었다.
사내 개발 중인 프로젝트는 TypeScript 기반이며 ESLint가 설정되어 있다. 이 경우 require() 를 사용하면 아래의 오류가 발생한다.

error Require statement not part of import statement @typescript-eslint/no-var-requires
TypeScript는 모듈 시스템을 지원하며 import 문법이 정적 분석, 타입 추론, 트리 셰이킹(tree shaking)에 더 유리하기 때문에 위와 같이 require 사용을 제한한다.
위의 구문을 import 사용 방식으로 변경하려 했으나 import를 사용했더니 빌드가 실행되지 않았다. vue.config.js는 기본적으로 CommonJS module 문법을 기대하기 때문에 호환성 오류가 발생할 수 있다고 한다.
오류 해결을 위해 아래 방법을 적용했다.
# .eslintrc.js
module.exports = {
...
overrides: [
{
files: ['vue.config.js'], // vue.config.js 파일에서 규칙 override
rules: {
'@typescript-eslint/no-var-requires': 'off', // require를 사용에 의한 경고 비활성화
'global-require': 'off', // require를 함수 바깥에서 사용하는 것을 금지하는 규칙 경고 비활성화
},
},
],
};
vue.config.js 파일에만 규칙 적용을 제외시켰더니 해결됐다.
이제 빌드 결과를 분석해보자.
npm run build를 실행하면 빌드 파일 경로에 앞에서 reportFilename으로 설정한 파일명으로 분석 파일이 생성된다.
각 번들이 어떤 라이브러리 등으로 구성되어 있고 용량은 얼마나 차지하는지 등을 시각적으로 확인할 수 있다.

번들에 마우스를 올려보면 용량 정보를 확인할 수 있다.

세 가지 size가 보여지는데 각각 아래의 의미를 가진다.
| 구분 | 의미 | 설명 |
|---|---|---|
stat size | Webpack 기준 용량 | 트리셰이킹 전 전체 모듈의 크기 |
parsed size | 최종 번들 크기 | 트리셰이킹 적용 후 실제 번들에 포함된 크기 |
gzip size | 압축 후 용량 | 실제 사용자에게 전송되는 용량 (gzip 기준) |
일반 사용자가 다운로드 받는 용량은 gzip size에 해당한다.
번들 전체의 용량도 확인할 수 있고 각 번들을 구성하고 있는 라이브러리에 대한 용량도 확인할 수 있다.
아래는 chunk-vendors 내부의 highlight.js 라이브러리가 차지하는 용량이다.

많은 번들 중에서 가장 큰 용량을 차지하는 chunk-vendors 를 분석하고 개선을 시도해봤다.
moment는 javascript에서 많이 사용되는 시간 관련 라이브러리이고 다국어를 지원한다. 기본 설정으로는 모든 다국어 파일을 번들에 포함시킨다.

대체로 많은 프로젝트가 그러하듯 사내 중인 프로젝트에서도 다국어 설정은 ko 와 en 정도만 사용하고 있다. 나머지 다국어 파일은 불필요하기 때문에 번들에서 제외시켜야겠다.
ko, en를 제외한 나머지는 불포함// vue.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
// configureWebpack에 설정할 수도 있는데 기존에 chainWebpack을 사용 중에서 아래처럼 설정했다.
chainWebpack(config) {
...
// moment 미사용 다국어 파일 제외
config
.plugin('moment-locales')
.use(webpack.ContextReplacementPlugin, [/moment[/\\]locale$/, /ko|en/]);
...
},
}
다시 빌드에서 결과를 살펴보면

lodash도 많이들 개선 타겟으로 잡는 라이브러리이다. 내가 작업 중인 프로젝트에서는 아래와 같이 잘못(?)되어있는 코드가 없어 적용하진 못했으나 기록해두려한다.
import _ from 'lodash' → 전체 lodash 포함 ❌import debounce from 'lodash/debounce' ✅→ lodash 사용 시 '개선 코드'처럼 작성할 경우 트리 셰이킹에 유리하다. 사용하지 않는 함수는 번들에서 제거된다.
이외에도 코스플리팅이나 UI 아이콘을 사용하는 것만 import 하는 등의 개선 방법이 있다. 좀 더 분석하고개선 포인트를 더 찾아서 작업한 뒤 총 번들 용량을 줄여봐야겠다.