반응형

웹 앱을 개발하다 보면 프로젝트가 커질수록 페이지 로딩 속도가 느려지고, 사용자가 필요하지 않은 코드까지 한 번에 내려받는 문제가 생깁니다.


Next.js에서는 이런 문제를 해결하기 위해 코드 스플리팅(Code Splitting)을 제공합니다. 이번 글에서는 Next.js에서 코드 스플리팅이 무엇인지, 어떻게 활용하는지, 그리고 면접에서 활용할 수 있는 포인트까지 알아보겠습니다.

 


1️⃣ 코드 스플리팅이란?

코드 스플리팅은 애플리케이션을 작은 청크(chunk) 단위로 나누어, 사용자가 실제로 필요할 때만 해당 코드를 다운로드하도록 하는 기법입니다.

  • 기존 방식: 모든 코드를 하나의 번들에 넣어 한 번에 로딩 → 앱이 커질수록 초기 로딩 시간이 길어짐
  • 코드 스플리팅: 진입 시 필요한 최소한의 코드만 불러오고, 나머지는 필요한 시점에 로드

👉 덕분에 초기 로딩 속도가 빨라지고, 사용자 경험이 개선됩니다.

 

 

그렇다면 코드 스플리팅이라는 것은 그냥 import를 시간차를 두고 하는걸까?  🤔 

 

 

찾아보니 거의 맞지만 조금 더 정확히 설명하면

코드 스플리팅(Code Splitting)은 단순히 import 타이밍을 늦추는 것 이상의 개념이라고 합니다. 😄

 

 

  • 애플리케이션의 코드를 여러 청크(chunk)로 나누는 것
  • 브라우저가 필요할 때만 해당 청크를 다운로드하도록 만드는 전략
  • 초기 번들을 작게 만들어 첫 화면 로딩 속도(FCP, LCP 등)를 개선

 

🧩 청크(chunk)란?

  • 청크 = 코드 조각, 번들 단위
  • 웹팩(Webpack)이나 Next.js 같은 번들러가 자바스크립트 코드를 묶을 때 만드는 작은 파일 단위
  • 브라우저는 필요할 때 각 청크를 따로 다운로드해서 실행

 

🤨 그럼 크롬 브라우저 > 개발자도구 의 Source에 있는게 청크야?

 

    결론부터 이야기한다면

  • Network에서 다운로드되는 JS 파일이 실제 “청크”라고 보는 게 가장 명확합니다.
  • Sources에서는 이미 로드된 청크를 포함해 모든 스크립트. 개발자 디버깅용

📂 Source 패널에 나오는 파일

  • 크롬 DevTools > Sources에 보이는 파일들은 브라우저가 현재 로드한 스크립트를 보여주는 것
  • 여기에는 메인 번들(main.js) + 분할된 청크(chunk.js) 모두 포함됨
  • 즉, 청크도 결국 소스 코드 파일로 보이지만, “Sources에서 보인다 = 청크다”는 건 아님
  • 예: main.js, 0.js, Chart.js 등은 각각 청크일 수 있음

📂  Network 패널에서 다운로드 되는 파일

  • 크롬 DevTools > Network에서 .js 파일이 요청될 때마다 HTTP 요청으로 내려받는 단위가 청크라고 볼 수 있음
  • dynamic import로 나눈 컴포넌트는 사용자가 필요할 때 네트워크로 다운로드
  • 예: 초기 로딩 시 main.js, index.js만 다운로드 → 스크롤 시 Chart.js 청크 다운로드

🔑 핵심 차이

구분 Source Network
청크 여부 로드된 모든 JS 파일 보기 실제 다운로드된 JS 파일 단위가 청크
동적 로드 이미 로드된 상태 필요한 시점에 새로 요청되는 파일
확인 용도 코드 디버깅 청크가 실제로 분리되고 다운로드되는지 확인

 

 

코드 스플리팅이 실제로 네트워크 요청 단위(청크)로 어떻게 동작하는지 설명하자면,

