이어서 추가로 서버비 절감 프로젝트를 시작한다
참고 자료 : https://ko.legacy.reactjs.org/docs/code-splitting.html
번들러는 다음과 같이 정의한다.
bundler : 각각의 모듈들에 대해 의존성 관계를 파악하여 하나 또는 여러개의 그룹으로 묶어주는 웹 개발 도구
이때 코드가 너무 방대하다면 다시 코드를 작은 덩어리로 나눠주게 되는데(코드 스플리팅),
나눠진 코드 조각을 chunk 라고 부른다.
꽤 오래전부터 빌드할때 뜨는 경고창이 있었다.
yarn run v1.22.19
$ vite build
vite v4.5.3 building for production...
✓ 4256 modules transformed.
dist/index.html 6.41 kB │ gzip: 4.13 kB
dist/assets/index-dea6fe59.css 60.62 kB │ gzip: 11.62 kB
dist/assets/index-483f2744.js 1,832.64 kB │ gzip: 514.76 kB
✓ built in 12.46s
Done in 12.89s.
(!) Some chunks are larger than 500 kB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
사실 여태까지는 대수롭지 않게 여겼다. 서버비가 많이 나오기 전까지는.
줄이면 좋다는 것을 어느 정도 알고 있었지만, 돈이 나가기 전까지는 깊게 생각하지 않았다.
번들 사이즈를 줄이는 방법은
정도가 대표적이라고 할 수 있고,
1번은 계속해서 리팩토링 해야 할 일이니,
이번에는 2,3번에 대해서 직접 실행 해보았다.
import { defineConfig } from 'vite';
import path from 'path';
import react from '@vitejs/plugin-react-swc';
import envCompatiblePlugin from 'vite-plugin-env-compatible';
import { visualizer } from 'rollup-plugin-visualizer'; // 번들러 사이즈 관찰을 위해 설치
export default defineConfig({
plugins: [
react(),
envCompatiblePlugin(/* options */),
// visualizer를 plugin에 등록한다. 빌드 시 번들 사이즈를 시각화하여 볼 수 있다.
visualizer({
filename: './dist/report.html',
open: true,
brotliSize: true,
}),
],
... // other configure
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
},
},
},
},
});
위와 같이 작업하여 node_modules에 설치된 패키지들을 패키지별로 분할하여 chunk를 생성하도록 vite.config.ts에 선언해준다.
Todo
또, visualizer를 통해 관찰된 "불필요하게 사이즈가 큰 패키지"들에 대해서, 사용하는 메소드만 선택적으로 가져오도록 선언해준다.
=> 이 부분은 별도 포스팅으로 추가로 다룰 예정이다.
$ yarn build
yarn run v1.22.19
$ vite build
vite v4.5.3 building for production...
✓ 3922 modules transformed.
Generated an empty chunk: "compute-scroll-into-view".
Generated an empty chunk: "copy-anything".
Generated an empty chunk: "copy-to-clipboard".
Generated an empty chunk: "is-what".
Generated an empty chunk: "json2mq".
Generated an empty chunk: "scroll-into-view-if-needed".
Generated an empty chunk: "string-convert".
Generated an empty chunk: "superjson".
Generated an empty chunk: "toggle-selection".
dist/index.html 10.40 kB │ gzip: 4.98 kB
dist/assets/index-cfe559f4.css 60.93 kB │ gzip: 11.67 kB
dist/assets/compute-scroll-into-view-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/copy-anything-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/copy-to-clipboard-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/json2mq-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/is-what-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/toggle-selection-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/string-convert-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/superjson-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/scroll-into-view-if-needed-4ed993c7.js 0.00 kB │ gzip: 0.02 kB
dist/assets/rc-input-c9c0d1f2.js 0.06 kB │ gzip: 0.07 kB
dist/assets/rc-steps-cdf18210.js 0.06 kB │ gzip: 0.07 kB
dist/assets/rc-rate-cdf18210.js 0.06 kB │ gzip: 0.07 kB
dist/assets/rc-checkbox-c9c0d1f2.js 0.06 kB │ gzip: 0.07 kB
dist/assets/rc-input-number-36eb93c1.js 0.09 kB │ gzip: 0.09 kB
dist/assets/rc-slider-164b3e53.js 0.09 kB │ gzip: 0.09 kB
dist/assets/rc-upload-87d64903.js 0.09 kB │ gzip: 0.09 kB
dist/assets/rc-collapse-8cbe26ec.js 0.12 kB │ gzip: 0.10 kB
dist/assets/rc-textarea-b6f5b20e.js 0.13 kB │ gzip: 0.11 kB
dist/assets/rc-image-6c9dd886.js 0.16 kB │ gzip: 0.11 kB
dist/assets/rc-drawer-624c7ee1.js 0.16 kB │ gzip: 0.12 kB
dist/assets/rc-dialog-624c7ee1.js 0.16 kB │ gzip: 0.12 kB
dist/assets/rc-table-3ed2968e.js 0.17 kB │ gzip: 0.13 kB
dist/assets/rc-virtual-list-d546dc47.js 0.17 kB │ gzip: 0.13 kB
dist/assets/rc-dropdown-61585954.js 0.20 kB │ gzip: 0.14 kB
dist/assets/rc-tree-951aa4f8.js 0.20 kB │ gzip: 0.14 kB
dist/assets/rc-cascader-b9d1b656.js 0.23 kB │ gzip: 0.15 kB
dist/assets/rc-menu-b9d1b656.js 0.23 kB │ gzip: 0.15 kB
dist/assets/rc-mentions-eb07dfb2.js 0.23 kB │ gzip: 0.15 kB
dist/assets/rc-select-a2a35932.js 0.23 kB │ gzip: 0.15 kB
dist/assets/rc-tree-select-b9d1b656.js 0.23 kB │ gzip: 0.15 kB
dist/assets/rc-tabs-dd4d2533.js 0.23 kB │ gzip: 0.15 kB
dist/assets/rc-pagination-38277765.js 0.36 kB │ gzip: 0.22 kB
dist/assets/clsx-0839fdbe.js 0.37 kB │ gzip: 0.24 kB
dist/assets/invariant-67bf807c.js 0.42 kB │ gzip: 0.31 kB
dist/assets/tslib-ce936417.js 0.44 kB │ gzip: 0.27 kB
dist/assets/shallowequal-31ea27cd.js 0.49 kB │ gzip: 0.31 kB
dist/assets/throttle-debounce-87e7e444.js 0.69 kB │ gzip: 0.40 kB
dist/assets/recoil-persist-9bf66054.js 0.93 kB │ gzip: 0.51 kB
dist/assets/classnames-c55f02e3.js 0.97 kB │ gzip: 0.56 kB
dist/assets/use-sync-external-store-09cfcca6.js 1.08 kB │ gzip: 0.60 kB
dist/assets/rc-switch-3602da0f.js 1.30 kB │ gzip: 0.66 kB
dist/assets/react-fast-compare-b02d41ca.js 1.81 kB │ gzip: 0.71 kB
dist/assets/react-loader-spinner-0a2e821b.js 2.59 kB │ gzip: 1.09 kB
dist/assets/rc-resize-observer-b412bb70.js 2.61 kB │ gzip: 1.25 kB
dist/assets/file-saver-54522f38.js 2.62 kB │ gzip: 1.26 kB
dist/assets/rc-tooltip-646b3502.js 2.88 kB │ gzip: 1.17 kB
dist/assets/rc-segmented-95467756.js 3.99 kB │ gzip: 1.66 kB
dist/assets/scheduler-765c72db.js 4.10 kB │ gzip: 1.78 kB
dist/assets/rc-progress-2e23a9f3.js 4.30 kB │ gzip: 2.03 kB
dist/assets/@emotion-8b85da0a.js 4.96 kB │ gzip: 2.37 kB
dist/assets/rc-overflow-804a6b07.js 5.44 kB │ gzip: 2.45 kB
dist/assets/react-router-dom-0c3dd056.js 7.38 kB │ gzip: 3.00 kB
dist/assets/resize-observer-polyfill-0f9f8adb.js 7.71 kB │ gzip: 2.54 kB
dist/assets/react-42d7b083.js 8.05 kB │ gzip: 3.06 kB
dist/assets/react-router-fe5135a6.js 8.15 kB │ gzip: 3.09 kB
dist/assets/rc-notification-65c0b49a.js 8.15 kB │ gzip: 3.40 kB
dist/assets/rc-motion-55c49273.js 8.91 kB │ gzip: 3.74 kB
dist/assets/react-helmet-async-462eba5a.js 12.07 kB │ gzip: 4.77 kB
dist/assets/@babel-e5c87543.js 12.47 kB │ gzip: 4.42 kB
dist/assets/@ctrl-fb5a5473.js 14.15 kB │ gzip: 4.72 kB
dist/assets/dayjs-c192c059.js 14.86 kB │ gzip: 5.73 kB
dist/assets/qrcode.react-b4b4d2cb.js 15.27 kB │ gzip: 5.74 kB
dist/assets/rc-util-a44f8968.js 19.11 kB │ gzip: 8.46 kB
dist/assets/react-responsive-d6a1a643.js 22.20 kB │ gzip: 7.53 kB
dist/assets/rc-field-form-a3e964be.js 32.31 kB │ gzip: 10.50 kB
dist/assets/axios-4fa4cdbc.js 34.39 kB │ gzip: 13.72 kB
dist/assets/@tanstack-9f63f290.js 35.74 kB │ gzip: 10.05 kB
dist/assets/@rc-component-67c515b2.js 36.32 kB │ gzip: 13.04 kB
dist/assets/@remix-run-fe056399.js 42.78 kB │ gzip: 15.18 kB
dist/assets/@ant-design-44b87355.js 43.05 kB │ gzip: 15.60 kB
dist/assets/rc-picker-1d63f1b3.js 68.03 kB │ gzip: 23.00 kB
dist/assets/lodash-es-cb22525a.js 87.23 kB │ gzip: 31.40 kB
dist/assets/recoil-9f9567b6.js 109.48 kB │ gzip: 29.29 kB
dist/assets/react-dom-77c34da7.js 130.27 kB │ gzip: 41.87 kB
dist/assets/styled-components-d2dad46c.js 158.71 kB │ gzip: 14.28 kB
dist/assets/antd-c476874b.js 173.76 kB │ gzip: 47.06 kB
dist/assets/html2canvas-85f1a6b6.js 201.43 kB │ gzip: 47.71 kB
dist/assets/index-89d935ad.js 419.87 kB │ gzip: 113.02 kB
✓ built in 13.29s
Done in 15.00s.
이렇게 해서 특정 코드를 읽기 위해서 모든 js파일을 로딩할 필요 없이, 필요한 js파일만 로딩함으로써 성능 향상을 기대할 수 있다.
=> 이제 더이상 chunk size 경고가 뜨지 않는다.
나는 분명 HTTP헤더에도 cache-control을 설정했고,
최근에 CloudFront의 function에서도 cache-control을 설정했다.
안 익숙해서 제대로 사용 못하던 AWS를 여기저기 돌아보다가 다음과 같은 분석 자료를 발견했다.

