1. Create React App (CRA) ← Only CSR


 

  • "Create React apps with no build configuration."
  •  
  • 아무런 초기 설정 없이도 CRA를 통해 React 기반의 SPA 사이트를 구현할 수 있게 됨.
    • (과장 조금 보태서) 터미널에 npx create-react-app my-app, npm run build 명령어 만으로 사이트 하나를 만드는 것이 가능.
    • webpack, babel 등 복잡한 세팅을 거치지 않아 React 기반 웹 프로젝트 확산에 큰 기여.
  • 그런데 얼마 간 시간이 지나면서 조금씩 이상한 점이 드러나기 시작.
    • "우리 사이트가 검색에 너무 안 걸리는걸?"
    • 원인) CRA로 build한 프로젝트는 Only CSR(Client Side Render)로 실행되기 때문.
  • CSR (Client Side Rendering)
    • 웹 페이지의 렌더링이 클라이언트(브라우저) 측에서 일어나는 것을 의미.
    • 브라우저는 최초 요청에서 html, js, css 확장자의 파일을 차례로 다운로드.
    • 최초로 불러온 html의 내용은 비어있음. (html, body 태그만 존재)
    • js 파일의 다운로드가 완료된 다음, 해당 js 파일이 dom을 빈 html 위에 그리기 시작.
    • 백엔드 호출을 최소화 할 수 있음
      • 최초 호출 때만 html, js, css를 요청
      • 이후에는 화면에서 변화가 일어나야 하는 만큼의 데이터만 요청 (ex. JSON)
    • 라우팅(새로운 페이지로 이동)을 하더라도 html 자체가 바뀌는 것이 아니라 JavaScript 차원에서 새로운 화면을 그려내는 것!

 

 

 

2. SEO (Search Engine Optimization)


 

  • 하지만 웹 크롤러 입장에서 CSR로 구성된 페이지에 접속하는 시나리오를 재구성해보자.
  • 웹 크롤러가 각 사이트를 돌아다니며 조사를 하는 상황이라고 가정.

CSR

  • 똑똑똑~
  • (끼익) ← 문이 열린다 (페이지 요청)
  • (빈 집) ← 첫 페이지
  • (조사 못하고 구글봇 퇴장)
  • (js 파일 다운로드 되며 페이지 로드) ← 뒷북
  • ⇒ 검색 노출 안 됨 

SSR

  • 똑똑똑~
  • (끼익) ← 문이 열린다 (페이지 요청)
  • (주인이 웹 크롤러를 맞이하며) "구글봇님 어서오세요. 저희 사이트는..." ← 첫 페이지
  • (조사를 마친 구글봇 퇴장)
  • ⇒ 검색 노출 됨 
  • CRA로 신나게 만들었던 페이지들이 검색 노출이 잘 안된다는 (충격적인) 사실이 알려지면서, SEO에 민감한 커머스 등의 비즈니스 영역은 대안을 찾아야 하는 상황.
    • "SPA의 장점을 살리면서 SEO도 같이 챙길 수는 없을까?"
    • ⇒ SSR (Server Side Rendering)

 

 

 

3. SSR (Server Side Rendering)


 

  • 위에서 언급했던 CSR과 SSR의 차이에서 알 수 있듯, SSR은 서버에서 첫 페이지의 렌더링을 클라이언트 측이 아닌 서버 측에서 처리해주는 방식.
  • CSR과 비교하면,
    • 1) UX 측면에서 유리
      • CSR에 비해 페이지를 구성하는 속도는 늦어질 수 있지만, 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점은 빨라진다.
      • Code Splitting?
        • 만약 첫 페이지 구성에 불필요한 JS 파일을 받아온다면?
        • 그 번들 파일의 크기가 크다면?
        • 불필요한 내용들은 받아오지 않고 서버 단에서 첫 페이지에 필요한 정적인 부분만 처리한 뒤 JS는 나중에 필요한 부분만 필요할 때 로드할 수 있다면?
    • 2) SEO 측면에서 유리
      • 서버에서 사용자에게 보여줄 페이지를 모두 구성하여 사용자에게 보여주는 방식이기 때문에 CSR의 단점인 "첫 페이지 깡통" 상태를 극복할 수 있음.
    • 주의) 페이지를 잘못 구성할 경우 CSR에 비해 서버 부하가 커지거나 / 첫 로딩이 매우 느려질 수 있음

 

 

 

 

 

4. SPA for SSR


 

SSR for MPA, SSR for SPA...?

  • 이쯤 되면 고개가 또 다시 갸우뚱 해진다. 🤔
  • "2세대 웹의 JSP, PHP, Django Template 같은 것들 역시 SSR이 아니었나요?" ⇒ 맞습니다! ✅
  • "그러면 CSR의 한계를 극복하기 위해 웹이 2세대 기술로 돌아가고 말았나요?" ⇒ 아니에요! 🚫
  • "SPA랑 CSR이랑 같은 의미 아니었나요?" ⇒ 아니에요! 🚫
  • 우리가 지금 얘기해볼 SSR은 SSR for SPA
  • SPA(결과물) / CSR, SSR (렌더링 방법)로 나누어 이해하면 좋음.

 

 

 

5. CSR + SSR?


  • 그렇다면 SSR과 CSR을 섞어 쓸 수는 없나요
  • 사용할 수 있다!
  • 1) 첫 렌더 SSR
  • 2) 그 이후 렌더 부터는 CSR

 

 