아래와 같은 코드들이 있을 때,

import ChartBar from './ChartBar';
import ChartLine from './ChartLine';
import ChartPie from './ChartPie';
import ChartRadar from './ChartRadar';
import ChartScatter from './ChartScatter';

export default function Page() {
  return (
    <>
      <ChartBar />
      <ChartLine />
      <ChartPie />
      <ChartRadar />
      <ChartScatter />
    </>
  );
}

 

📶 개발자 도구 > Network 패널의 흐름

순서 파일이름 용량 설명
1 main.js 200KB 초기 페이지 번들, 모든 차트 포함
2 vendor.js 150KB React 등 외부 라이브러리
3 기타 CSS/이미지 ... 페이지 렌더링용

⭐ 특징:

  • 페이지 접속 시 모든 차트 코드가 한 번에 다운로드됨
  • 초기 로딩 시간이 길어질 수 있음

import dynamic from 'next/dynamic';
const ChartBar = dynamic(() => import('./ChartBar'));
const ChartLine = dynamic(() => import('./ChartLine'));
const ChartPie = dynamic(() => import('./ChartPie'));
const ChartRadar = dynamic(() => import('./ChartRadar'));
const ChartScatter = dynamic(() => import('./ChartScatter'));

export default function Page() {
  return (
    <>
      <ChartBar />
      <ChartLine />
      <ChartPie />
      <ChartRadar />
      <ChartScatter />
    </>
  );
}

 

위와 같은 코드의 경우,

📶 개발자 도구 > Network 패널의 흐름

순서 파일 이름 용량 설명
1 main.js 80KB 초기 페이지 번들, dynamic 제외
2 vendor.js 150KB React 등 외부 라이브러리
3 0.js 30KB ChartBar 청크 (렌더링 시 다운로드)
4 1.js 25KB ChartLine 청크
5 2.js 40KB ChartPie 청크
6 3.js 35KB ChartRadar 청크
7 4.js 45KB ChartScatter 청크

⭐ 특징:

  • 초기 페이지 로딩 시 main.js는 가벼움 → FCP/LCP 빠름
  • 각 차트가 렌더링될 때 해당 청크만 다운로드
  • 불필요한 코드 다운로드 최소화 → Performance 점수 향상

 

 


2️⃣ Next.js에서 코드 스플리팅 방법

2-1. 페이지 단위 자동 코드 스플리팅

  • Next.js가 기본 제공하는 방식 (Next.js는 페이지 파일 단위로 자동 코드 스플리팅 제공)
  • 개발자가 별도로 설정할 필요 없음
  • 폴더 안의 파일 기준으로 번들이 나뉨
  • 페이지 진입 시 해당 코드만 다운로드 (/about 접속 시 about/page.tsx 청크만 다운로드)

⭐ 특징:

  • 가장 간단하게 적용 가능
  • 페이지 단위로 자동 최적화
  • SSR과 CSR 모두 지원

흐름

  1. 사용자가 /about 페이지 접속
  2. Next.js는 about.js에 해당하는 청크만 로드
  3. 다른 페이지(contact.js, index.js)는 로드하지 않음
  4. 페이지 전환 시 필요한 번들만 새로 로드

👉 장점: 별도 설정 없이 자동 적용, 초기 진입 시 최소 코드만 로드
👉 예시: 블로그 글 상세 페이지에 들어갈 때, 다른 글 관련 JS는 다운로드되지 않음


2-2. 동적 import (next/dynamic) - 수동 코드 스플리팅

  • 특정 컴포넌트 단위로 청크를 분리
  • 필요할 때만 다운로드 가능, SSR 제외 가능
 
import dynamic from "next/dynamic";
const Chart = dynamic(() => import("./Chart"), { ssr: false });

 

⭐ 특징:

  • 큰 라이브러리나 모달, 차트 등 초기 로딩에 필요 없는 컴포넌트에 유용
  • SSR 제외 가능 → 서버 부담 감소

 