진짜 대수롭게 여기지 않았었는데, 누락된 바이트.. 뭔가 신경쓰인다

=> 이건 뭔가 잘못된 게 분명하다
이렇게 되면 모든 사람이 페이지에 매번 접속할때마다 모든 데이터에 대한 요청을 보내서 요청 당 비용도 과금이 되고,
Data Transfer에 의한 비용도 과금이 되는 것 아닌가?

이걸 비활성화 해놨던 것 같다.
원래 S3 버킷만으로 정적 웹사이트 호스팅을 하게 되면 문제가 발생한다는 이유로 비활성화 했던 것 같은데,
S3 버킷만으로 호스팅 할 경우 문제점
- https가 아닌 http 통신을 해야 함
- 버킷이 퍼블릭 공개됨
- AWS S3의 엔드포인트 주소를 그대로 사용해야 함
이 문제를 해결하려고 이미 CloudFront 로 CDN 서비스를 이용하고 있는 내가
굳이굳이 비활성화 해뒀던 설정이다.
주의 : 사실 이 부분이 잘 기억이 안난다. 무수히 많은 트러블슈팅 과정에서 고친 항목 중 하나인데, 아무래도 이게 원인이 아니었을가 하는 내 추정일 수도 있다
=> 드디어 찾았다
Cloudfront > 배포 > [내 그룹] > 편집 으로 가면
이런 설정을 할 수 있다.
처음 설정할때는 대수롭지 않게 넘어갈 수도 있는 부분이라 찾아볼 생각조차도 하지 못했다.
★★Cloudfront의 캐시 정책을 비활성화 해놓은건 아닌지 반드시 확인하자★★




그러니까, 이 모든 게 전부 다..

이렇게 과금되고 있었던 것이다.
대략 평균 130GB에서 37GB로 감소했으니 데이터 전송비용만 거의 3.5배를 더 내고 있었던 것이다.
놀랍게도 1100 달러까지 올라가고 있었던 이번 달 서버비가..
860달러까지 감소했다.
불과 며칠 안 남은 이번 달에 대한 과금 예상액이 저정도 감소했다는 건..
다음 달은 기대 해봐도 좋은 걸까?
AWS Billing Manager를 통해 다음 달에 이 작업에 대한 최종 포스팅을 정리하도록 하겠다.
아 그리고 하나 더.
냥 지나갔던 "패키지에서 필요한 기능만 선택적으로 호출하기" 관련 포스팅부터 이어가도록 하자.
그럼 이만.
