최근에 회사에서 해외 서비스를 도입한다고 해서 사이트의 성능을 검사해 보았는데, 아래와 같이 페이지의 번들 크기가 예상보다 커진 것을 발견했다.
Route: 동적 라우트를 포함한 페이지의 경로
Size: 클라이언트 브라우저에서 페이지에 접근할 때 필요한 자바스크립트 번들의 크기
First Load JS: 각 페이지마다 필요한 자바스크립트 번들 크기 + 앱 전반에 사용되는 공용 코드, 프레임워크 코드, 웹팩 코드, CSS 등의 크기
각각의 청크 파일은 다음과 같은 역할을 합니다
chunks/framework-*: 프레임워크와 관련된 파일 (예: react-dom 및 react)
chunks/main-*: Next.js와 관련된 기능 (예: next/dist - 라우터 포함)
chunks/page/_app-*: _app 페이지와 관련된 파일
chunks/webpack-*: 웹팩 스크립트 코드 (build-manifest.json을 통해 페이지 이동 시 필요한 JS 로드)
npm run build를 실행하면 생성되는 .next 디렉토리를 살펴보았다.
chunks 폴더 안에는 페이지별 청크 파일이 있으며, Next.js가 기본적으로 페이지 단위로 코드 스플리팅을 하기 때문에 이것을 확인할 수 있었다.
.next/server: 각 페이지를 pre-render할 때 사용되며, 완성된 HTML과 .next/static/chunks 파일을 통해 하이드레이션된다.
.next/static/chunks: 페이지 간 이동 시 필요한 청크 파일이 저장된다.
.next/build-manifest.json 파일을 확인하면 각 페이지에 대한 청크가 정의되어 있는데, Next.js는 이를 기반으로 페이지에 맞는 청크를 제공한다.
사용하지 않는 라이브러리는 초기 번들링에 포함되지 않지만, 추후 앱 라우터 마이그레이션을 위해 정리하기로 했다.
npm install --save-dev @next/bundle-analyzer cross-env
yarn add -D @next/bundle-analyzer cross-env
next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')()
module.exports = withBundleAnalyzer(configs)
npm run build를 실행하면 자동으로 client.html 파일이 열리며, 번들 파일을 분석할 수 있습니다. 거기서 사용하지 않는 사이즈가 큰 라이브러리를 제거 했다.
_app.js는 서버로 요청이 들어왔을 때 가장 먼저 실행되는 공통 컴포넌트이므로 최적화를 하기로 했다.
크기가 큰 라이브러리를 _app.js에서 import했는데, 해당 라이브러리를 사용하는 공용 컴포넌트로 이동했다.
다른 블로그에서는 첫 로딩에 필요 없는 모달이나 토스트와 같이 상호작용 이후에 나오는 컴포넌트를 동적 임포트를 하던데 적용하기에는 컴포넌트가 무겁지 않아서 크기 감소가 미미하고 사용자 경험에 부정적인 영향을 줄 수 있을 거 같아서 적용하지 않았다. 나중에 첫 로딩에 필요 없고 무거운 코드, 라이브러리를 사용한다면 동적 임포트를 사용하면 좋을 듯하다.
_app.js를 최적화한 결과, 모든 페이지에 대한 JS 번들 크기가 13% 감소했다.
또한 일반적인 네트워크 상황에서는 크게 차이가 나지 않았지만 네트워크를 fast 3G를 했을 때 1초 정도 차이가 났다. 그렇다면 한국 유저는 체감할 수 없지만 해외 유저면 의미가 있는 최적화인듯하다.
개발서버에서 라이트 하우스도 확인을 해봤다.
비교군 서버1 : _app.js 최적화 전
비교군 서버2 : _app.js 최적화 전
서버3: _app.js 최적화 후