개발자가 명시적으로 분리하는 방식

  • 특정 컴포넌트가 무겁거나, 항상 필요한 게 아닐 때 동적으로 로드
  • 버튼 클릭, 특정 이벤트 발생 시점에만 다운로드

흐름

  1. 사용자가 /index 페이지 접속
  2. Modal 컴포넌트는 초기 번들에 포함되지 않음
  3. 사용자가 버튼 클릭 → Modal이 필요한 순간 네트워크 요청 발생
  4. Modal 청크 파일을 비동기로 다운로드 후 화면 렌더링

👉 장점: 무거운 라이브러리(차트, 지도, 에디터 등)를 초기 로딩에서 제외 가능
👉 예시: 지도 API는 특정 화면에서만 필요 → 해당 버튼을 눌렀을 때만 로드

 

 

예시)

// pages/index.js
import { useState } from 'react';
import dynamic from 'next/dynamic';

// 동적으로 Modal 컴포넌트 로드
const DynamicModal = dynamic(() => import('../components/Modal'), {
  ssr: false, // 서버 사이드 렌더링 제외
});

export default function HomePage() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div>
      <h1>Next.js Code Splitting Example</h1>
      <button onClick={() => setIsOpen(true)}>Open Modal</button>
      {isOpen && <DynamicModal onClose={() => setIsOpen(false)} />}
    </div>
  );
}

👉 여기서 중요한 점:

  • dynamic()을 선언하지 않으면, Modal 코드가 초기 번들에 포함됨 → 초기 로딩 느려짐
  • dynamic()을 사용하면, Modal은 별도의 청크로 분리되어 버튼을 눌렀을 때만 로드됨

2-3. React.lazy + Suspense

  • React에서 제공하는 동적 import 기능
  • Next.js App Router에서도 사용 가능
  • Next.js에서는 next/dynamic이 내부적으로 React.lazy를 확장한 형태라 더 편리
import React, { Suspense } from "react";
const Chart = React.lazy(() => import("./Chart"));
export default function Page() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Chart />
    </Suspense>
  );
}
 

⭐ 특징:

  • Suspense로 로딩 상태 표시 가능
  • 단점: SSR을 사용하려면 추가 설정 필요

2-4. Webpack import()

  • Next.js는 내부적으로 Webpack 사용
  • import()를 직접 사용하면 Webpack이 청크로 분리
button.addEventListener('click', () => { 
	import('./Chart').then((module) => { const Chart = module.default; Chart.render(); }); 
});
 

⭐ 특징:

  • 페이지/컴포넌트 단위 모두 가능
  • Next.js 환경에서는 dynamic이 더 편리

 


 

5️⃣ 언제 차이가 나는가?

  • 컴포넌트가 작을 때 → 초기 로딩 속도 차이는 거의 없음
  • 컴포넌트가 클 때 (예: 차트 라이브러리, 에디터, 지도 API 등) → dynamic을 쓰면 초기 로딩이 훨씬 빨라짐

즉, 모든 컴포넌트를 동적으로 분리할 필요는 없고, 무겁고 특정 상황에서만 필요한 컴포넌트를 dynamic으로 처리하는 것이 좋습니다.

 

 


6️⃣ 실제 프로젝트 적용

실제 차트 라이브러리 를 다루는 테스트 프로젝트에서 dynamic을 활용해 보았습니다.

 

📊 문제 : 서비스 대시보드에 여러 개의 차트를 표시

-> 이를 해결하기 위해, 차트 컴포넌트를 next/dynamic으로 분리하여 해당 페이지에 진입했을 때만 다운로드하도록 변경

 

 

(하지만 단순히 차트 5개를 한 페이지에 배치한다고 해서 심각한 성능 저하가 발생하지는 않았습니다. 그 점 참고 바랍니다.)


실제 테스트 결과, 생각과는 다소 다른 결과가 나왔습니다.


