js 번들 분석 및 최적화하기
JS 번들의 영향도
- 첫 화면이 느리다(LCP↑), 초기 JS 다운로드가 크다
- 특정 페이지를 안 열어도 3D/에디터/그래프 같은 무거운 라이브러리가 항상 내려온다
- 라우트 이동 때마다 같은 라이브러리가 중복 로드된다
Next.js 번들 생성 특징 및 주의사항
- 기본은 서버 컴포넌트, 클라이언트 컴포넌트 하위는 전부 번들로 합쳐짐.
- 즉 클라이언트쪽에서 큰 라이브러리를 사용할 때 주의할 것.
- app router는 경로별로 별도 청크를 만듦.
- 동적 import를 사용하면 지연로딩 청크를 따로 생성함.
- Next/link 를 사용시 자동으로 프리패치됨으로 다음 페이지 청크를 미리 받아서 빠르게 로드가능.
설정코드
package.json
플러그인 실행하는 명령어 설정 @next/bundle-analyzer
{
"scripts": {
"analyze": "cross-env ANALYZE=true next build"
},
}
next.config.mjs
플러그인 세팅
import bundleAnalyzer from '@next/bundle-analyzer';
/** @type {import('next').NextConfig} */
const nextConfig = {
//... config 설정
};
// 번들 분석 플러그인
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === "true",
});
// Wrap MDX and Next.js config with each other
export default withBundleAnalyzer(nextConfig);
실제 적용코드
import dynamic from 'next/dynamic';
import type { RigidBody } from '@dimforge/rapier3d-compat'; // 무거운 3d타입만 적용시
// 무거운 위젯(차트/맵/에디터 등)
const HeavyChart = dynamic(() => import('./HeavyChart'), {
loading: () => <p>차트를 불러오는 중…</p>,
});
// ssr 제외 (브라우저 전용 라이브러리를 가져올 때)
const Map = dynamic(() => import('./Map'), { ssr: false });
// Suspense 를 통해서 무거운 내용만 따로 로딩
import { Suspense } from 'react';
import dynamic from 'next/dynamic';
const Heavy = dynamic(() => import('./Heavy'), { ssr: false });
export default function Page() {
return (
<>
<Hero /> {/* 가벼운 상단 */}
<Suspense fallback={<Skeleton />}>
<Heavy /> {/* 아래쪽은 늦게 */}
</Suspense>
</>
);
}
예시
아래 화면은 next/bundle-analyzer로 분석한 번들의 크기이다. 아래 코드를 보면 rapier.es.js 코드가 크게 2개가 있다. 이 경우에서 보면 @react-three/drei와 @react-three/rapier에서 각각 다른 버전의 모듈을 참고하면서 두개의 번들을 가져오면서 발생한 일이다.
npm ls @dimforge/rapier3d-compat
koosang-vidoe-story@ C:\work\cursor\koosang-vidoe-story
├─┬ @react-three/drei@9.122.0
│ └─┬ maath@0.10.8
│ └─┬ @types/three@0.176.0
│ └── @dimforge/rapier3d-compat@0.12.0
└─┬ @react-three/rapier@1.5.0
└── @dimforge/rapier3d-compat@0.14.0
해결하기 위해서는 우선 두 모듈이 서로 호환되는지 확인해야한다. @dimforge/rapier3d-compat@0.12.0 와 0.14.0 은 호환되는 타입인 것을 확인하고, packege.json에 합산 코드를 넣고 package-lock.json 삭제 후 재설치 하면 0.14.0 버전으로 합산된다. // package.json
{
"scripts":{...},
"overrides": {
"@dimforge/rapier3d-compat": "0.14.0"
},
"dependencies":{...}