카테고리 없음

Server Side Rendering(SSR) with Next.js

김 정출 2024. 9. 29. 11:18

Server Side Rendering(SSR)

Server Side Rendering(SSR)은 웹 페이지를 사용자의 브라우저가 아닌 서버에서 렌더링하는 방식입니다. 전통적인 웹 애플리케이션 방식으로, 클라이언트가 페이지를 요청하면 서버가 HTML을 렌더링하고, 이 완성된 HTML을 브라우저에 전달하는 방식입니다. 이와 반대되는 방식이 클라이언트 측 렌더링(Client-Side Rendering, CSR)으로, 브라우저에서 JavaScript를 실행해 동적으로 페이지를 구성하는 방식입니다.

SSR의 주요 특징과 장점을 살펴보면 다음과 같습니다:

1. SEO(검색 엔진 최적화) 향상

SSR 방식은 서버에서 완성된 HTML 페이지를 즉시 제공하기 때문에, 검색 엔진 크롤러가 페이지 내용을 쉽게 읽고 인덱싱할 수 있습니다. CSR 방식에서는 JavaScript가 실행되어야 페이지가 완성되므로, 크롤러가 이를 제대로 처리하지 못해 SEO가 떨어질 수 있습니다.

2. 빠른 초기 로드

클라이언트가 페이지를 요청할 때 서버에서 이미 렌더링된 HTML을 전달하므로, 초기 로드 속도가 빠릅니다. 특히 네트워크가 느린 환경에서는 SSR이 더 빠른 사용자 경험을 제공합니다. CSR 방식에서는 사용자가 페이지를 보려면 브라우저가 JavaScript 파일을 다운로드하고 실행한 후에야 화면이 렌더링되기 때문에 초기 로딩이 지연될 수 있습니다.

3. 콘텐츠의 미리 렌더링

SSR에서는 서버에서 모든 콘텐츠를 완성한 후 사용자의 브라우저로 보내므로, 브라우저가 별도로 JavaScript를 실행하지 않아도 콘텐츠를 즉시 볼 수 있습니다. 이는 특히 초기 데이터가 중요한 페이지(예: 블로그 포스트, 뉴스 기사 등)에 적합합니다.

4. 복잡한 상태 관리 필요성 감소

서버에서 페이지를 렌더링하고 HTML을 전달하는 과정에서 대부분의 데이터와 상태가 이미 반영되어 있기 때문에, 클라이언트 측에서 복잡한 상태 관리를 크게 줄일 수 있습니다.


SSR의 단점

SSR은 장점도 많지만, 몇 가지 단점도 존재합니다.

  1. 서버 부하 증가: 모든 페이지 요청에 대해 서버에서 HTML을 렌더링하기 때문에, 서버에 더 많은 부하가 발생합니다.
  2. 상호작용성 문제: 페이지가 처음 로드될 때는 서버에서 완성된 HTML이 제공되지만, 이후의 동적인 상호작용(예: 버튼 클릭 등)을 위해 여전히 JavaScript가 필요합니다. 이를 위해 하이드레이션(hydration)이라는 과정이 필요하며, 이 과정에서 성능 저하가 발생할 수 있습니다.
  3. 복잡한 캐싱 전략: 클라이언트 측에서의 캐싱보다 서버 측 캐싱이 복잡할 수 있으며, 각 페이지별로 캐싱 전략을 잘 설계해야 합니다.

SSR과 CSR 비교

SSR (Server Side Rendering) CSR (Client Side Rendering)

서버에서 HTML을 렌더링하여 전달 클라이언트에서 JavaScript로 HTML 생성
SEO에 유리 SEO 최적화에 불리
초기 로딩 속도 빠름 초기 로딩 속도 느림 (JS 다운로드 및 실행 필요)
서버 부하가 큼 클라이언트 부하가 큼
즉시 콘텐츠 표시 콘텐츠가 늦게 표시될 수 있음

SSR을 사용하는 프레임워크

SSR을 구현하기 위해서는 서버에서 JavaScript를 실행할 수 있는 환경이 필요합니다. 아래는 SSR을 지원하는 대표적인 프레임워크들입니다:

  • Next.js: React 기반의 프레임워크로, CSR과 SSR을 모두 지원하며, 페이지 별로 어떤 방식을 사용할지 선택할 수 있습니다.
  • Nuxt.js: Vue.js 기반의 프레임워크로, SSR을 쉽게 설정하고 사용할 수 있습니다.
  • Angular Universal: Angular 애플리케이션에서 SSR을 지원하는 도구입니다.

SSR은 사용자 경험과 SEO 최적화를 위해 중요한 기술이지만, 서버 자원의 효율적인 사용과 성능 최적화를 위해 적절한 상황에서 선택적으로 사용해야 합니다.

