본문 바로가기
React

React에서 서버 사이드 렌더링 구현하기

by 굿센스굿 2024. 12. 16.
반응형

 

React는 주로 클라이언트 사이드 렌더링(Client-Side Rendering, CSR)을 기반으로 동작하지만, SEO(검색 엔진 최적화) 및 초기 로딩 속도를 개선해야 하는 경우 서버 사이드 렌더링(Server-Side Rendering, SSR)을 활용할 수 있습니다. 이 글에서는 React에서 서버 사이드 렌더링을 구현하는 방법과 관련 기술을 상세히 살펴보겠습니다.

1. 서버 사이드 렌더링이란?

서버 사이드 렌더링(SSR)은 React 애플리케이션을 서버에서 렌더링하여 완전한 HTML을 클라이언트에 전달하는 방식입니다. 이 방식은 사용자가 브라우저에서 초기 페이지 로딩 시 바로 콘텐츠를 확인할 수 있게 하며, 검색 엔진이 콘텐츠를 더 쉽게 크롤링할 수 있도록 돕습니다.

SSR의 주요 장점

  1. SEO 최적화: HTML에 콘텐츠가 포함되어 있어 검색 엔진이 페이지를 크롤링하기 쉽습니다.
  2. 빠른 초기 로딩: 사용자에게 완성된 HTML이 전달되므로 초기 화면이 빠르게 표시됩니다.
  3. 소셜 미디어 미리보기 개선: Open Graph 태그 등의 메타 정보가 포함된 HTML을 제공할 수 있어 공유 시 미리보기가 잘 작동합니다.

SSR의 단점

  1. 서버 부하 증가: 클라이언트에서 처리하던 렌더링 작업이 서버에서 처리되므로 서버 부하가 늘어납니다.
  2. 구현 복잡성 증가: 데이터 패칭, 상태 관리 등이 추가로 요구됩니다.

2. React에서 SSR 구현을 위한 준비

React에서 SSR을 구현하려면 아래 기술 스택 및 도구를 사용합니다:

  • Node.js: 서버 환경 제공
  • Express.js: 서버 구성 및 라우팅
  • ReactDOMServer: 서버에서 React 컴포넌트를 렌더링하기 위한 메서드 제공
  • Webpack: 번들링 도구 (선택 사항)

필수 패키지 설치

SSR을 구현하기 위해 필요한 패키지를 설치합니다:

npm install react react-dom express react-dom/server

3. SSR 구현 단계

(1) Express 서버 구성

Express를 사용해 기본적인 서버를 설정합니다. 서버는 클라이언트 요청에 따라 React 애플리케이션을 렌더링하고 HTML을 반환합니다.

const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const App = require('./App');

const app = express();
const PORT = 3000;

// 정적 파일 서빙
app.use(express.static('public'));

// React 애플리케이션 렌더링
app.get('*', (req, res) => {
    const appHTML = ReactDOMServer.renderToString(React.createElement(App));

    const html = `
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>React SSR Example</title>
        </head>
        <body>
            <div id="root">${appHTML}</div>
            <script src="/bundle.js"></script>
        </body>
        </html>
    `;

    res.send(html);
});

app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

(2) React 애플리케이션 작성

기본 React 컴포넌트를 작성합니다. 이 컴포넌트는 서버와 클라이언트 모두에서 렌더링될 수 있습니다.

// App.js
const React = require('react');

function App() {
    return (
        <div>
            <h1>React 서버 사이드 렌더링</h1>
            <p>이 페이지는 서버에서 렌더링되었습니다.</p>
        </div>
    );
}

module.exports = App;

(3) Webpack을 통한 번들링 (선택 사항)

React 애플리케이션을 브라우저에서 실행하기 위해 Webpack을 사용해 클라이언트용 번들을 생성합니다.

Webpack 설정 파일 작성

// webpack.config.js
const path = require('path');

module.exports = {
    entry: './index.js',
    output: {
        path: path.resolve(__dirname, 'public'),
        filename: 'bundle.js',
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                exclude: /node_modules/,
                use: 'babel-loader',
            },
        ],
    },
    resolve: {
        extensions: ['.js', '.jsx'],
    },
};

Babel 설정 파일 작성

React 코드를 컴파일하기 위해 Babel 설정을 추가합니다:

{
    "presets": ["@babel/preset-env", "@babel/preset-react"]
}

4. 서버와 클라이언트 통합

서버에서 렌더링된 HTML은 클라이언트에서 React 애플리케이션과 결합되어야 합니다. 이를 위해 React의 hydrate 메서드를 사용합니다.

// index.js (클라이언트 엔트리 포인트)
const React = require('react');
const ReactDOM = require('react-dom');
const App = require('./App');

ReactDOM.hydrate(
    React.createElement(App),
    document.getElementById('root')
);

hydrate는 서버에서 렌더링된 HTML과 클라이언트의 React 상태를 연결합니다.

5. 데이터 패칭과 SSR

SSR에서 데이터 패칭은 중요한 고려 사항입니다. 데이터가 준비되기 전에 HTML을 렌더링하면 빈 콘텐츠가 전달될 수 있습니다. 이를 방지하려면 서버에서 데이터를 미리 가져오고, 렌더링 시 해당 데이터를 React 컴포넌트에 전달해야 합니다.

데이터 패칭 구현 예제

// 서버에서 데이터 가져오기
app.get('*', async (req, res) => {
    const data = await fetchData(); // 서버에서 데이터 요청
    const appHTML = ReactDOMServer.renderToString(
        React.createElement(App, { data })
    );

    const html = `
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>React SSR with Data</title>
        </head>
        <body>
            <div id="root">${appHTML}</div>
            <script>window.__INITIAL_DATA__ = ${JSON.stringify(data)}</script>
            <script src="/bundle.js"></script>
        </body>
        </html>
    `;

    res.send(html);
});

클라이언트에서 초기 데이터를 받아 사용하는 코드는 다음과 같습니다:

const data = window.__INITIAL_DATA__;
ReactDOM.hydrate(
    React.createElement(App, { data }),
    document.getElementById('root')
);

6. 결론

React에서 서버 사이드 렌더링을 구현하면 SEO와 초기 로딩 속도를 대폭 개선할 수 있습니다. 위에서 설명한 단계를 따라 기본적인 SSR 구조를 설정하고, 데이터 패칭 등 고급 기능을 추가하여 더욱 효율적인 애플리케이션을 구축해보세요.

반응형