웹팩으로 Vue.JS 번들 크기를 줄이는 방법


작성자 : Jennifer Bland

원문 : https://medium.com/js-dojo/how-to-reduce-your-vue-js-bundle-size-with-webpack-3145bf5019b7

필자는 Stanley Black & Decker의 Industry 4.0 팀에서 일하고 있다. 최근 우리 팀은 세계적인 Stanley의 제조 공장을 위해 앱 스토어와 같은 것을 만들었다. 공장들은 온라인 시장에 방문하여 해당 지역에서 생산하는 제품을 기반으로 필요한 애플리케이션을 선택할 수 있다. 이렇게 하면 공장을 돌리기 위해 모든 애플리케이션을 함께 번들로 묶은 커스텀 빌드가 만들어진다. 그러나 이렇게 많은 양의 애플리케이션을 번들로 묶어 Vue를 프로덕션 빌드하면 크기가 초과되었다는 경고가 여러 번 나타난다.

초기 빌드 크기

빌드를 하면 다음 두 가지 에러 메시지가 발생한다.

Vue는 번들 된 각 에셋의 크기가 244 KiB를 초과하지 않을 것을 권장한다. 우리는 이 크기를 초과한 14개의 에셋을 가지고 있었다. 추가로 위에서 권장한 크기를 초과한 네 개의 엔트리 포인트 파일도 있었다. 지금부터 빌드 파일 크기를 반으로 줄이는 방법을 소개한다.

크기가 큰 번들 파일의 원인은 무엇인가?

먼저 크기가 큰 번들 파일의 원인을 알아야 했다. 원인을 찾기 위해 webpack-bundle-analyzer를 설치했다. 이 플러그인은 각 번들 아이템의 크기를 시각적인 가이드로 제공해준다.

npm install --save-dev webpack-bundle-analyzer

그 다음 vue.config.js 파일에서 이것을 사용하기 위해 webpack 설정을 했다. 필자가 vue.config.js 파일에 설정한 내용은 다음과 같다.

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
    .BundleAnalyzerPlugin;

module.exports = {
    configureWebpack: {
        plugins: [new BundleAnalyzerPlugin()]
    }
};

플러그인을 설치하고 프로덕션 빌드를 다시 실행하면 번들 파일 크기가 2.48MB로 나온다. 이미지를 보면 큰 용량의 범인을 명확히 알 수 있다.

  • vue-echarts
  • vuetify
  • moment
  • lodash

Lodash 크기 줄이기

Lodash는 번들 파일의 70.74kb를 차지하고 있었다. Lodash는 프레임워크의 모든 애플리케이션에서 두 곳에서만 사용된다. 단지 2개 메서드 때문에 번들 크기의 많은 양이 차지되고 있다.

lodash뿐만 아니라 vue-lodash도 가져오고 있었다. 문제를 해결하는 첫 번째 단계는 필요하지 않은 vue-lodash를 package.json에서 제거하는 것이다.

다음 단계는 lodash 전체 라이브러리를 가져오는 대신 필요한 2개 메서드만 가져오도록 하는 것이다. 우리는 cloneDeepsortBy를 사용하고 있었다. lodash 전체 라이브러리를 가져오던 초기 호출 방식을 변경했다.

import _ from 'lodash';

lodash에서 lodash/core로 import 구문을 변경해 필요한 2개 메서드만 가져오도록 변경했다.

import { cloneDeep, sortBy } from 'lodash/core';

이러한 변경으로 번들 파일 크기가 2.48MB에서 2.42MB로 줄어들었다. 다음 이미지는 현재 줄어든 번들 크기를 보여준다.

그리고 여기서 번들 파일의 부분으로 lodash 자체 크기를 볼 수 있다.

moment.js 크기 줄이기

Moment.js는 번들 파일에서 234.36KB를 차지하고 있었다. 이전 이미지를 보면 지원하는 모든 언어에 대한 국제화 로케일이 압도적으로 큰 용량을 차지한 것을 볼 수 있다. 번들 파일에서는 moment.js 전체를 사용하지 않으므로 불필요한 용량을 차지할 뿐이다.

다행히도 이를 제거할 수 있다. 다음 호출로 moment.js 전체를 가져오는 대신,

import moment form 'moment';

이 호출을 통해서 날짜 조작 코드만 가져올 수 있다.

import moment from 'moment/src/moment'

하지만 우리의 코드베이스에서 적어도 이 대체 코드를 만드는 것만으로는 어려움이 있다. 코드의 18곳에서 moment.js를 가져오고 있었다. 전체 검색을 해서 코드를 변경할 수 있었다. 그러나 프레임워크에 새 애플리케이션을 추가할 경우, 개발자가 기본 호출을 사용하여 moment.js를 가져올 수 있다. 그렇게 하면 우리는 또 다시 모든 국제화 로케일을 가져오게 된다.

그래서 트레이드오프로 웹팩에서 숏컷 별칭을 만들었다. 숏컷은 'moment'를 'moment/src/moment'로 가져오는 모든 호출을 대체한다. resolve 옵션을 사용하고 별칭을 설정하여 vue.config.js 파일에 별칭을 추가할 수 있다. 다음은 필자가 설정한 vue.config.js 파일이다.

현재 프로덕션 빌드를 실행하면 번들 파일 크기가 2.22MB로 줄어들었다.

