Next JS 코드 스플리팅 적용해보기 (Dynamic Import)

2022. 7. 3. 13:55Library,Framework

728x90

이번 포스트에서는 Next JS에서 동적 불러오기(Dynamic Import)를 통해 코드분할(Code Splitting)을 적용해보도록 하겠습니다.

 

React의 경우 모든 페이지가 하나의 페이지에서 랜더링 되는 SPA (Single Page Application)이기 때문에 코드분할을 따로 해주지 않으면 퍼포먼스에 영향이 가게 되고 이는 곧 좋지 않은 사용자 경험으로 이어지게 됩니다. 물론 한 페이지에서 실행되는 로직이 복잡하지 않다면 크게 영향을 받지는 않지만 로직이 복잡해지고 많은 양의 데이터를 불러와야 한다면 각 라우트마다 코드 스플리팅을 해주는 편이 좋습니다. 

 

그렇다면 Next JS는 어떨까요? 

 

넥스트 JS를 배워보자 1편 에서 언급했다시피 Next JS는 파일 시스템의 라우트를 내장하고 있기 때문에 pages에 파일만 만들어주면 알아서 해당 라우트가 생성이 됩니다. Next JS는 SSR이나 SSG를 지원하도록 만들어졌기 때문에 React를 사용할때와는 달리 라우트 별로 코드 분할을 하지 않아도 알아서 적용이 되는 구조입니다. 

 

그럼 Next JS에서는 코드 분할을 안해도 되는 건가요라고 물으신다면 당연히 그건 아닙니다. 물론 페이지 단위로는 하지 않아도 되지만 코드 분할을 적용할 수 있는 범위는 생각보다 많습니다. 예를 들어 로그인/회원가입 모달 창 컴포넌트 코드를 분할하여 동적으로 불러온다던지, 페이지 내에 탭 메뉴에 첫 메뉴만 불러오고 사용자가 다른 메뉴를 클릭했을 때 그에 맞는 컴포넌트를 랜더링 하는 방식이 있습니다. 그럼 한번 실제로 적용해보도록 하겠습니다.

 


코드 분할 적용해보기

필자가 현재 진행중인 프로젝트의 마이페이지에서 프로필이나 나의 리뷰 탭이 따로 나눠져 있는데 마이페이지가 랜더링 됐을 때 프로필 정보와 리뷰를 둘 다 불러오는 게 아니고 해당 메뉴탭을 클릭했을 때 동적으로 해당 컴포넌트를 불러오도록 설정해보도록 하겠습니다.

 

import React, { useState } from "react";
import dynamic from "next/dynamic";
import Spinner from "components/Spinner";
import styles from "styles/pages/Experts/MyProfile.module.scss";

const MyProfile = ({userInfo}) => {
  
  const Review = dynamic(() => import("components/Content/ManagerReview"), {
    loading: () => <Spinner />,
  });

  const Profile = dynamic(() => import("components/Content/ManagerProfile"), {
    loading: () => <Spinner />,
  });
  
  const [activeMenu, setActiveMenu] = useState("profile");
  
  return (
    <div className={styles.profile}>
      <div className={styles.nav}>
        <Button
          onClick={() => setActiveMenu("profile")}
          noStyle
          className={classNames(styles.btn, {
            [styles.active]: activeMenu === "profile",
          })}
        >
          내 정보
        </Button>
        <Button
          onClick={() => setActiveMenu("reviews")}
          noStyle
          className={classNames(styles.btn, {
            [styles.active]: activeMenu === "reviews",
          })}
        >
          내가 받은 리뷰
        </Button>
      </div>
      {activeMenu === "profile" && <Profile user={userInfo} />}
      {activeMenu === "reviews" && <Review id={userInfo?.id} />}
    </div>
  );
};

 

위에 작성한 코드처럼 Next JS에서 컴포넌트를 동적으로 불러오기 위해선 React.lazy의 extension인 next/dynamic을 사용해주면 됩니다. 각 메뉴 버튼에 현재 클릭된 버튼을 알 수 있도록 상태를 변경시켜주도록 설정을 해두고 사용자가 버튼을 클릭했을 때 activeMenu에 따라 해당 컴포넌트가 동적으로 불러와지도록 작성만 해두시면 됩니다.

 

React 18 이전 버전에서는 loading으로 모듈이 로드되는 동안 사용자에게 보여줄 문구나 컴포넌트를 넣어주고 만약 18 이후 버전을 사용 중이라면 아래와 같이 Suspense와 Fallback 조합으로도 작성 가능합니다.  React 18에 소개된 Suspense와 Fallback 개념에 대해 아직 익숙하지 않다면 React의 공식문서를 참고해주시길 바랍니다.

 

import dynamic from 'next/dynamic'
import { Suspense } from 'react'

const MyProfile = ({userInfo}) => { 
const Profile = dynamic(() => import("components/Content/ManagerProfile"), {
  suspense: true,
})

return (
	...생략
    <Suspense fallback={`Loading...`}>
      <Profile />
    </Suspense>
    ...생략
)

}

 


해당 포스트에 제목은 Next JS에서 코드 스플리팅 (코드 분할)을 적용하는 방법이지만 앞선 상황은 그냥 React를 사용했을 때도 마찬가지로 코드 분할을 적용해주는 편이 좋다고 생각합니다. 물론 해당 상황은 불러올 데이터양이 많지가 않아 크게 차이가 없고 데이터가 많아진다고 해도 내 리뷰 데이터는 최대 10개씩만 가져오도록 페이지네이션 처리를 해주었기 때문에 퍼포먼스에 큰 영향은 없을 것입니다. 하지만 마이페이지를 클릭하는 사용자 중 대다수의 사용자는 기본적으로 불러와지는 프로필 정보를 원해서 들어오는 경우가 많기 때문에 나의 리뷰 정보가 필요한 사용자들에게만 해당 데이터를 요청해서 보여주는 방식이 적합하다고 생각을 했기 때문에 코드 분할을 진행해보았습니다.

 

 

출처: https://nextjs.org/docs/advanced-features/dynamic-import