프로덕션 환경에서 Vue 애플리케이션을 빌드하면
chunk-vendors 번들이 과도하게 커져 초기 화면 로딩이 지연되는 문제가 자주 발생한다. 이 글에서는 빌드 단계와 서버 설정을 함께 다루어 전송 크기를 줄이고 실제 로딩 시간을 단축하는 방법을 살펴본다.compression-webpack-plugin으로 gzip 자산 생성
빌드 시점에 정적 파일을 gzip으로 미리 압축하면 서버 부담을 줄이고 브라우저 전송 속도를 높일 수 있다. 먼저 패키지를 설치한다.
# npm 사용
npm install --save-dev compression-webpack-plugin@6.1.1
# yarn 사용
yarn add compression-webpack-plugin@6.1.1 --dev
버전 충돌 주의: 최신 버전(v9 이상)은 Webpack 5 문법을 사용해 기존 Vue CLI 환경에서 TypeError: Cannot read property 'tapPromise' of undefined 오류가 발생할 수 있다. Node 12~14 환경에서는 6.x 대 버전을 사용하는 것이 안정적이다.
vue.config.js 설정
const CompressPlugin = require('compression-webpack-plugin')
module.exports = {
chainWebpack: cfg => {
if (process.env.NODE_ENV !== 'production') return
cfg.plugin('gzip-assets').use(CompressPlugin, [{
test: /\.(js|css)$/i,
threshold: 10240, // 10KB 이상만 압축
minRatio: 0.8, // 압축률 80% 이상일 때만 적용
deleteOriginalAssets: false // 원본 파일 보존
}])
}
}
Nginx에서 gzip 정적 파일 서빙
빌드 산출물의 .gz 파일을 Nginx가 우선 반환하도록 설정하면 실시간 압축 부하 없이 빠르게 전송된다.
핵심 설정
server {
listen 80;
server_name _;
# 동적 gzip 압축 활성화
gzip on;
gzip_static on; # .gz 파일이 있으면 우선 반환
gzip_min_length 1024; # 1KB 미만은 압축 대상 제외
gzip_comp_level 5; # 압축률과 CPU 사용량 균형
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_types
text/plain
text/css
application/javascript
application/x-javascript
text/javascript
application/xml
text/xml;
location / {
root /var/www/app/dist;
try_files $uri $uri/ /index.html;
}
}
주요 디렉티브 의미
| 디렉티브 | 설명 |
|---|---|
gzip on | 응답 시 gzip 압축 활성화 |
gzip_static on | 미리 압축된 .gz 파일을 먼저 찾아 반환 |
gzip_min_length | 설정 값보다 작은 파일은 압축에서 제외 |
gzip_comp_level | 1~9, 높을수록 압축률은 좋으나 CPU 소모 증가 |
gzip_types | 압축 대상 MIME 타입 지정 |
gzip_vary | 캐시 서버가 Accept-Encoding 헤더를 구분하도록 지시 |
실제 적용 예시
빌드 설정 통합
const CompressPlugin = require('compression-webpack-plugin')
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
productionSourceMap: false,
chainWebpack: cfg => {
// SVG 처리 규칙 커스터마이징
const svg = cfg.module.rule('svg')
svg.uses.clear()
svg
.test(/\.svg$/)
.use('sprite-loader')
.loader('svg-sprite-loader')
// 프로덕션에서만 gzip 플러그인 적용
if (process.env.NODE_ENV === 'production') {
cfg.plugin('compress').use(CompressPlugin, [{
test: /\.(js|css)$/,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: false
}])
}
},
devServer: {
open: true,
port: 8001,
overlay: { errors: true, warnings: true }
}
}
Nginx 가상 호스트 설정
server {
listen 80;
server_name localhost;
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_types text/plain application/javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
location / {
root /home/vue/dist;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
설정 변경 후 Nginx를 재시작한다.
nginx -s reload
번들 구성 분석으로 과도한 의존성 제거
gzip 적용 후에도 chunk-vendors가 여전히 크다면 webpack-bundle-analyzer로 번들 구성을 시각화하여 불필요한 대용량 라이브러리를 찾아낼 수 있다.
설치 및 적용
npm install --save-dev webpack-bundle-analyzer
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false
})
]
}
}
빌드 후 dist/report.html을 열면 각 모듈이 차지하는 비율을 한에 파악할 수 있다. 실무 사례에서는 미사용 대용량 패키지 3개를 제거하여 chunk-vendors를 7.7MB에서 3.1MB로, gzip 후에는 900KB 수준으로 줄인 경험이 있다.