dynamic을 사용하면 성능이 더 좋아질 것이라고 예상했지만, 오히려 사용하지 않은 쪽이 더 높은 성능을 보여주었습니다.
아래에서 테스트 과정과 함께 자세히 설명해드리겠습니다.



첫 번째 테스트는 평소처럼 일반적인 import를 사용해 차트를 렌더링하는 방식으로 구성했습니다.
두 번째 테스트는 dynamic을 활용하여 차트를 필요할 때만 불러오는 방식으로 만들어 비교했습니다.

일반적인 import 사용한 코드

 

dynamic을 사용한 코드

 

 

 

결과:  dynamic을 쓰는 페이지가 lighthouse 측정 시, Performance 부분이 더 낮게 나오게 되었습니다. 😅  

👉 이 경험을 통해 dynamic은 필요한 경우에만 적절히 사용하는 것이 중요하다는 걸 깨달았습니다. 무작정 성능 최적화를 위해 남발하면 오히려 역효과가 날 수 있다는 점도 배우게 되었습니다.

 

 

1️⃣ Dynamic Import의 효과는 언제 체감되는가?

  • dynamic import는 초기 번들에서 해당 컴포넌트를 제외하고 필요할 때 로드하도록 하는 기능
  • 초기 로딩에서만 성능을 보는 Lighthouse 기준에서는:
    • 이미 5개 차트 전체가 화면에 보이도록 렌더링되고 있음
    • 즉, dynamic import가 있어도 초기 렌더링 시점에 모든 차트 JS가 다운로드되면서 렌더링됨 → 초기 FCP/LCP에는 큰 이득 없음

한마디로, dynamic import는 초기 화면에 안 보이는 컴포넌트에 효과적이지, 화면 진입 시 이미 모든 차트를 보여주면 체감 성능이 적음


2️⃣ Lighthouse 점수가 낮게 나온 이유

  • dynamic import로 각 컴포넌트가 별도 청크로 분리됨 → 브라우저가 네트워크 요청을 동시에 여러 번 해야 함
  • Chrome Lighthouse는 모든 네트워크 요청과 JS 실행 시간을 측정
  • 따라서 작은 차트는 dynamic import로 오히려 초기 로딩 지연이 발생할 수 있음 (청크 로딩 오버헤드)

즉, dynamic import가 항상 Performance 점수를 올려주는 건 아니고, 컴포넌트 크기와 초기 화면 노출 여부에 따라 효과가 달라집니다.


3️⃣ 결론 / 적용 포인트

  • 화면 진입 시 모든 컴포넌트를 보여줘야 한다 → dynamic import는 오히려 초기 로딩 지연 가능
  • 화면 진입 시 필요 없는 컴포넌트 (탭, 모달, 스크롤 지점 등) → dynamic import 효과 확실
  • Lighthouse 점수로 비교하려면 초기 화면에 바로 안 보이는 차트를 만들어서 테스트해야 차이를 명확히 볼 수 있음

💡 요약 비유

  • dynamic import = "필요할 때만 창고에서 꺼내 쓰기"
  • 현재처럼 진입과 동시에 모든 차트를 렌더링 = "필요 없어도 창고에서 다 꺼내놓음" → 초기 성능 이득 없음

 

 

🆕 추가 테스트

dynamic 을 사용한 부분의 Perfomance 점수를 향상을 위해 

Next.js에서 dynamic import + 스크롤 트리거를 적용해 보았습니다.

 

1️⃣ 접근 방법

  • 초기 화면에 보이는 차트만 바로 렌더
  • 나머지 차트는 스크롤할 때 Intersection Observer로 동적 로드
  • 차트별로 min-height: 50vh 등 반응형 높이를 적용하여, 첫 화면에는 일부만 보이고 나머지는 스크롤해야 나타나도록 구성

2️⃣ 적용 효과

  • dynamic import를 사용해 초기 화면에 필요 없는 JS 청크를 지연 로딩
  • 스크롤 시 차트가 로드되어 UX 저하 없이 렌더링
  • Lighthouse Performance 점수 향상 확인