:: 원리 & 구조

 

  • SSR은 다음과 같은 요소로 구성된다
    • node.js로 구성된 FE 서버
    • pyhton, django로 되어 있는 BE 서버

 

  • 다음과 같은 과정을 거쳐 SSR이 진행된다 (링크)
    1. 유저가 브라우저에 **/**를 입력.
    2. 미리 실행되고 있는 FE 서버가 요청을 받고 서버사이드 렌더링.
    3. 만들어진 html 을 브라우저에게 보냄.
    4. 브라우저가 응답받은 html 을 그림.
    5. html 에 기능을 부여할 **index.js**파일을 다운로드 받음. (hydration)
    6. 다운로드가 완료된 이후, go to second 링크를 클릭.
    7. **/second**로 라우팅하고 second 페이지 코드를 생성.
    8.  

:: 예제 코드

import React from "react";
import ReactDom from "react-dom";
import App from "./App";

const initialData = window.__INITIAL_DATA__;

ReactDom.hydrate(
  <App page={initialData?.page} />,
  document.getElementById("root")
);
// 출처: <실전 리액트 프로그래밍>, 이재승 저

index.js

 

 

hydration

  • 서버에서 전송한 정적 문서를 데이터 변경에 반응할 수 있는 동적 형태로 변환하는 클라이언트 측 프로세스를 말한다.
  • render와 동일하지만, dom은 이미 그려져 있는 상태이기 때문에 event listener만 부착하는 식으로 작동.

 

<!DOCTYPE html>
<html>
  <head>
    <title>ssr test</title>
    <script type="text/javascript">
      window.__INITIAL_DATA__ = __DATA_FROM_SERVER__;
    </script>
		__STYLE_FROM_SERVER__
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

index.html

 

import express from "express";
import fs from "fs";
import path from "path";
import * as url from "url";
import { renderToString } from "react-dom/server";
import React from "react";
import { ServerStyleSheet } from "styled-components";
import App from "./App";

const app = express();
const html = fs.readFileSync(
  path.resolve(__dirname, "../dist/index.html"),
  "utf8"
);
app.use("/dist", express.static("dist"));

app.get("favicon.ico", (req, res) => res.sendStatus(204));
app.get("*", (req, res) => {
  const parsedUrl = url.parse(req.url, true);
  const page =
    parsedUrl.pathname && parsedUrl.pathname !== "/"
      ? parsedUrl.pathname.substr(1)
      : "home";

  const sheet = new ServerStyleSheet();
  const renderString = renderToString(sheet.collectStyles(<App page={page} />));
  const styles = sheet.getStyleTags();

  const initialData = { page };
  const result = html
    .replace('<div id="root"></div>', `<div id="root">${renderString}</div>`)
    .replace("__DATA_FROM_SERVER__", JSON.stringify(initialData)) // head script에 server 측 주입
    .replace("__STYLE_FROM_SERVER__", styles); // head script에 데이터 주입

  res.send(result);
});

app.listen(3000);

server.js

 

 

 

 

6. Next.js


 

  • 생산성을 위해 Next.js가 주로 채택됨 
 

Next.js by Vercel - The React Framework

Production grade React applications that scale. The world’s leading companies use Next.js by Vercel to build static and dynamic websites and web applications.

nextjs.org

 

  ◦ SSR의 CRA, 간단히 구성 가능

  ◦원티드, 토스, 배민, 카카오커머스 등 사용 중

 

import React from "react";
import Link from "next/link"; // next/link 사용하여 라우팅 -> CSR 동작

export default function About({ data }) {
  return (
    <div>
      <Link href="/">about</Link> {data}
    </div>
  );
}

About.getInitialProps = function () {
  return { data: "data" };
};

 

 

    1. 첫 페이지를 "/"로 호출했을 때 페이지 자체가 SSR 후 HTML 파일로 완성되어 돌아옴
    1. 1번 이후 Link 컴포넌트를 사용하여 라우팅을 하면 CSR이 이뤄지고 서버로부터 about.js만 새로 받아온 뒤 화면을 그리게 됨
    2.  (전부 CSR로 할 땐 js를 한 번에 다운로드 받습니다. 그래서 about.js를 추가적으로 다운받지 않습니다. 서버에서 추가적으로 about.js를 다운받는건 SSR이후 CSR을 하기 위해서입니다.)
    3.  
    4. 2번에서 CSR로 이동했던 "/about" 페이지를 첫 호출로 불러오게 되면 아까는 CSR로 불러와졌던 페이지가 SSR로 호출되었음을 확인할 수 있음 (about.html)

 

 

장점

  • SSR 외에도 React App에 필요한 여러가지 필수 기능들을 제공하는 Framework 역할
    • 페이지 기반 라우팅 시스템 (동적 라우팅 지원)
    • pre-rendering , 페이지별 정적파일 생성과 서버사이드 렌더링 지원
    • 코드 스플리팅
    • CSS, Sass 기본 지원 및 다른 CSS-in-JS 라이브러리 지원 
    • 등등...

 

 

 


추가자료 (SSR CSR 상세동작 순서)

 

[CS / Q] SSR CSR의 상세동작 순서, node.js (window객체)

1. SSR, CSR의 상세동작 순서 더보기 1-1. SSR의 동작 순서 Server Side Rendering의 약자. 서버쪽에서 렌더링 준비를 끝마친 상태로 클라이언트에 전달하는 방식이다. 1. User가 Website 요청을 보냄. 2. Server..

higher77.tistory.com

 

 

Reference

https://workatit.tistory.com/m/74

 

 

 

+ Recent posts