Published on

14단계: Node.js 기반 유니버설 자바스크립트

14-1. 유니버설 자바스크립트란?

React 코드를 브라우저뿐만 아니라 서버(Node.js)에서도 실행 가능한 구조입니다. 이를 통해 초기 렌더링을 서버에서 처리하여 SEO와 성능을 개선할 수 있습니다.


14-2. 서버사이드 렌더링(SSR)의 장점

  • 초기 페이지 로딩 속도 개선
  • 검색엔진(SEO)에 유리
  • 소셜미디어에서 미리보기 메타 태그 노출 가능

14-3. ReactDOMServer 사용

import { renderToString } from 'react-dom/server';
import App from './App';

const html = renderToString(<App />);

브라우저가 HTML을 먼저 받고 이후 hydrate로 상호작용을 이어갑니다.


14-4. Express 서버 구성 예시

import express from 'express';
import { renderToString } from 'react-dom/server';
import App from './App';
import fs from 'fs';

const app = express();

app.use(express.static('dist'));

app.get('*', (req, res) => {
  const html = renderToString(<App />);
  const template = fs.readFileSync('./dist/index.html', 'utf8');
  res.send(template.replace('<div id="root"></div>', `<div id="root">${html}</div>`));
});

app.listen(3000);

14-5. hydrate 사용

import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById("root"), <App />);

hydrate는 클라이언트에서 서버에서 렌더링된 DOM을 takeover하면서 React 이벤트와 상태를 연결합니다.


14-6. 초기 데이터 처리 방식

서버 측에서 데이터를 먼저 받아 React에 전달하려면 HTML에 데이터를 삽입해 클라이언트에서 읽어야 합니다.

<script>
  window.__INITIAL_STATE__ = ${JSON.stringify(data)};
</script>

14-7. Next.js 소개

Next.js는 React 기반의 SSR과 정적 생성 기능을 기본으로 제공하는 프레임워크입니다. 직접 SSR 구현보다 훨씬 생산성을 높여줍니다.


요약

  • 유니버설 자바스크립트는 브라우저와 서버 양쪽에서 React 실행
  • renderToString으로 HTML 생성, hydrate로 클라이언트 기능 연결
  • 초기 데이터 전달, Express 서버 구성, 정적 템플릿 대체 등으로 SSR을 구현
  • Next.js를 활용하면 직접 구현 없이 쉽게 SSR을 적용할 수 있음

심화학습

Q1. 클라이언트 렌더링과 SSR의 가장 큰 차이점은 무엇인가요?
A1. 클라이언트 렌더링은 빈 HTML로 시작해 JS가 DOM을 만들고, SSR은 완성된 HTML이 먼저 전달되어 초기 로딩이 빠릅니다.


Q2. renderToString과 hydrate는 왜 함께 써야 하나요?
A2. renderToString은 서버에서 HTML을 렌더링하고, hydrate는 그 HTML을 React가 takeover하여 interactivity를 부여합니다.


Q3. SSR에서 동적 데이터를 처리할 때 가장 주의할 점은 무엇인가요?
A3. 서버와 클라이언트의 렌더링 결과가 달라지면 hydration mismatch가 발생할 수 있으므로 데이터 동기화를 신중히 처리해야 합니다.