3️⃣ 결론

  • 반응형 높이와 스크롤 기반 로딩을 결합하면 초기 로딩 최적화 + 사용자 체감 성능 개선 모두 달성 가능

 

// src/app/dynamic-chart-test-opt/page.tsx
"use client";

import { useEffect, useRef, useState } from "react";
import dynamic from "next/dynamic";

// 초기 화면 2개 차트는 바로 import
import ChartBar from "../dynamic-chart-test/ChartBar";
import ChartLine from "../dynamic-chart-test/ChartLine";

// 나머지 3개는 dynamic import + ssr: false
const ChartPie = dynamic(() => import("../dynamic-chart-test/ChartPie"), { ssr: false });
const ChartRadar = dynamic(() => import("../dynamic-chart-test/ChartRadar"), { ssr: false });
const ChartScatter = dynamic(() => import("../dynamic-chart-test/ChartScatter"), { ssr: false });

const DynamicChartScrollPage: React.FC = () => {
    const [showPie, setShowPie] = useState(false);
    const [showRadar, setShowRadar] = useState(false);
    const [showScatter, setShowScatter] = useState(false);
  
    const pieRef = useRef<HTMLDivElement>(null);
    const radarRef = useRef<HTMLDivElement>(null);
    const scatterRef = useRef<HTMLDivElement>(null);
  
    useEffect(() => {
        const observerCallback = (
          entries: IntersectionObserverEntry[],
          observer: IntersectionObserver,
          setter: React.Dispatch<React.SetStateAction<boolean>>
        ) => {
          if (entries[0].isIntersecting) {
            setter(true);
            observer.disconnect(); // 한 번 로드 후 관찰 종료
          }
        };
      
        const createObserver = (
          ref: React.RefObject<HTMLDivElement | null>,
          setter: React.Dispatch<React.SetStateAction<boolean>>
        ) => {
          if (!ref.current) return; // null 체크
          const observer = new IntersectionObserver(
            (entries) => observerCallback(entries, observer, setter),
            { threshold: 0.1 }
          );
          observer.observe(ref.current); // ref.current는 null이 아님이 확실
        };
      
        // 안전하게 null 체크 후 호출
        if (pieRef.current) createObserver(pieRef, setShowPie);
        if (radarRef.current) createObserver(radarRef, setShowRadar);
        if (scatterRef.current) createObserver(scatterRef, setShowScatter);
      }, []);
  
    const chartStyle: React.CSSProperties = {
      width: "100%",
      minHeight: "50vh", // 반응형 높이, 화면 절반 정도
      marginBottom: "20px",
    };
  
    return (
      <div style={{ padding: "20px" }}>
        <h1>Dynamic Chart Test (Scroll Trigger, Responsive)</h1>
  
        {/* 초기 화면 차트 */}
        <div style={chartStyle}><ChartBar /></div>
        <div style={chartStyle}><ChartLine /></div>
  
        {/* 스크롤 시 로드되는 차트 */}
        <div ref={pieRef} style={chartStyle}>
          {showPie && <ChartPie />}
        </div>
        <div ref={radarRef} style={chartStyle}>
          {showRadar && <ChartRadar />}
        </div>
        <div ref={scatterRef} style={chartStyle}>
          {showScatter && <ChartScatter />}
        </div>
      </div>
    );
  };
  
  export default DynamicChartScrollPage;

 

✅ 특징

  1. 첫 화면: Bar + Line만 로드 → 초기 FCP/LCP 빠름
  2. 스크롤 트리거: Pie, Radar, Scatter → 필요할 때만 JS 청크 다운로드
  3. 반응형 높이: minHeight: "50vh" → 화면 크기에 따라 자동 조절
  4. TypeScript 오류 없음: ref.current!와 null 체크로 안전하게 동작
  5. Performance 최적화 체감: 초기 화면 Lighthouse 점수 상승, 스크롤 시 차트 로딩

