[FE]webpack-bundle-analyzer

Choise.o·2025년 6월 12일
0

FE 프로젝트 빌드 파일 크기가 커지면 초기 로딩 속도가 느려지고 dev 서버 구동 시에도 시간이 오래 걸린다.
용량을 줄일 수 있는 방법은 뭐가 있을까? 코드 스플리팅 설정은 되어있는데 실제로 잘 적용되고 있을까?

webpack-bundle-analyzer를 사용하여 빌드 설정을 분석하고 개선해보자.


🔧 webpack-bundle-analyzer란?

webpack-bundle-analyzer는 Webpack이 만든 번들 결과물을 트리맵(Tree Map) 형태로 시각화하여 보여주는 도구이다.

어플리케이션이 어떤 라이브러리에 의해 얼마나 무거워졌는지 한눈에 볼 수 있다.

⚙️ 설치 및 설정 방법 (vue.config.js 기준)

  • npm을 사용하여 dev 환경에만 설치했다.
npm install --save-dev webpack-bundle-analyzer
  • vue.config.js 설정
// 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' },
      ]);
    ...
  },
}

위와 같이 설정하면 끝인데 작은 문제가 있었다.


ESLint 오류

사내 개발 중인 프로젝트는 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 sizeWebpack 기준 용량트리셰이킹 전 전체 모듈의 크기
parsed size최종 번들 크기트리셰이킹 적용 후 실제 번들에 포함된 크기
gzip size압축 후 용량실제 사용자에게 전송되는 용량 (gzip 기준)

일반 사용자가 다운로드 받는 용량은 gzip size에 해당한다.

번들 전체의 용량도 확인할 수 있고 각 번들을 구성하고 있는 라이브러리에 대한 용량도 확인할 수 있다.
아래는 chunk-vendors 내부의 highlight.js 라이브러리가 차지하는 용량이다.


개선 작업

많은 번들 중에서 가장 큰 용량을 차지하는 chunk-vendors 를 분석하고 개선을 시도해봤다.

1. moment 다국어 파일 제거

moment는 javascript에서 많이 사용되는 시간 관련 라이브러리이고 다국어를 지원한다. 기본 설정으로는 모든 다국어 파일을 번들에 포함시킨다.

대체로 많은 프로젝트가 그러하듯 사내 중인 프로젝트에서도 다국어 설정은 ko 와 en 정도만 사용하고 있다. 나머지 다국어 파일은 불필요하기 때문에 번들에서 제외시켜야겠다.

  • AS-IS : 모든 locale 포함
  • TO-BE : 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/]);
    ...
  },
}

다시 빌드에서 결과를 살펴보면

  • moment 에서 ko와 en만 남은 것을 시각적으로 확인할 수 있고
  • 용량에서도 개선된 수치를 확인할 수 있다. 684.73KB → 195.47KB(Stat size 기준)

2. lodash import 방식 개선

lodash도 많이들 개선 타겟으로 잡는 라이브러리이다. 내가 작업 중인 프로젝트에서는 아래와 같이 잘못(?)되어있는 코드가 없어 적용하진 못했으나 기록해두려한다.

  • 잘못된 코드 : import _ from 'lodash' → 전체 lodash 포함 ❌
  • 개선 코드 : import debounce from 'lodash/debounce'

→ lodash 사용 시 '개선 코드'처럼 작성할 경우 트리 셰이킹에 유리하다. 사용하지 않는 함수는 번들에서 제거된다.

이외에도 코스플리팅이나 UI 아이콘을 사용하는 것만 import 하는 등의 개선 방법이 있다. 좀 더 분석하고개선 포인트를 더 찾아서 작업한 뒤 총 번들 용량을 줄여봐야겠다.


TODO : 추가 개선 작업 후 번들 용량, 최초 로딩 속도, Lighthouse 점수 비교

참고

0개의 댓글