manualChunks 옵션 설정하여 빌드파일 크기 줄이기 (+lazy loading)
블로그 프론트엔드를 드디어 배포해보려고 빌드했더니 이런 경고문이 떴다.
js 파일 사이즈가 커서 나타난 경고문으로 해결 방법도 함께 표시해주고 있다. 여담이지만 프론트엔드 최적화가 중요하다고 말만 많이 들었지 체감을 할 수 있는 경험이 없었는데 직접 배포를 시도하니 자연스럽게 알게 되고 하게 되어서 좋다.
일단 참고한 블로그 글은 이곳이고, lazy loading, dynamic import, manualChunks 옵션 설정의 세 가지 방법 중 manualChunks 옵션으로 처리하는 게 지금 상황에서 가장 효과적일 것으로 생각해 시도해보았다.
크기가 큰 react-icons를 별도로, 그리고 react 관련된 모듈을 묶어주었다. 다시 빌드해 보니 지정한 옵션에 따라 잘 나뉘어지는 건 확인했지만 여전히 500kb 초과한다.
export default defineConfig({
...
build: {
rollupOptions: {
output: {
manualChunks(id: string) {
if (id.includes('react-icons')) {
return '@icon-vender'
}
if (id.includes("node_modules/react/") || id.includes("node_modules/react-dom/")) {
return "@react-vendor";
}
}
}
}
}
});
크기를 어떻게 확인하면 좋을까 생각하다가 로컬에서 열어서 네트워크 탭을 봤다.
크기 기준으로 보면 아래와 같은데, 위지윅 에디터 라이브러리인 react-quill이랑 TOC 해시 링크에서 사용한 rehype가 꽤나 컸다. 폰트도 CDN으로 안 넣고 같이 말아서 빌드했는데 꽤 크고. 일단 react-quill은 어차피 내가 글 작성할 때 사용할 거니 굳이 처음에 서빙할 필요가 없다. 그렇게 생각하니 블로그에 접근하는 유저가 보는 페이지와 나만 접근할 페이지를 기준으로 나누면 좋겠다고 생각했다.
로딩시간 기준으로 보면 아래와 같은데, TOC에 사용하는 rehype와 github-slugger를 나누면 좋겠다고 생각했다.
결과는 요렇게 됐다.
export default defineConfig({
...
build: {
rollupOptions: {
output: {
manualChunks(id: string) {
if (id.includes("axios")) {
return "@networking-vendor";
}
if (
id.includes("node_modules/react/") ||
id.includes("node_modules/react-dom/")
) {
return "@react-vendor";
}
if (id.includes("react-icons")) {
return "@icon-vender";
}
if (id.includes("react-quill")) {
return "@editor-vendor";
}
if (id.includes("rehype") || id.includes("github-slugger")) {
return "@toc-vendor";
}
},
},
},
},
});
그렇게 다 된 줄 알았는데 빌드한 걸 S3 버킷에 넣어 url로 접근해보니 에러가 떴다.
manualChunks 설정 부분을 주석처리하고 한꺼번에 빌드했더니 문제 없이 잘 동작했다. chunk를 분리하다 보니 react-quill 라이브러리 의존성 문제가 생긴 모양이다.
gpt한테 물어보니 Vite 설정에서 optimizeDeps에 react-quill 라이브러리를 등록해주면 의존성 문제를 완화할 수 있다고 하여 적용해봤는데 잘 동작하지 않았다. 그래서 manualChunks 옵션 설정으로 직접 chunk 분리하지 않고 react-quill 라이브러리를 lazy loading 으로 처리해서 chunk 분리를 Vite한테 맡겼다. 아래는 그 결과물.
그리고 잘 동작한다!
테스트한다고 계속 빌드하고 S3에 기존 객체 삭제하고 다시 업로드하고를 반복하다보니 CI/CD가 왜 필요한지 느낄 수 있었다. 매우 귀찮다!! 삭제 후 업로드 aws api 쏘는 걸로 만들어서 그냥 deploy 명령어로 처리하고 싶다. 이번에 배포하면서 그냥 같이 해봐버려야겠다.