7️⃣ 코드 스플리팅의 장점

  1. 초기 로딩 속도 향상 – 필요한 코드만 먼저 내려받아 사용자 체감 속도 개선
  2. 불필요한 코드 다운로드 최소화 – 네트워크 절약, 특히 모바일 환경에서 유리
  3. 대규모 앱 성능 안정화 – 번들 크기 분리로 브라우저 부담 감소
  4. 캐싱 효율 증가 – 변경된 청크만 다시 내려받으면 됨

8️⃣ 면접에서 활용할 답변 예시

  • 프론트엔드 성능 최적화 경험을 강조하고 싶은 경우
  • Next.js, React, Vue 등 SPA 프레임워크 경험을 평가할 때
  • 대규모 프로젝트 경험이 있는 지원자를 평가할 때
  • Lighthouse, 웹 성능, 번들 최적화 관련 질문이 나올 때

 

💡 면접관이 기대하는 답변 포인트

  1. 코드 스플리팅의 개념
    • 앱을 작은 청크(chunk) 단위로 나누어 필요할 때만 로드하는 기법
    • 초기 로딩 속도(FCP, LCP) 개선 및 불필요한 코드 다운로드 최소화
  2. Next.js에서의 방법
    • 페이지 단위 자동 코드 스플리팅
    • next/dynamic으로 컴포넌트 단위 코드 스플리팅
    • 필요 시 React.lazy + Suspense 활용 가능
  3. 실제 경험 예시
    • 무거운 라이브러리(차트, 지도, 에디터 등)를 동적으로 로드한 사례
    • 초기 로딩 성능 개선, 네트워크 요청 분산 등
  4. 적용 시 고려 사항
    • 초기 화면에 바로 보여지는 컴포넌트는 dynamic으로 분리하지 않음
    • 필요 없는 컴포넌트에만 dynamic 적용
    • 잘못 사용하면 오히려 성능 저하 가능

 

프론트엔드 면접에서 코드 스플리팅 자체를 직접 물어보지는 않을 수도 있지만, 성능 최적화, 번들 관리, Next.js 경험과 연결되면 거의 확실히 나올 수 있습니다.

 

 

질문:  "코드 스플리팅이 뭔가요?"

답변 예시:

“코드 스플리팅은 애플리케이션 코드를 작은 청크(chunk) 단위로 나누어, 사용자가 필요할 때만 해당 코드를 다운로드하도록 하는 기술입니다.
덕분에 초기 페이지 로딩 속도를 높이고, 불필요한 코드 다운로드를 줄여 성능을 개선할 수 있습니다.”


질문: "Next.js에서 코드 스플리팅은 어떻게 되나요?"

답변 예시:

“Next.js는 페이지 단위 코드 스플리팅을 자동으로 지원합니다.
즉, 사용자가 특정 페이지로 접근하면 그 페이지에 필요한 번들만 내려받습니다.
또한, next/dynamic을 사용하면 컴포넌트 단위로 동적으로 로드할 수 있어, 초기 화면에 필요 없는 무거운 라이브러리(예: 차트, 지도, 에디터 등)를 나중에 불러오도록 할 수 있습니다.”


질문: "실제로 프로젝트에서 적용한 경험이 있나요?"

답변 예시:

“저는 서비스 대시보드에 여러 차트를 표시해야 하는 페이지를 개발하면서, 차트 라이브러리 용량 때문에 초기 로딩 속도가 느려지는 문제를 발견했습니다.
이를 해결하기 위해, 초기 화면에서 바로 보이는 차트만 일반 import로 불러오고, 나머지 차트는 next/dynamic + 스크롤 트리거로 동적 로딩하도록 구현했습니다.
결과적으로 초기 FCP/LCP가 개선되고, 네트워크 사용량도 줄어 성능 최적화에 성공했습니다.”


질문: "dynamic을 무조건 쓰면 좋은가요?"

답변 예시:

