블로그를 개발하는 것에 몰두한 나머지 번들 사이즈에 대해서는 신경을 쓰지 못했습니다. 그래서 번들 크기가 굉장히 커졌고, 네트워크 요청에도 꽤 시간이 걸렸습니다.
저는 이전 포스팅에서 알아본 Lazy Loading을 도입해서 최적화를 해보려고 합니다.
번들 사이즈를 측정해보자
먼저 번들을 최적화하기 위해서는, 현재 번들 사이즈가 얼마나 되는지 알아야겠죠? NextJS에서 Bundle Analyzer plugin을 제공합니다.
이를 사용해서 측정하니 4가지의 정보를 파악할 수 있었습니다.
위 표에는 언급되지 않은 edge.html도 생성되나, 특별히 Edge Functions을 사용하지 않기 때문에 분석된 결과가 표시되지 않아 제외했습니다.
client.html
: 브라우저에서 실행되는 클라이언트 사이드 번들의 분석 결과(브라우저에서 동적으로 로드되는 추가 자원들(예: JavaScript 파일)의 크기와 구성을 의미)nodejs.html
: 서버 사이드에서 실행되는 번들의 분석 결과edge.html
: Edge Functions에 대한 번들의 분석 결과(Edge Functions의 코드 크기와 구성을 의미)
번들 사이즈를 줄여보자
컴포넌트에 지연 로딩을 적용
상호작용 이후에 화면에 보여지는 컴포넌트에 우선적으로 지연로딩을 적용했습니다. 이미지 첨부 후 보여지는 로딩 스피너, 링크를 복사하거나 포스트를 삭제할 때 보여지는 토스트와 모달 컴포넌트 등이 이에 해당되었습니다.
이 외에 현재 블로그의 메인 페이지에 진입하면 포스트 목록을 10개 단위로 가져와서 보여주고 있습니다. 이 곳에 사용되는 포스트 아이템(PostSideCard
)도 지연 로딩을 적용했습니다.
일부 route에서 미세하게 사이즈가 커졌지만, 대체적으로 상당히 많은 양이 줄어들었습니다.
/blog/[slug]
: 약 40% 감소 (257kB → 152kB)/write
: 약 65% 감소 (510kB → 182kB) 그리고 사용하지 않는 route(/write/[id]
)는 제거했습니다.
그런데 사실 지연로딩은 전체적인 번들 사이즈를 줄여주지는 않습니다.(여기서 줄인다는 것은 감소한다는 의미 e.g. 500kB -> 300kB) 초기 로드에 필요한 JS 코드의 양을 줄여주는 것이죠. 그런 의미에서 전체 번들 사이즈를 줄이려면, 앞서 위에서 살펴봤던 client.html
, nodejs.html
에서 용량이 큰 라이브러리 등을 파악해서 이를 대체하는 것이 하나의 방법이 될 수 있습니다.
용량이 큰 패키지 변경하기
지연 로딩을 적용한 후에도 위 이미지에서 더 이상 First Load JS를 줄일 수 없었습니다. 자세히 살펴보니 사용하고 있는 라이브러리 때문이었습니다. 저는 UI 라이브러리로 nextui를 사용하고 있고, 에디터 기능이 필수이기 때문에 ToastUIEditor를 사용하고 있습니다. 제 경우에는 이 두 라이브러리가 가장 큰 용량을 차지하고 있었네요. UI 라이브러리(nextui) 를 잠깐 살펴보자면, 단 3개만 import 해오는 데도 불구하고 용량이 75.2k(gzipped: 23.5k) 입니다.
에디터 라이브러리는 gzipped여도 269.5k 니다. 여기에 플러그인과 각종 css를 합치면 적어도 300k는 차지하고 있습니다.
라이브러리 간의 크기를 한 번 비교해봤습니다.
기존 라이브러리의 크기가 보이시나요? 상대적으로 가벼운 라이브러리로 대체할 필요성이 보입니다. 무거웠던 라이브러리를 모두 교체해보았습니다.
- NextUI → shadcn
- NextUI는 사용하지 않는 컴포넌트들도 일단 모두 설치를 하는 방식입니다. 그렇기에 요구하는 용량도 큽니다. (사용을 원하는 컴포넌트만 설치하는 방식이 있으나, 번거롭고 까다롭습니다.)
- 이와 다르게 shadcn은 사용하고자 하는 컴포넌트만 설치해서 사용하기에 상대적으로 요구 용량이 매우 적습니다.
- ToastUIEditor → MDXEditor
에디터 변경
에디터를 변경함에 있어서 아래 4가지 기능을 제공하는지가 선택의 기준이었습니다.
- 마크다운
- 이미지 드래그 앤 드롭
- 실시간 뷰어
- 상대적으로 작은 라이브러리 크기
이를 토대로 3가지의 후보로 추려졌습니다.
- react-quill
- prose-mirror
- MDXEditor
react-quill
은 찾아보니 Markdown을 기본적으로 제공하지는 않고 플러그인을 따로 설치해야 했습니다. quilljs-markdown이라는 별도의 플러그인을 사용할 수 있으나 Unpacked Size가 279로 너무 컸습니다. 그리고 react-quill 자체도 403kB 입니다. 그리고 이미지 드래그 앤 드롭도 플러그인 설치로 사용해야 했습니다. 뷰어는 깊게 찾아보지는 않았으나 따로 제공하지 않는 것 같았습니다. 그리고 무엇보다도 유지보수가 2년전이 마지막이어서 사용하기가 꺼려졌습니다.
prose-mirror
는 이전에 한 번 들어본 적이 있었습니다. 굉장히 높은 자유도를 제공하지만 반대로 내가 원하는 기능을 스스로 구현해야 한다는 문제가 있었습니다. 에디터를 만드려는 목적이 아니었고 직접 구현하기에는 시간이 많이 소요된다는 점에서 선택하지 않았습니다.
MDXEditor
는 처음 접해봤는데, 공식문서과 꽤 잘 정리되어 있었습니다. NextJS App router에 대한 내용도 따로 제공을 하며, 플러그인을 별도로 설치받을 필요 없이 자체적으로 내장되어 있기 때문에 단순히 import로 사용할 수 있었습니다. 그리고 유지보수도 꽤 활발히 진행중임을 볼 수 있었습니다. (4.25일 기준 3일 전 업데이트) 하지만, 실시간 뷰어를 제공하지 않고 라이브러리의 크기가 컸습니다. Unpacked Size 기준으로 503kB입니다. 기존 라이브러리에 비해서는 굉장히 작았는데 약간 아쉬웠습니다. react-quill은 405kB으로 MDXEditor가 약 100kB정도 높기는 하지만 공식문서의 예제를 보고 괜찮을 것 같다고 판단했습니다.
최적화 후 번들 사이즈
기존의 최근 작성 포스트, 다시보기 포스트를 가져오기 위해 parallel route(/blog
)로 처리하는 부분을 모두 제거했습니다. 또한, 이 때문에 루트 페이지를 blog
로 바꿨던 이슈를 /
로 되돌릴 수 있었습니다. 결론적으로 /
는 약 6kB정도 증가했으나 /write
는 510kB → 122kB(77%) 로 줄였습니다.