React

[Next.js] SSR과 SSG의 최적화 전략: 동적 컴포넌트 관리 방법

연신내고독한늑대 2024. 8. 28. 20:00

Next.js는 현대 웹 애플리케이션 개발을 최적화하는 데 강력한 도구를 제공합니다. Next.js는 기본적으로 **서버 사이드 렌더링(SSR)**을 사용하지만, 상황에 따라 **정적 사이트 생성(SSG)**을 자동으로 적용하여 성능을 극대화합니다. 이 글에서는 Next.js의 SSR, SSG 최적화 전략과 동적 컴포넌트 관리 방법에 대해 다룹니다.

 

■ Next.js의 기본 설정: SSR과 SSG의 자동 최적화

Next.js는 기본적으로 SSR이 defalut로 적용합니다. 이는 페이지 요청 시 Next.js 서버가 HTML을 생성하고 클라이언트로 전달하는 방식입니다. 여기서 "서버"는 Next.js가 자체적으로 제공하는 서버로, 여러분이 사용하는 백엔드(Spring Boot, Node.js 등)와는 다른 개념입니다. Next.js 서버는 주로 클라이언트에게 정적 파일을 제공하거나, SSR을 통해 미리 렌더링된 HTML을 전달하는 역할을 합니다.

하지만, 백엔드와의 통신이나 동적 데이터가 필요 없는 페이지의 경우, Next.js는 SSR 대신 **정적 사이트 생성(SSG)**을 자동으로 적용합니다. 예를 들어, 다음과 같은 페이지를 생각해봅시다:

// src/app/page.tsx
export default function HomePage() {
  return (
    <div>
      <h1>Welcome to Next.js</h1>
    </div>
  );
}

이 페이지는 동적 데이터가 필요하지 않으므로, Next.js는 자동으로 이 페이지를 빌드 시점에 정적 HTML로 생성합니다. 이렇게 생성된 정적 HTML 파일은 .next 폴더에 저장됩니다.

사용자가 페이지를 요청할 때, Next.js 서버는 이 정적 HTML 파일을 SSR을 통해 새로 렌더링하지 않고, 캐시에서 바로 제공하게 됩니다. 이를 통해 페이지 로딩 속도가 극대화되며, 서버의 부하도 줄어듭니다.

 

■ ssr: false 옵션을 사용하는 이유

Next.js에서 dynamic 함수를 사용해 컴포넌트를 동적으로 로드할 때, ssr: false 옵션을 자주 사용합니다. 이 옵션을 설정하면 해당 컴포넌트는 서버 사이드 렌더링(SSR)을 하지 않고, 클라이언트 측에서만 렌더링됩니다.

이 옵션이 필요한 이유는 다음과 같습니다:

  • 클라이언트에서만 필요한 컴포넌트: 예를 들어, 브라우저 API를 사용하는 컴포넌트나 사용자 인터랙션에 의해 로드되는 UI 요소는 SSR이 필요 없습니다.
  • 초기 로딩 성능 최적화: 클라이언트에서만 필요한 컴포넌트를 SSR에서 제외함으로써 초기 로딩 속도를 개선할 수 있습니다.
  • 서버 자원 절약: 서버는 필수적인 컴포넌트만 렌더링하고, 나머지는 클라이언트에서 처리하게 되어 서버 자원을 효율적으로 사용할 수 있습니다.

예를 들어, 다음 코드는 클라이언트에서만 렌더링되는 동적 컴포넌트를 정의합니다:

import dynamic from 'next/dynamic';

// 클라이언트에서만 로드될 컴포넌트
const MyComponent = dynamic(() => import('@/components/MyComponent'), {
  ssr: false, // 서버 사이드 렌더링을 비활성화
});

export default function Page() {
  return (
    <div>
      <h1>My Page</h1>
      <MyComponent />
    </div>
  );
}

 

이 경우 어떻게 동작할까요?

  • 서버 측: MyComponent는 서버에서 렌더링되지 않습니다. Next.js 서버는 <h1>My Page</h1> 부분만 HTML로 생성하여 클라이언트로 전달합니다. 따라서, 초기 HTML에는 MyComponent의 내용이 포함되지 않습니다.
  • 클라이언트 측: 페이지가 로드되면, 브라우저에서 자바스크립트가 실행되면서 MyComponent가 동적으로 로드되고 렌더링됩니다. 즉, 클라이언트에서 자바스크립트가 로드된 후에야 MyComponent가 화면에 표시됩니다.

이렇게 설정함으로써, 클라이언트 측에서만 동작해야 하거나, SSR을 통해 렌더링할 필요가 없는 컴포넌트를 효과적으로 관리할 수 있습니다.

 

■ 동적 컴포넌트와 정적 컴포넌트의 분리: 성능 최적화의 핵심

Next.js에서 동적 컴포넌트 안에 정적 컴포넌트가 포함되면, 해당 정적 컴포넌트도 동적으로 생성됩니다. 이 경우, 원래는 정적으로 생성되어야 할 컴포넌트가 불필요하게 동적으로 처리되어 성능에 영향을 미칠 수 있습니다.

import dynamic from 'next/dynamic';
import StaticComponent from './StaticComponent';

const DynamicPart = dynamic(() => import('./DynamicPart'), {
  ssr: false,
});

export default function Page() {
  return (
    <div>
      <h1>Page with Dynamic and Static Components</h1>
      <DynamicPart />
      <StaticComponent /> {/* 이 부분은 정적으로 렌더링됩니다. */}
    </div>
  );
}

위 코드에서 StaticComponent는 별도로 렌더링되기 때문에 정적으로 생성됩니다. 그러나 만약 StaticComponent가 DynamicPart 안에 포함된다면, StaticComponent도 동적으로 생성되어야 하므로, 성능에 불리하게 작용할 수 있습니다.

이러한 이유로 정적 컴포넌트와 동적 컴포넌트를 분리하여 관리하는 것이 Next.js에서 성능 최적화의 핵심입니다. 가능하면 정적 컴포넌트는 정적 렌더링을 유지하고, 동적 컴포넌트만 필요한 상황에서 동적으로 로드되도록 설계하는 것이 중요합니다.

 

■ 결론

Next.js는 기본적으로 SSR을 제공하지만, 상황에 따라 SSG를 자동으로 적용하여 성능을 최적화합니다. 이때 Next.js 서버는 SSR을 통해 새로 렌더링하지 않고, 빌드 시점에 생성된 정적 HTML 파일을 캐시에서 바로 제공하여 성능을 극대화합니다. 또한, ssr: false 옵션을 통해 클라이언트 측에서만 렌더링되어야 하는 컴포넌트를 효율적으로 관리할 수 있으며, 동적 컴포넌트와 정적 컴포넌트를 분리함으로써 최적의 성능을 유지할 수 있습니다.

이러한 최적화 전략을 활용하여 Next.js 애플리케이션을 더욱 효율적이고 빠르게 만들 수 있습니다.