빌드하는 중에 이런 경고 메시지가 떴다.
이 경고는 빌드 프로세스 중에 몇몇 청크(코드 묶음)가 최소화된 후에도 여전히 500kB를 초과한다는 것을 알리는 메시지라고 한다.
큰 프로젝트도 아닌데 빌드 시간이 11.66s ... ... .
어떤 것이 문제인지 확인하기 위해 rollup-plugin-visualizer
로 번들의 크기를 시각적으로 확인해 보았다.
아까 문제가 되었던 index.js에서는 firebase가 많은 부분을 차지하고 있고, EventDetail.js에서는 refractor가 많은 부분을 차지하고 있는 것을 알 수 있다.
firebase 라이브러리가 상당히 큰 공간을 차지하고 있는 것을 알 수 있다.
그래서 검색해 봤는데 firebase 공식 문서에서 제안한 방법들은 나는 vite를 사용하고 있기 때문에 이미 적용이 되고 있었다…….
// before
import { doc, getDoc, setDoc, updateDoc } from 'firebase/firestore';
// after
import { doc, getDoc, setDoc, updateDoc } from 'firebase/firestore/lite';
일단 실시간 업데이트가 필요하지 않은 서비스는 firestore/lite
를 사용하면 번들 사이즈를 좀 줄일 수 있다고 하여 해당 코드를 수정하였다.
dist/assets/index-D1u2acml.js 746.35 kB │ gzip: 205.89 kB
dist/assets/EventDetail-BHVjT0o1.js 1,050.32 kB │ gzip: 362.96 kB
✓ built in 7.04s
index.js가 처음 빌드 시에
935.29 kB
였던 것이746.35 kB
가 되었다.
built 시간이11.66s
에서7.04s
가 되었다.어느 정도 성공!
동적 import를 이용한 코드 스플리팅
터미널 메시지에서 제안해 준 방법대로 Using dynamic import() to code-split the application
를 적용해 보았다.
동적 import로 수정한 컴포넌트의 기준은 사용자가 특정 동작을 수행할 때만 필요할 수 있는 컴포넌트이다.
예를 들어 Main.tsx에서는 사용자가 필터 버튼을 눌렀을 때만 보여지는 컴포넌트인 ModalCategory와 ModalPrice, 그리고 에러가 났을 때만 보여지는 컴포넌트인 ErrorBox를 동적 import로 수정했다.
const ErrorBox = lazy(() => import('@shared/ErrorBox'));
const ModalCategory = lazy(() => import('@components/main/ModalCategory'));
const ModalPrice = lazy(() => import('@components/main/ModalPrice'));
dist/assets/index-AaaZZaCI.js 739.39 kB │ gzip: 203.56 kB
dist/assets/EventDetail-jb-Hc4l9.js 1,050.70 kB │ gzip: 363.12 kB
✓ built in 7.27s
index.js가
746.35 kB
였던 것이739.39 kB
가 되었다.
built 시간이7.04s
에서7.27s
가 되었다......................... 약간 실패.
Rollup의 manualChunks 옵션을 사용하여 청크를 수동으로 분할하는 방법을 적용
빌드 오류에서 제안해 준 방법대로 Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
를 적용해 보았다.
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom', 'react-router-dom'],
firebase: [
'firebase/app',
'firebase/auth',
'firebase/firestore',
'firebase/storage',
'firebase/analytics',
],
ui: [
'@radix-ui/react-alert-dialog',
'@radix-ui/react-avatar',
'@radix-ui/react-checkbox',
'@radix-ui/react-dropdown-menu',
'@radix-ui/react-label',
'@radix-ui/react-popover',
'@radix-ui/react-radio-group',
'@radix-ui/react-select',
'@radix-ui/react-slot',
'@radix-ui/react-tooltip',
],
syntaxHighlight: ['refractor'],
},
},
},
},
// ... 생략
});
dist/assets/index-C8WAEFox.js 280.67 kB │ gzip: 78.15 kB
dist/assets/EventDetail-B6b9m9S7.js 937.60 kB │ gzip: 323.21 kB
✓ built in 7.62s
index.js가
739.39 kB
였던 것이280.67 kB
가 되었다.
EventDetail.js도1,050.70 kB
였던 것이937.60 kB
가 되었다.
built 시간이7.27s
에서7.62s
가 되었다.성공.
하지만 아직도 EventDetail은 개선이 필요하다. 별도의 청크로 분리를 시도하였으나 의도와는 다르게 refractor가 여전히 초기 로딩 시 로드되고 있는 중이다.
라이브러리 교체를 통한 번들 최적화
ChatGPT에 물어보니 다른 라이브러리(@uiw/react-md-editor
)에서 내부적으로 refractor
를 사용하고 있기 때문에 여전히 번들 크기에 영향을 미치고 있다는 것 같았다.
그래서 나는 refractor를 사용하지 않고 훨씬 더 가벼운 react-markdown
로 라이브러리를 대체하였다.
dist/assets/index-Cb2yEKZa.js 280.60 kB │ gzip: 78.10 kB
dist/assets/EventDetail-BT16ARb2.js 122.06 kB │ gzip: 38.05 kB
✓ built in 6.15s
index.js가
280.67 kB
였던 것이280.60 kB
가 되었다.
EventDetail.js도937.60 kB
였던 것이122.06 kB
가 되었다.
built 시간이7.62s
에서6.15s
가 되었다.성공.
최종적으로는 웹 애플리케이션의 빌드 시간을 기존 11.66초에서 6.15초로 단축, 47% 개선을 달성하였다!
사용자 경험 향상과 서버 리소스 효율성 증가에 기여하게 된 것이다.