CSR & SSR

sxungchxn.dev·2022년 6월 17일
3

Frontend

목록 보기
1/7
post-custom-banner

이번 포스트에서는 프론트엔드의 대표적인 렌더링 방식인 CSR(Client Side Renering)SSR(Server Side Rendering)에 특징과 어떤 시기에 사용해야 가장 좋은지에 알아보겠다.


📄 페이지 구성 방식 - SPA, MPA

본격적인 렌더링 방식을 알아보기 전에 웹어플리케이션을 페이지 구성 방식에 따라 크게 두가지로 나누어볼 수 있다.

SPA(Single Page Application)

페이지 변경 없이 하나의 페이지 안에서 어플리케이션이 구동되는 방식 - ex) React, Vue, Angular

MPA(Multi Page Application)

사용자에 상호작용에 따라 여러개의 페이지가 제공되는 웹어플리케이션 - ex) php, JSP

이러한 웹어플리케이션은 각자의 특징때문에 과거에는 각자에게 필요한 렌더링 방식을 사용해야했다. 나중에 제대로 설명할 것이지만 렌더링 방식은 크게 3가지로 아래와 같은데,

  • CSR - Client Side Rendering : 클라이언트 측에서 렌더링을 하는 방식
  • SSR - Server Side Rendering : 서버 측에서 렌더링을 하는 방식
  • SSG - Static Site Generation : 빌드 타임에 미리 리소스들을 정적으로 생성하는 방식

이러한 렌더링 방식과 결합시켜 아래와 같은 구성으로 웹어플리케이션을 구성하였다.

App 구성 #1App 구성 #2
페이지 구성 방식SPAMPA
렌더링 방식CSRSSR

하지만, 최근들어 다양한 기술들과 프레임워크가 등장하면서부터는 SPA 상에서도 SSR을 구성할 수 있게되었다. 지금까지 웹어플리케이션의 페이지 구성방식에 대해 알아봤다면 이제부터는 정말로 렌더링 방식에 대해 알아볼 차례이다.



🕹 CSR의 동작 과정과 특징

CSR은 클라이언트 측에서 리소스를 다운로드 받아 직접 렌더링에 관여하는 방식인데 다음의 특징들을 가진다.

  • JS 다운로드 후 브라우저 측에서 동적 DOM 생성하고 나서야 렌더링이 완료되기 때문에 초기 로딩속도가 매우 느리다. 다만, 모든 요소가 다운로드 된 후 렌더링이 진행되기에 화면 깜빡임은 없다.
  • 첫 렌더링 이후에는 일부 요소 변경 시 해당되는 리소스만 요청하면 되기 때문에 초기 로딩을 제외한 나머지 시기의 구동 속도는 매우 빠르다.
  • 빈 뼈대 HTML과 JS경로를 제공하는 것 외에는 하는일이 없어 서버 측 부하는 다소 적다.
  • 웹 크롤러 입장에서는 인덱싱 과정에서 빈뼈대 HTML을 읽어드리기 때문에 적절한 색인 작업이 불가능하다. 이는 검색어 상단에 노출시키도록 하는 작업인 검색엔진최적화(SEO)에 불리하다.

대표적으로 React 라이브러리를 이용한다면 아래와 같이 useEffect 훅을 이용해서 렌더링에 필요한 데이터를 백엔드로부터 불러오는 것이 대표적인 예이다.

useEffect(() => {
    axios
      .get('https://worldtimeapi.org/api/ip')
      .then((res) => {
        setDateTime(res.data.datetime);
      })
      .catch((error) => console.error(error));
  }, []);


📡 SSR의 동작 과정과 특징