Server Side Rendering(SSR)을 서버단에서 자바스크립트와 비슷한 언어로 구현하는 예시를 원하신다면, Node.js를 사용한 SSR 구현이 가장 적절한 예시입니다. Node.js는 자바스크립트 기반 서버 환경이기 때문에 자바스크립트와 거의 동일한 방식으로 SSR을 구현할 수 있습니다.

아래 예시는 Node.js 환경에서 Express.jsEJS(Embedded JavaScript) 템플릿 엔진을 사용하여 SSR을 구현한 간단한 코드입니다. 이 코드는 서버에서 데이터를 받아와 템플릿을 렌더링하여 HTML을 클라이언트에게 전송하는 방식입니다.

Node.js를 이용한 SSR 구현 예시

1. Node.js 프로젝트 설정

먼저, Node.js 프로젝트를 초기화하고 필요한 패키지를 설치합니다.

# 프로젝트 폴더 만들기
mkdir ssr-example
cd ssr-example

# Node.js 프로젝트 초기화
npm init -y

# Express.js 및 EJS 설치
npm install express ejs

2. 서버 코드 작성 (SSR 구현)

이제 서버 코드를 작성하여 SSR을 구현합니다. index.js 파일을 만들어 아래와 같이 작성합니다.

// index.js
const express = require('express');
const app = express();
const port = 3000;

// EJS 템플릿 엔진 설정
app.set('view engine', 'ejs');
app.set('views', './views');

// 가상의 데이터
const data = {
  title: 'Server Side Rendering Example',
  message: 'This page is rendered on the server with EJS!',
  users: [
    { name: 'John', age: 30 },
    { name: 'Jane', age: 25 },
    { name: 'Doe', age: 22 }
  ]
};

// SSR을 구현한 라우팅
app.get('/', (req, res) => {
  // 서버에서 데이터를 처리하고 템플릿을 렌더링한 후 클라이언트에게 전달
  res.render('index', { data: data });
});

// 서버 실행
app.listen(port, () => {
  console.log(`Server is running on <http://localhost>:${port}`);
});

3. 템플릿 작성

서버에서 렌더링될 HTML 템플릿 파일을 작성합니다. views/index.ejs 파일을 만들어 다음과 같이 작성합니다.

<!-- views/index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%= data.title %></title>
</head>
<body>
    <h1><%= data.message %></h1>

    <h2>User List</h2>
    <ul>
        <% data.users.forEach(user => { %>
            <li><%= user.name %> (Age: <%= user.age %>)</li>
        <% }); %>
    </ul>
</body>
</html>

4. 서버 실행 및 확인

모든 준비가 완료되었으면 서버를 실행하여 SSR을 확인할 수 있습니다.

node index.js

이제 브라우저에서 http://localhost:3000으로 접속하면 서버에서 렌더링된 HTML이 표시됩니다. 여기서 데이터를 서버에서 받아와 렌더링한 결과가 클라이언트에 전달됩니다.


이 코드의 흐름

  1. Express.js 서버: Express는 웹 서버를 설정하고 요청을 처리합니다.
  2. EJS 템플릿 엔진: EJS를 사용해 HTML 템플릿에 데이터를 삽입하고 서버에서 렌더링된 HTML을 생성합니다.
  3. SSR 구현: 클라이언트가 http://localhost:3000/으로 요청을 보내면, 서버는 데이터를 처리하고 해당 데이터를 EJS 템플릿에 삽입하여 HTML 파일을 생성한 후 클라이언트로 전달합니다.
  4. 클라이언트는 서버에서 완성된 HTML을 전달받아 바로 표시하게 됩니다. 즉, 클라이언트는 추가적인 JavaScript 실행 없이 완성된 페이지를 볼 수 있습니다.

SSR의 작동 방식 요약

  • 서버 요청 처리: 클라이언트가 페이지 요청을 보내면 서버에서 해당 페이지를 처리합니다.
  • 서버 렌더링: 서버에서 필요한 데이터를 가져와 HTML을 동적으로 생성합니다.
  • HTML 전달: 완성된 HTML을 클라이언트에게 반환하여 브라우저에 바로 표시됩니다.

이 방식은 전형적인 SSR 패턴으로, SEO가 중요한 웹사이트나 빠른 초기 페이지 로딩이 필요한 경우에 유용합니다.

Next.js

Next.js는 React를 기반으로 한 서버 사이드 렌더링(SSR)을 쉽게 구현할 수 있는 프레임워크입니다. Next.js는 SSR과 함께 정적 생성(SSG) 및 클라이언트 측 렌더링(CSR)도 지원하므로 다양한 웹 애플리케이션 요구 사항을 충족할 수 있습니다.

