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

코드 분할 및 스마트 로드 전략으로 Next.js 앱의 속도를 높이는 방법

게시일: 2019년 11월 8일

다양한 유형의 코드 분할과 동적 가져오기를 사용하여 Next.js 앱의 속도를 높이는 방법을 알아봅니다.

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

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

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

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

동적 가져오기 사용 사례

이 게시물에는 버튼 하나가 있는 간단한 페이지로 구성된 샘플 앱의 여러 버전이 포함되어 있습니다. 버튼을 클릭하면 귀여운 강아지가 표시됩니다. 앱의 각 버전을 살펴보면서 동적 가져오기가 정적 가져오기와 어떻게 다른지, 동적 가져오기를 사용하는 방법을 알아봅니다.

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

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

Next.js가 앱을 번들링하는 방법을 확인하려면 DevTools에서 네트워크 추적을 검사하세요.

  1. 사이트를 미리 보려면 앱 보기를 누릅니다. 그런 다음 전체 화면 전체 화면을 누릅니다.

  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 네트워크 탭

클릭하세요 버튼을 누르면 강아지 JPEG 요청만 네트워크 탭에 추가됩니다.

버튼 클릭 후 DevTools 네트워크 탭에 동일한 6개의 JavaScript 파일과 1개의 이미지가 표시됩니다.

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

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

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로 감소).

이제 index.js가 0.5KB 더 작아진 것을 제외하고 동일한 6개의 JavaScript 파일을 보여주는 DevTools 네트워크

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

버튼 클릭 후 DevTools 네트워크 탭으로, 추가된 1.js 파일과 파일 목록 하단에 추가된 이미지가 표시됩니다.

실제 애플리케이션에서 구성요소는 훨씬 더 큰 경우가 많으며, 이러한 구성요소를 지연 로드하면 초기 JavaScript 페이로드를 수백 킬로바이트까지 줄일 수 있습니다.

맞춤 로드 표시기가 있는 동적 가져오기

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

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

로딩 표시기가 작동하는 것을 확인하려면 DevTools에서 느린 네트워크 연결을 시뮬레이션하세요.

  1. 사이트를 미리 보려면 앱 보기를 누릅니다. 그런 다음 전체 화면 전체 화면을 누릅니다.

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

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

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

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

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

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

텍스트가 표시된 어두운 화면

SSR이 없는 동적 가져오기

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

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

결론

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