SSRCSR 과 달리 서버가 HTML 뼈대와 JS 링크를 주는 것에 그치지 않고 직접 HTML페이지와 관련된 JS파일을 실행시켜 완성된 HTML과 브라우저 측에서 실행할 JS 파일링크를 넘기는 방식으로 렌더링을 진행한다. 이러한 SSR 방식은 다음의 특징들을 가진다.

  • 초기 렌더링시 HTML 뼈대만이 아니라 렌더링이 완료된 HTML과 이후 실행될 자바스크립트 코드가 제공되어 웹 크롤러 입장에서는 더 상세하게 인덱싱이 가능하여 SEO(검색엔진 최적화)에 매우 용이하다.

  • 이미 렌더링이 완료된 상태로 페이지가 제공되기 때문에 초기 구동속도가 빠르다. 다만, HTML과 관련된 JS 로직들이 모두 연결되기 전까지는 사용자의 상호작용이 불가능하다. 이러한 경우 TTV(Time To View) ≠ Time To Interact 인 상황이라고도 한다.

    • 참고로 SSR 과정에서 서버측에서 먼저 렌더링한 HTML 파일이 전송된 후 이후에 클라이언트 측에서 실행할 JS가 다운로드되어야 웹페이지가 인터렉션이 가능해지는데 이러한 과정을 Hydration 이라고 한다.
  • 또한 서버가 매 요청시 필요한 리소스를 직접 만들어야하기 때문에 서버에 과부하가 생길 수 있다. 이러한 경우, 사용자가 페이지 최초 진입시 페이지가 보여지는데 오랜시간이 걸릴수도 있다.

CSR과 SSR의 특징들을 정리하여 장점과 단점으로 분리하면 다음과 같다.

CSRSSR
장점화면 깜빡임(≠ 화면전환)이 없음
초기 로딩 이후 구동 속도 빠름
TTV와 TTI 사이 간극이 없음
TTV와 TTI 사이 간극이 없음
서버 부하 분산
초기 구동 속도가 빠름
SEO에 유리함
단점초기 로딩 속도 느림
SEO에 불리함
화면 깜빡임이 존재
TTV와 TTI 사이 간극 존재
서버 부하가 존재


🎱 CSR의 단점 개선

위에서 살펴보았던 CSR 단점들은 다음의 해결책들을 통해 어느정도 해소될 수 있다.

  • 초기 진입시 느린 로딩 속도 개선
    • Code-splitting - SPA는 초기 실행시에 필요한 웹 리소스를 다운받는 특징이 있다. 이를 해소하기 위해 일부 리소스들에 대해서 lazy loading 을 적용하여 한번에 다운로드 받지 않도록 하는 방법이 있다. 리액트에서는 React.lazySuspense 컴포넌트를 활용해 일부 리소스를 필요할 때 import 시킴으로써 최적화할 수 있다.
      const OtherComponent = React.lazy(() => import('./OtherComponent'));
      
      function MyComponent() {
        return (
          <div>
            <Suspense fallback={<div>Loading...</div>}>
              <OtherComponent />
            </Suspense>
          </div>
        );
      }
      Code splitting 에 대해서 자세하게 알아보고싶다면 아래를 참고하길 바란다. Code-Splitting(코드 스플릿팅)
    • Tree-shaking - 웹어플리케이션을 개발하다보면 다양한 모듈들을 설치해 사용하게 될텐데 이중에서 사용되지 않은 모듈들을 최대한 배제하는 기법이다. 나무를 흔들어서 죽은 나뭇잎들을 떨어뜨리는 데에서 유래 되었다고 한다.
      import * as util from '../utilFile';
      대표적으로 특정 파일에서 모듈을 위와 같은 방식으로 import 하게 될 경우, 사용하지 않는 모듈들도 같이 import 하게될텐데 이런식으로 불필요한 리소스가 누적되면 어플리케이션을 build 하면서 만들어지는 번들의 크기가 매우 커지게된다. 이로 인해 리소스를 로딩하는 시간을 지연시킬 수 있다. 이에 대한 자세한 설명은 아래를 참고하면 좋을것 같다. 웹 성능 최적화를 위한 Tree Shaking 소개
  • SEO 개선

    • 페이지 미리 렌더링함으로써 검색엔진에서 해당 웹어플리케이션을 인덱싱하기 용이하기 하면 SEO 가 잘 안되던 기존의 문제점을 해결할 수 있다. 이처럼 페이지가 미리 렌더링되도록 해놓는 작업을 Pre-rendering 이라고 한다.
  • SSR/SSG를 부분 도입

    • 렌더링의 부담을 모두 Client 측으로 돌리는 것이 아니라 일부 Server 측에게도 부여하는 방식이다. 이를 통해 초기 로딩 속도를 크게 감소시킬 수 있다. 또한 이를 도입하면 프리렌더링도 해줄 수 있어 SEO 개선도 가능하다. 이제부터는 SSR/SSG를 도입하는 방법에 대해서 알아보고자 한다.


