Angular main bundle 사이즈 줄이기
in Javascript
어느 순간부터 회사에서 작업 중인 앵귤러 프로젝트들의 main 사이즈가 커져서 초기 로딩이 늦어지는 이슈가 있었다.
아래 이미지처럼 초기에 로딩되는 앵귤러 bundle 파일이 1.6MB나 됐었고, Fast 3G
환경에서는 로딩하는데 약 11~12초정도나 걸렸다.
1. 이슈 원인 파악
우선 번들 파일을 확인하기 위해 webpack-bundle-analyzer
를 설치한 후, package.json
에 아래 스크립트를 추가해준다.
stats 파일은 tsconfig.json의 target에 따라 달라진다.
$ npm install -D webpack-bundle-anlayzer
# package.json
...
"scripts": {
...
"analyze": "ng build --aot --prod --stats-json && webpack-bundle-analyzer ./dist/my-angular-project/stats-es2015.json"
}
npm run analyze
를 통해 bundle 파일을 확인해보니 @lemoncloud/components
라이브러리가 전체 번들 사이즈의 반 이상 차지하고 있었다. 회사에서 주로 사용하는 컴포넌트나 서비스는 따로 라이브러리화해서 사용 중이었는데, 라이브러리 최적화가 잘못된건지 사이즈가 상당히 컸다.
확인해보니 font, img 등 asset 파일들도 포함되어 있어서 사이즈가 비정상적으로 컸다.
일단 이슈가 급하니, 사용하는 컴포넌트들만 빼서 해당 프로젝트에 다시 만들고 @lemoncloud/components
라이브러리를 걷어냈다. 이 라이브러리만 걷어내니 main.js
의 크기가 약 700KB로 감소했다.
일단 안쓰는 라이브러리들은 다 삭제해주자.
2. bundle 파일 압축(gzip)하기
좀 더 지연시간을 줄이기 위해 gzip을 활용해서 bundle 파일들을 압축하기로 했다.
2-1. @angular-builders/custom-webpack
설치
@angular-builders/custom-webpack
은 angular의 기본 빌드 환경에서 추가적으로 웹팩을 설정할 수 있는 라이브러리이다. 웹팩의 compression-webpack-plugin
플러그인을 사용하기 위해 설치했다.
$ npm install -D @angular-builders/custom-webpack
$ npm install -D compression-webpack-plugin
2-2. angular.json 파일 수정
angular.json 파일을 다음과 같이 수정한다.
angular의 버전에 따라 아래 내용이 다를 수 있다.
...
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.config.js"
},
...
2-3. webpack.config.js 파일 추가
프로젝트의 루트에 webpack.config.js 파일을 생성 후 아래와 같이 수정한다.
const CompressionPlugin = require(`compression-webpack-plugin`);
module.exports = {
plugins:[
new CompressionPlugin({
test: /\.(js|css)$/,
filename(info) {
const opFile = info.path.split('.');
const opFileType = opFile.pop();
const opFileName = opFile.join('.');
return `${opFileName}.${opFileType}.gz`;
}
})
],
}
위 설정을 마친 후, 프로젝트를 빌드하면 아래와 같이 gz
파일도 생성된다.
이제 js
, css
파일 대신에 gz
파일들을 AWS S3에 올려 호스팅해야 한다.
3. AWS S3에 gzip 파일 업로드
scripts
폴더를 생성한 후, deploy.sh
파일을 추가한다.
스크립트 내용을 요약하면 다음과 같다.
.js
,.css
파일 삭제.gz
파일 이름 변경(gz
확장자 삭제)- content-encoding을 gzip으로 설정 후 s3 업로드
#!/bin/bash
APP_NAME=my-angular-project
# delete origin js, css files
while IFS= read -r file; do rm ${file}; done < <(find dist/${APP_NAME}/ -type f -name "*.{js|css}")
# rename gzip files to remove .gz extension
while IFS= read -r file; do mv $file ${file%.gz}; done < <(find dist/${APP_NAME}/ -type f -name "*.gz")
# sync data to AWS S3
echo 'Deploy to S3'
aws s3 sync dist/${APP_NAME} s3://${APP_NAME} --metadata-directive REPLACE --acl public-read --exclude "index.html" --exclude "*.css" --exclude "*.js" || { echo 'ERROR: s3 sync failed' ; exit 1; }
aws s3 sync dist/${APP_NAME} s3://${APP_NAME} --metadata-directive REPLACE --acl public-read --exclude "*" --include "*.css" --include "*.js" --content-encoding gzip || { echo 'ERROR: s3 js/css sync failed' ; exit 1; }
aws s3 cp dist/${APP_NAME}/index.html s3://${APP_NAME}//index.html --metadata-directive REPLACE --cache-control max-age=0,no-cache,no-store,must-revalidate --content-type text/html --acl public-read || { echo 'ERROR: s3 cp index failed' ; exit 1; }
angular package.json
에서 deploy 스크립트를 수정하자.
...
"scripts": {
...
"!deploy": "-------- deploy to s3 -------------",
"predeploy": "npm run clean && npm run build",
"deploy": "./scripts/deploy.sh",
}
...
npm run deploy
스크립트를 실행하면, 자동으로 AWS S3에 gzip
인코딩 설정으로 올라간다. 참고로 AWS S3 CORS 설정도 변경해야할 수도 있다.
참고로 AWS CloudFront에 자동으로 압축하는 설정이 활성화 되어있었는데, 잘 동작하지 않은 것 같다.
4. 배포 및 테스트
위 스크립트로 배포 후 해당 사이트를 확인해보자.
아래 이미지와 같이 bundle 사이즈가 약 300KB정도로 줄어들었고, Fast 3G 환경에서 3~4초정도 걸린다.
main.js
파일의 헤더를 보면 content-encoding
이 gzip으로 설정된 것을 확인할 수 있다.