이미지에서 moment.js를 보면 국제화 로케일이 더 이상 로드되지 않는 것을 볼 수 있다.

moment.js에서 로케일을 제거하면, 서버를 실행할 때마다 코드에서 ./locale를 찾을 수 없다고 에러가 발생한다. 이 문제에 대해서 찾아보니 이전부터 있었던 moment.js의 노운 이슈인 것을 알게되었다. moment.js는 로케일을 항상 로드한다고 가정한다. 날짜 조작 기능만 로드할 수는 없다.

이를 해결하기 위해 빌트인 웹팩 플러그인 IgnorePlugin을 사용해 이 메시지를 무시했다. 다음은 필자가 vue.config.js 파일에 추가한 플러그인 코드다.

new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)

Vuetify.js 크기 줄이기

다음 목표는 Vuetify.js의 크기다. Vuetify는 500.78KB를 차지하고 있었다. 이것은 하나의 벤더가 차지하기에 많은 양이다.

Vuetify는 마치 원하는 것만 골라 담을 수 있는 식사(a-la-carte) 같은 기능을 제공한다. 이는 사용하는 Vuetify 컴포넌트만 가져올 수 있다는 것을 의미한다. 그리고 이렇게 하면 크기가 줄어든다. 문제는 우리가 사용하고 있는 컴포넌트를 확인하고 처리하려고 하는 애플리케이션이 너무 많다는 것이다.

현재 Vuetify 버전(아티클을 작성할 당시 1.56 버전)에서는 vuetify-loader를 제공하고 있다. vuetify-loader는 코드를 살펴보고 사용중인 모든 컴포넌트를 확인한 다음 번들로 가져올 것이다. 참고: 결국 vuetify v2에 이 기능이 내장되었다. 2 버전을 사용하기 전까지는 사용하는 컴포넌트만 가져오기 위해 vuetify-loader를 사용해야 한다. Vuetify 문서에 따르면 필요한 모든 스타일을 얻으려면 stylus로 가져와야 한다.

필자는 우리가 vuetify.js 구 버전을 실행하고 있었다는 것을 알게 되었다. 그래서 vuetify 버전을 최신으로 업그레이드 하기로 했다. 또한 스타일 관련된 것들과 vuetify-loader를 같이 설치했다. (역자주 : vuetify 외 다른 모듈은 --save-dev 옵션을 사용하여 devDependencies로 설치해야 한다)

npm install vuetify vuetify-loader stylus stylus-loader style-loader css-loader --save

Vuetify를 가져오는 플러그인 코드에는 테마가 회사의 색상표를 사용하도록 정의되어 있다. 현재 필자의 Vuetify 플러그인은 다음과 같다.

vuetify/lib으로 가져오기 위해 Vuetify import 방식을 변경해야 한다. 또한 모든 스타일을 얻기 위해 stylus를 import 했다. 현재 필자의 플러그인 코드는 다음과 같다.

마지막 단계는 사용하는 컴포넌트만 가져올 수 있도록 웹팩에서 vuetify-loader 플러그인을 설정하는 것이다. 플러그인을 require로 가져오고 배열로 플러그인을 추가한다. 필자의 vue.config.js는 다음과 같다.

현재 실행된 프로덕션용 번들 파일 크기는 2MB가 되었다.

vue-echarts 크기 줄이기

Vue-echarts는 필자의 번들 파일에서 그다지 크지 않은 요소이다. Vue-echarts는 echarts 위에서 실행된다. Vuetify와 같이 Vue-echarts, echarts도 구 버전을 실행하고 있다. 두 모듈을 최신 버전으로 업그레이드 하기 위해 다음 명령어를 실행한다.

npm install echarts vue-echarts --save

필자는 vue-echarts의 깃헙 레포를 조사하다가 클로즈 된 이슈들 중에서 다음 내용을 찾았다. 최신 버전의 vue-echarts를 사용하면 가져오는 코드를 변경해 더 작은 크기의 번들을 로드할 수 있다. 이전에는 이렇게 vue-echarts를 가져오고 있었는데,

import ECharts from 'vue-echarts';

이렇게 변경했다.

import ECharts from 'vue-echarts/components/ECharts.vue';

프로덕션 빌드를 실행하면 번들 파일 크기는 1.28MB로 줄어든다.

결론

목표는 우리 애플리케이션의 프로덕션용 번들 파일 크기를 줄이는 것이었다. 초기 번들 파일 크기는 2.48MB였다. 몇 가지 변경을 통해서 번들 파일 크기를 1.2MB로 줄일 수 있었다. 크기가 거의 절반으로 줄었다.

만약 프로덕션용 Vue 애플리케이션을 만든다면 당신의 번들 파일 크기를 평가해봐야 한다. webpack-bundle-analyzer를 사용해 많은 공간을 차지하고 있는 항목을 확인한다. 그리고 나서 이 항목들의 크기를 줄이기 위해 필요한 단계들을 시작한다. 이러한 방식으로 필자의 번들 파일에서는 네 가지 가장 큰 항목의 크기를 줄일 수 있었다.

이 글에서 설명한 단계를 따라서 여러분의 프로덕션용 번들 사이즈도 줄일 수 있길 바란다. 질문이 있거나 코멘트가 필요하다면 아래에 남겨달라. 읽어줘서 고맙다.