🥏 CSR + SSR/SSG 도입 방법

  • 프레임워크 없이 도입 Express, Nest 등으로 백엔드 라이브러리를 이용해 별도의 서버를 운영하는 방법 : 진입장벽이 높고, 서버 환경 구성이 백엔드에 익숙하지 않은 프론트엔드 개발자에게는 다소 어렵다는 단점이 있어 실현되기 어렵다.
  • 프레임워크를 이용해 도입 프레임워크를 이용하면 쉽게 SSR/SSG를 도입할 수 있는데 프론트엔드 라이브러리 별로 도입할 수 있는 프레임워크는 다음과 같다.
    • React - NextJS, Gatsby

    • Angular - Universal

    • Vue - Nuxt

      대표적으로 NextJS 를 이용해 SSR를 할 경우 다음과 같은 방식으로 특정 페이지에 대하여 SSR을 진행할 수 있다. getServerSideProps 라는 함수가 프론트엔드 서버측에서 미리 실행되어 data를 패치한뒤 이를 페이지 컴포넌트의 props로 넘기는 방식이다.

      function Page({ data }) {
        // Render data...
      }
      
      // This gets called on every request
      export async function getServerSideProps() {
        // Fetch data from external API
        const res = await fetch(`https://.../data`)
        const data = await res.json()
      
        // Pass data to the page via props
        return { props: { data } }
      }
      
      export default Page

다만, 프레임워크를 사용하게되면 당여히 프레임워크에 대한 이해가 필요하여 러닝커브가 존재하고 코드 복잡도도 상승하게 된다는 단점이 있다.



🧐 CSR, SSR, Universal(CSR+SSR)의 선택 기준

지금까지 렌더링하는 방식들의 특징들과 도입방법들에 대해서 알아보았다. 각각의 장단점들이 있으니 상황에 맞게 사용하는 것이 중요하다. 각 렌더링 방식에 대하여 사용해야될 경우를 특정해보면 다음과 같다.

  • CSR이 선호되는 경우

    • 유저와의 상호작용이 많은 경우
    • 고객 개인 정보를 다뤄야 하는 페이지라 검색엔진 노출이 필요 없는 경우
  • SSG/SSR이 선호되는 경우

    • 회사 홈페이지 처럼 홍보가 필요해 검색어 입력시 상위페이지에 존재해야함(SEO 필요)
    • 누구에게나 동일한 내용 노출
    • 자주 업데이트가 이루어지는 페이지 ⇒ SSR
    • 자주 업데이트가 이루어지지 않는다 ⇒ SSG
  • Universal(CSR + SSR)이 선호되는 경우

    • 사용자에 따라서 페이지가 달라짐 ⇒ SSR/CSR를 적절히 혼용
    • 빠른 인터렉션이 중요한 경우 ⇒ 프리렌더링이 필요함 ⇒ SSR
    • 화면 깜빡임 X ⇒ 리소스를 다운받은 상태에서 렌더링이 이뤄져야함 ⇒ CSR
    • 검색어 상위 노출이 요구 ⇒ SEO 최적화 필요 ⇒ SSR

위의 내용을 참고하되 정해진 정답은 없으니 프로젝트의 상황에 맞게 렌더링 방식을 선택하는 것이 좋겠다.

🪢 같이 배워보면 좋은 키워드들

  • Code-splitting
  • Tree-shaking
  • SEO(Search Engine Optimization)
  • Hydration

🚩 출처 및 참고자료

[10분 테코톡] 🎨 신세한탄의 CSR&SSR

Client-Side v/s Server-Side Rendering: What to Choose When? - DZone Web Dev

Understanding Rendering in Web Apps: SPA vs MPA

profile
🏠 버튼을 누르면 더 많은 글들을 보실 수 있습니다
post-custom-banner

0개의 댓글