“Dynamic import를 무작정 쓰는 것이 항상 좋은 것은 아닙니다.
초기 화면에 반드시 보여야 하는 컴포넌트까지 동적으로 로드하면 오히려 초기 로딩 속도가 느려질 수 있습니다.
따라서 ‘화면 진입 시 필요 없는 컴포넌트’나 ‘특정 이벤트 발생 시 필요한 컴포넌트’에만 적용하는 것이 핵심입니다.”

 

 


✅ 마무리

Next.js 코드 스플리팅은 자동(페이지 단위) + 수동(dynamic을 통한 컴포넌트 단위) 두 가지 방식이 결합된 강력한 성능 최적화 전략입니다.

  • 기본 페이지 이동만으로도 성능 이점 확보
  • 필요 시 무거운 컴포넌트를 동적으로 분리해 초기 로딩 최적화

👉 프로젝트 규모가 커질수록 효과가 극대화되므로, 꼭 알고 넘어가야 할 Next.js의 핵심 기능 중 하나입니다.

 

🔹 정리:    자동 vs 수동 코드 스플리팅 흐름 비교

구분 자동 코드 스플리팅 수동 코드 스플리팅 (dynamic)
기준 페이지 단위 컴포넌트 단위
적용 Next.js가 자동 처리 개발자가 dynamic() 사용
로드 시점 페이지 진입 시 필요 시점 (버튼 클릭, 스크롤 등)
장점 설정 필요 없음, 초기 로딩 최적화

/about 접속 시 about.js만 다운로드
무거운 라이브러리 초기 로딩 제외 가능

모달, 차트, 지도 API 등 필요할 때만 다운로드
 

✅ 결론:

  • 페이지 단위는 Next.js가 자동으로 처리
  • 컴포넌트 단위는 next/dynamic이 가장 편리
  • 필요에 따라 React.lazy나 Webpack import()도 선택 가능

➕ 추가

✅ Pages Router vs App Router 기준으로 Next.js 코드 스플리팅 차이

📝 Pages Router 기준 (pages/)

  • 각 페이지 파일이 별도의 JS 청크로 분리됨
  • 사용자가 /about 페이지로 이동하면 → about.js 청크만 다운로드
  • 초기 로딩 시 불필요한 페이지 코드는 내려받지 않음
  • 동적 import(next/dynamic)로 컴포넌트 단위 코드 스플리팅도 가능

특징

  • 경로 구조: 파일명 그대로 URL
  • 자동 분리: 페이지 단위
  • 동적 import: 컴포넌트 단위

📝 App Router 기준 (app/)

  • 각 page.tsx가 별도의 청크로 자동 분리됨
  • /about 접속 시 → about/page.tsx 청크만 다운로드
  • App Router에서도 next/dynamic으로 컴포넌트 단위 코드 스플리팅 가능

특징

  • 경로 구조: 폴더 구조 + page.tsx
  • 자동 분리: 페이지 단위
  • 동적 import: 컴포넌트 단위
  • 레이아웃(layout.tsx)도 자동 청크 분리 → 공통 레이아웃은 캐싱 효율 ↑

🔹 핵심 비교

항목 Pages Router App Router
파일 구조 pages/about.js app/about/page.tsx
URL 매핑 파일명 기준 폴더 + page.tsx
페이지 청크 자동 분리 자동 분리
컴포넌트 청크 next/dynamic 사용 next/dynamic 사용
레이아웃/공통 컴포넌트 별도 청크 분리 어려움 layout.tsx로 쉽게 청크 분리 가능
장점 익숙함, 단순 레이아웃 재사용 + 캐싱 효율 ↑

정리하면 ✅

  • 자동 코드 스플리팅은 Pages Router든 App Router든 동일하게 동작
  • 차이는 폴더 구조와 레이아웃 처리 방식 정도
  • App Router에서는 레이아웃까지 청크로 분리할 수 있어 성능과 캐싱 효율이 더 좋아짐

 

반응형

+ Recent posts