Picovert

JavaScript 번들 크기 최적화: 500 KB에서 80 KB로

2026-04-248분 분량

JavaScript는 웹에서 가장 비싼 리소스입니다 — 바이트당 JavaScript 파일은 동일한 크기의 이미지보다 비용이 많이 드는데, 디코딩만 하면 되는 게 아니라 파싱과 실행이 필요하기 때문입니다. 500KB JavaScript 번들은 중급 폰에서 메인 스레드를 2~4초 동안 차단할 수 있습니다. 100KB 미만으로 줄이는 방법을 알아봅니다.

1단계: 현재 상태 측정

최적화 전에 현재 번들을 감사하세요. npx @next/bundle-analyzer를 실행하세요.next.config.js에서 ANALYZE=true npm run build로 활성화합니다. 트리맵은 어떤 패키지가 가장 크고, 어떤 페이지가 어떤 모듈을 포함하는지 보여줍니다.

2단계: 사용하지 않는 의존성 제거

가장 흔한 번들 비대화 소스:

패키지크기대체대체 크기
moment.js67 KBdate-fns (트리쉐이킹)3–8 KB
lodash72 KBlodash-es (트리쉐이킹)1–5 KB
axios14 KBfetch (네이티브)0 KB
react-icons (전체)340 KB개별 SVG 임포트0.5 KB/아이콘

3단계: 트리쉐이킹

트리쉐이킹은 한 번도 임포트되지 않은 익스포트를 제거합니다. 작동하려면:

  • 배럴 파일에서 기본 임포트 대신 이름 임포트를 사용하세요. import { format } from 'date-fns'는 트리쉐이킹됩니다; import dateFns from 'date-fns'는 안 됩니다.
  • 유틸리티 모듈에서 사이드 이펙트 임포트를 피하세요. 상단에 import 'some-polyfill'이 있는 파일은 사이드 이펙트가 있다고 처리되어 트리쉐이킹되지 않습니다.
  • 라이브러리의 package.json에서 sideEffects: false를 확인하세요. 이를 선언하지 않은 라이브러리는 Webpack/Turbopack의 트리쉐이킹에서 제외됩니다.

4단계: 코드 스플리팅

Next.js는 페이지 수준에서 자동으로 코드를 분리합니다. 서브 페이지 분리에는 동적 임포트를 사용하세요:

const HeavyEditor = dynamic(() => import('./Editor'), { loading: () => <Spinner /> });

동적 임포트 좋은 후보: 리치 텍스트 에디터, 차트 라이브러리, PDF 뷰어, 지도 컴포넌트, 비디오 플레이어, 탭이나 모달 뒤에 있어 초기 로드 시 보이지 않는 컴포넌트.

5단계: 서드파티 스크립트 최적화

Next.js의 <Script> 컴포넌트를 서드파티 스크립트에 사용하세요:

  • strategy="lazyOnload" — 다른 모든 것 이후에 로드, INP에 영향 없음.
  • strategy="afterInteractive" — 하이드레이션 후 로드, 대부분의 분석에 적합.
  • strategy="worker" — Web Worker에서 로드(실험적), 메인 스레드에서 완전히 분리.

전후 비교: 실제 수치

지표이전이후
홈페이지 JS (gzipped)520 KB82 KB
메인 스레드 차단 시간3.2초0.4초
INP (75번째 백분위수)480 ms95 ms
Lighthouse 성능6194

변경 사항: moment.js를 date-fns로, lodash를 네이티브 JS로 교체하고, 데이터 테이블을 서버 컴포넌트로 이동하고, 분석 스크립트를 지연 로드했습니다.