아래는 Next.js를 사용하여 SSR을 구현하는 간단한 예시입니다. 이 예시는 서버에서 데이터를 가져와 페이지를 렌더링하는 방식으로 동작합니다.

1. Next.js 프로젝트 설정

먼저 Next.js 프로젝트를 설정하고 필요한 패키지를 설치합니다.

# Next.js 프로젝트 생성
npx create-next-app ssr-example
cd ssr-example

# 의존성 설치
npm install

2. SSR 구현을 위한 페이지 작성

Next.js는 기본적으로 pages 폴더에 파일을 추가하면 해당 파일 이름에 맞는 경로로 페이지가 자동으로 생성됩니다. pages/index.js 파일을 수정하여 SSR을 구현하겠습니다.

// pages/index.js
import React from 'react';

// 메인 컴포넌트 정의
const Home = ({ data }) => {
  return (
    <div>
      <h1>{data.title}</h1>
      <p>{data.message}</p>

      <h2>User List</h2>
      <ul>
        {data.users.map((user, index) => (
          <li key={index}>
            {user.name} (Age: {user.age})
          </li>
        ))}
      </ul>
    </div>
  );
};

// getServerSideProps 함수는 서버 측에서 데이터를 가져오고 렌더링 전에 실행됩니다.
export async function getServerSideProps() {
  // 가상의 데이터를 서버에서 생성
  const data = {
    title: 'Next.js Server Side Rendering Example',
    message: 'This page is rendered on the server using Next.js!',
    users: [
      { name: 'John', age: 30 },
      { name: 'Jane', age: 25 },
      { name: 'Doe', age: 22 }
    ]
  };

  // props로 전달할 데이터를 반환
  return {
    props: { data }, // 페이지 컴포넌트에 전달되는 데이터
  };
}

export default Home;

3. SSR이 동작하는 방식

  • getServerSideProps 함수: 이 함수는 Next.js에서 서버 사이드 렌더링을 위한 중요한 부분입니다. 페이지가 요청될 때마다 서버 측에서 실행되며, 데이터를 가져오고 그 데이터를 페이지 컴포넌트에 전달하여 렌더링합니다.
  • 서버에서의 데이터 처리: 이 예시에서는 서버에서 간단한 사용자 데이터를 생성하여 클라이언트에 전달하고 있습니다. 실제 환경에서는 API 호출 등을 통해 서버에서 데이터를 가져오는 로직을 포함할 수 있습니다.

4. 프로젝트 실행

SSR이 구현된 Next.js 프로젝트를 실행해 봅니다.

npm run dev

서버가 실행되면 브라우저에서 http://localhost:3000에 접속할 수 있습니다. 페이지가 로드될 때마다 서버에서 데이터를 처리하여 HTML을 렌더링하고, 브라우저에 해당 HTML이 전송됩니다.


SSR 흐름 설명

  1. 클라이언트 요청: 클라이언트가 http://localhost:3000 페이지에 접근하면, Next.js 서버가 요청을 받습니다.
  2. 서버 측 데이터 처리: getServerSideProps 함수가 실행되어 서버 측에서 데이터를 가져옵니다.
  3. 서버 렌더링: 가져온 데이터를 기반으로 React 컴포넌트를 서버에서 HTML로 렌더링합니다.
  4. HTML 전송: 서버에서 렌더링된 HTML이 클라이언트로 전송됩니다.
  5. 클라이언트 렌더링: 클라이언트에서 서버에서 제공한 HTML을 받아 화면에 표시하고, 이후 React가 하이드레이션(hydration) 과정을 통해 상호작용이 가능하게 만듭니다.

5. 주요 기능 요약

  • getServerSideProps: 서버 사이드 렌더링을 위해 페이지 요청 시마다 데이터를 서버에서 받아올 수 있도록 하는 Next.js의 API.
  • SSR: 데이터를 서버에서 미리 받아와 페이지를 렌더링하고 클라이언트로 전송하여 SEO 및 초기 로딩 성능을 향상시킵니다.

Next.js의 SSR 장점

  1. SEO 최적화: 페이지가 서버에서 렌더링되어 검색 엔진이 내용을 쉽게 크롤링할 수 있습니다.
  2. 빠른 초기 로딩: 클라이언트가 완성된 HTML을 받아오므로 첫 로딩이 빠릅니다.
  3. React 생태계 사용: Next.js는 React를 기반으로 하므로 기존 React 프로젝트에 쉽게 통합할 수 있고, React의 강력한 컴포넌트 기반 개발 방식을 사용할 수 있습니다.

Next.js는 복잡한 SSR을 손쉽게 구현할 수 있는 강력한 프레임워크로, SSR 외에도 정적 사이트 생성(SSG) 및 클라이언트 측 렌더링(CSR)도 지원하여 다양한 요구를 만족시킬 수 있습니다.