Next.js에서 동적 가져오기를 사용한 코드 분할

코드 분할과 스마트 로드 전략을 통해 Next.js 앱의 속도를 높이는 방법

밀리카 미하즐리야
밀리카 미하즐리야

학습 내용

이 게시물에서는 다양한 유형의 코드 분할과 동적 가져오기를 사용하여 Next.js 앱의 속도를 높이는 방법을 설명합니다.

경로 기반 및 구성요소 기반 코드 분할

기본적으로 Next.js는 JavaScript를 경로마다 별도의 청크로 분할합니다. 사용자가 애플리케이션을 로드하면 Next.js는 초기 경로에 필요한 코드만 전송합니다. 사용자는 애플리케이션을 탐색할 때 다른 경로와 연결된 청크를 가져옵니다. 경로 기반 코드 분할은 한 번에 파싱 및 컴파일해야 하는 스크립트의 양을 최소화하므로 페이지 로드 시간이 빨라집니다.

경로 기반 코드 분할이 적절한 기본값이지만 구성요소 수준에서 코드 분할을 사용하여 로드 프로세스를 추가로 최적화할 수 있습니다. 앱에 큰 구성요소가 있는 경우 별도의 청크로 분할하는 것이 좋습니다. 이렇게 하면 중요하지 않거나 특정 사용자 상호작용 (예: 버튼 클릭)에서만 렌더링되는 대형 구성요소를 지연 로드할 수 있습니다.

Next.js는 JavaScript 모듈 (React 구성요소 포함)을 동적으로 가져오고 각 가져오기를 별도의 단위로 로드할 수 있는 동적 import()를 지원합니다. 이렇게 하면 구성요소 수준의 코드 분할이 가능해지며, 사용자가 보고 있는 사이트에서 필요한 코드만 다운로드하도록 리소스 로드를 제어할 수 있습니다. Next.js에서 이러한 구성요소는 기본적으로 서버 측 렌더링(SSR)입니다.

동적 가져오기의 작동 방식

이 게시물에는 하나의 버튼이 있는 간단한 페이지로 구성된 여러 버전의 샘플 앱이 포함되어 있습니다. 버튼을 클릭하면 귀여운 강아지가 표시됩니다. 앱의 각 버전을 살펴보면서 동적 가져오기와 정적 가져오기의 차이점과 동적 가져오기로 작업하는 방법을 확인할 수 있습니다.

앱의 첫 번째 버전에서는 강아지가 components/Puppy.js에 살고 있습니다. 페이지에 강아지를 표시하기 위해 앱은 정적 가져오기 문을 사용하여 index.jsPuppy 구성요소를 가져옵니다.

import Puppy from "../components/Puppy";

Next.js가 앱을 번들로 묶는 방법을 보려면 DevTools에서 네트워크 트레이스를 검사합니다.

  1. 사이트를 미리 보려면 View App을 누른 다음 Fullscreen 전체 화면을 누릅니다.

  2. `Control+Shift+J` (Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.

  3. 네트워크 탭을 클릭합니다.

  4. 캐시 사용 중지 체크박스를 선택합니다.

  5. 페이지를 새로고침합니다.

페이지를 로드하면 Puppy.js 구성요소를 포함하여 필요한 모든 코드가 index.js에 번들로 포함됩니다.

6개의 JavaScript 파일(index.js, app.js, webpack.js, main.js, 0.js), dll(동적 링크 라이브러리) 파일이 표시된 DevTools Network 탭

Click me 버튼을 누르면 강아지 JPEG에 대한 요청만 Network 탭에 추가됩니다.

버튼을 클릭한 후 DevTools Network 탭에 동일한 JavaScript 파일 6개와 이미지 1개가 표시되어 있습니다.

이 접근 방식의 단점은 사용자가 강아지를 보기 위해 버튼을 클릭하지 않더라도 index.js에 포함되어 있으므로 Puppy 구성요소를 로드해야 한다는 것입니다. 이 예시에서는 큰 문제가 아니지만 실제 애플리케이션에서는 필요할 때만 큰 구성요소를 로드하는 것이 크게 개선되는 경우가 많습니다.

이제 정적 가져오기가 동적 가져오기로 대체된 두 번째 버전의 앱을 확인해 보세요. Next.js에는 Next의 모든 구성요소에 동적 가져오기를 사용할 수 있는 next/dynamic가 포함되어 있습니다.

import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";

// ...

const Puppy = dynamic(import("../components/Puppy"));

첫 번째 예의 단계에 따라 네트워크 트레이스를 검사합니다.

앱을 처음 로드하면 index.js만 다운로드됩니다. 이번에는 Puppy 구성요소의 코드가 포함되어 있지 않으므로 0.5KB 더 작습니다 (37.9KB에서 37.4KB로 줄어짐).

동일한 6개의 JavaScript 파일을 표시하는 DevTools Network 단, index.js는 이제 0.5KB 더 작습니다.

이제 Puppy 구성요소는 버튼을 누를 때만 로드되는 별도의 1.js 청크에 있습니다.

버튼을 클릭한 후 DevTools Network 탭에 추가 1.js 파일과 파일 목록 하단에 추가된 이미지가 표시됩니다.

실제 애플리케이션에서는 구성요소가 훨씬 큰 경우가 많으며 지연 로드를 사용하면 초기 자바스크립트 페이로드가 수백 KB만큼 잘릴 수 있습니다.

맞춤 로드 표시기를 사용한 동적 가져오기

리소스를 지연 로드할 때는 지연이 발생하는 경우 로드 표시기를 제공하는 것이 좋습니다. Next.js에서는 dynamic() 함수에 추가 인수를 제공하여 이 작업을 수행할 수 있습니다.

const Puppy = dynamic(() => import("../components/Puppy"), {
  loading: () => <p>Loading...</p>
});

작동 중인 로드 표시기를 보려면 DevTools에서 느린 네트워크 연결을 시뮬레이션합니다.

  1. 사이트를 미리 보려면 View App을 누른 다음 Fullscreen 전체 화면을 누릅니다.

  2. `Control+Shift+J` (Mac의 경우 `Command+Option+J`)를 눌러 DevTools를 엽니다.

  3. 네트워크 탭을 클릭합니다.

  4. 캐시 사용 중지 체크박스를 선택합니다.

  5. 제한 드롭다운 목록에서 Fast 3G를 선택합니다.

  6. Click me 버튼을 누릅니다.

이제 버튼을 클릭하면 구성요소가 로드되는 데 다소 시간이 걸리며 그동안 앱에 '로드 중...' 메시지가 표시됩니다.

텍스트가 있는 어두운 화면

SSR 없는 동적 가져오기

클라이언트 측에서만 구성요소를 렌더링해야 하는 경우 (예: 채팅 위젯) ssr 옵션을 false로 설정하면 됩니다.

const Puppy = dynamic(() => import("../components/Puppy"), {
  ssr: false,
});

결론

동적 가져오기를 지원하는 Next.js는 JavaScript 페이로드를 최소화하고 애플리케이션 로드 시간을 개선할 수 있는 구성요소 수준의 코드 분할을 제공합니다. 모든 구성요소는 기본적으로 서버 측에서 렌더링되며 필요할 때마다 이 옵션을 사용 중지할 수 있습니다.