SPA, CSR, SSR과 Next.JS

GY·2022년 2월 14일
0

Basic CS

목록 보기
21/28
post-thumbnail

👉 SPA에서의 SSR과 CSR

기본적으로 SPA를 구성하는 방식이 CSR이다.

SPA가 무엇일까?

하나의 html파일로 여러 페이지를 구현하는 방식의 애플리케이션
HTML 태그를 자바스크립트가 동적으로 생성한다.

조금 더 자세히 얘기하면,

  • html 파일은 한 개만 존재한다.
  • npm run build 명령어로 빌드하면 html 파일이 하나만 생성된다.
  • 페이지를 이동했을 때
    의 내용을 자바스크립트가 동적으로 생성해 교체한다. 따라서 화면 깜빡임이 없다.

👉 CSR과 SSR의 차이점

1️⃣ CSR (Client Side Rendering)

웹 페이지의 렌더링이 클라이언트 측에서 일어나는 것

  • 최초 요청 시 브라우저는 html, js, css 파일을 차례로 다운로드 하는데, html의 내용은 비어있다.
  • js파일을 모두 다운로드 한 다음, 이 js파일이 DOM을 빈 html위에 그린다.

데이터를 유동적으로 호출해야 하지만 SEO가 필요없는 마이페이지, 관리 페이지 등은 CSR방식으로 만들면 된다.

👍 CSR의 장점

  • 웹 서버 호출을 최소화 할 수 있다.
    - 최초 호출 시에만 각 파일을 요청하고, 이후에는 업데이트가 필요한 부분의 데이터만 요청한다.
    • 페이지 이동이 빠르다.
      • 라우팅으로 페이지를 이동하더라도 html파일이 변경되지 않고 JS가 새로운 화면을 그려낸다.
        • 처음에 모든 리소스를 다운받아놓고, 페이지 이동시 필요한 데이터만 전달받아 업데이트한다.
        • SSR은 서버측에서 뷰를 모두 렌더링하여 전체 페이지를 다시 읽어 새로고침하기 때문에 상대적으로 더 느리다.

👎 CSR의 단점

  • 검색 노출이 잘 되지 않는다.
    - CRA가 CSR 방식으로 빌드하는 방식인데, 검색 노출에서 한계가 있었다.


검색 노출의 한계

CRA로 빌드한 프로젝트는 CSR로만 실행되기 때문에, 검색 노출이 잘 되지 않는다.

반대로 어드민 페이지나 특정 조건(유료 멤버십 페이지, vip 페이지 등)은 특별히 검색노출이 필요하지 않기 때문에 CRA로 충분히 개발할 수 있다.



2️⃣ SSR

서버에서 첫 페이지의 렌더링을 처리해주는 방식
페이지 요청이 발생했을 때 서버에서 api를 호출해 데이터를 가져와 html을 완성시키고 클라이언트에 전달한다.

👍 SSR의 장점

  • SEO측면에서 유리하다.
    - 서버에서 페이지를 모두 구성해서 보여주기 때문에 첫 렌더링 시 html파일이 비어있지 않다.
  • UX 측면에서 유리
    - CSR에 비해 페이지를 구성하는 속도는 늦어지지만, 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점은 빨라진다.

CSR에 비해 페이지를 구성하는 속도는 늦어지지만, 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점은 빨라진다. => 이게 무슨 말이냐면...

SSR은 아래 이미지와 같이 동작한다.
서버에서 html파일을 준비해 보내주면 바로 화면을 그려 사용자에게 보여줄 수 있다.
이후 JS파일을 로드하고, 실행시켜 페이지의 구성을 완료한다.

따라서 사용자의 입장에서 화면을 빠르게 볼 수 있다.

이미지 출처: The Benefits of Server Side Rendering Over Client Side Rendering

반면 CSR은 빈 html파일을 받아온 후, JS파일을 다운받고, 이 JS코드를 실행해 DOM을 화면에 모두 그린 후에야 사용자에게 보여줄 수 있기 때문에, 사용자에게 화면을 보여주기 위한 시간은 상대적으로 더 많이 소요된다.

👎 SSR의 단점

  • 페이지를 잘 못 구성할 경우 CSR에 비해 서버 부하가 커지거나 첫 로딩이 매우 느려질 수 있다.
  • 요청 시마다 html을 만들어야 하므로 응답 시간이 오래걸릴 수 있다.


👉 Next.js: CSR + SSR

Next.js는 SSR과 CSR을 섞어 쓸 수 있도록 하는 리액트 프레임 워크이다.

1️⃣ CRA로는 부족한거야?

CRA는 별도의 초기 설정 없이도 리액트 기반의 SPA 사이트를 구현하도록 도와준다.
하지만 CSR방식으로 빌드하는데, 이렇게 되면 SEO가 잘 되지 않는다.

2️⃣ Next.js의 장점

  • 페이지 기반 라우팅 시스템: pages 폴더 하위에 pageName[params].tsx 형태로 파일이름을 지정하면 pageName/params형태로 동적 라우팅이 된다.
  • 페이지 별 정작파일 생성과 서버사이드 렌더링 지원
  • css, sass, CSS-in-JS라이브러리 지원
  • 코드 스플리팅 가능

코드 스플리팅이란?

코드 스플리팅은 한 개의 파일에서 처음부터 모든 걸 불러오지 않고, 당장 필요하지 않은 코드는 분리시킨 다음 필요할 때 불러 사용하는 것이다.

SPA의 경우 자바스크립트 번들 파일에 어플리케이션에 대한 모든 로직을 불러오기 때문에 프로젝트 규모가 커질 경우 용량 또한 커진다고 위에서 언급했다.

코드 스플리팅을 사용하면 페이지의 로딩 속도를 개선할 수 있다.



3️⃣ Next.js의 세가지 렌더링 방식

정적생성 Static Generation

  • 빌드 시점에 온전한 페이지의 HTML이 생성되어 서버에서 물리적으로 HTML파일을 모두 갖고 있는 상태

    다시 말하면, 데이터까지 포함된 완성된 html파일을 미리 만들어둔 뒤 페이지 요청이 잇을 때 이 페이지를 바로 응답한다.

  • Next.js에서 권장하는 렌더링 방식
  • 한 번 응답한 후에는 CDN (content delivery network)이 파일을 캐싱해서 응답하기 때문에 화면을 그리는 속도가 빨라지고 불필요한 서버 요청이 줄어든다.

정적생성 방식의 한계

  • 유동적으로 데이터를 실시간으로 받아와야 할 경우 정적생성 방식이 적합하지 않다.
  • 예를 들어 쇼핑몰의 메인 페이지가 매일 새로운 상품을 보여줄 경우, 빌드 시점에 정적으로 HTML을 생성하면 빌드 시점에 호출해 가져온 상품목록 데이터가 고정되어 html파일이 만들어진다. 따라서 유동적으로 데이터를 받아올 수 없다.
  • 정적 생성에 적합한 페이지는 회사 소개 페이지, 개인정보 처리방침과 같은 설명 페이지, 정적 블로그 페이지 등이 있다.


4️⃣ 렌더링 방식을 결정하는 데이터 호출 메서드

이 렌더링 방식은 어떻게 구현하면 될까?
Next.js에서 제공하는 데이터 호출 메서드들이 있다.
이 메서드로 데이터를 호출해 사용하면, 그대로 렌더링 방식이 결정된다.

1️⃣ static generation: getStaticProps, getStaticPaths

getStaticProps

import { GetStaticProps } from 'next'

export const getStaticProps: GetStaticProps = async context => {
	// 생략
}

getStaticPaths

동적라우트인 페이지면서 정적으로 페이지를 생성하고 싶을 때 사용하는 메서드
동적라우트로 생성될 모든 경로에 대해 getStaticProps와 마찬가지로 빌드 시점에 데이터를 받아 페이지를 정적으로 생성한다.


export const getStaticPaths: GetStaticPaths = async () => {
	return {
		paths: [{ params: { id: '1' } }, { params: { id: '2' } }]
	};
};

export const getStaticProps: GetStaticProps = async ({ params }) => {

	const response = await axios(`${API_URL}/restaurant?id=${params.id}`);

	return {
		props: {
			data: response.data.restaurant
		}
	};
};

2️⃣ SSR: getServerSideProps

getInitialProps라는 메서드도 있지만, Next.js 9.3버전 이후로 getSererSideProps가 더 기능이 좋아졌기 때문에 사용하지 않아도된다.

export const getServerSideProps: GetServerSideProps = async () => {
	const all = await axios(`${API_URL}/restaurants`);
	
	return {
		props: {
			data: all.data.restaurants
		}
	};
};

SSR 구성 요소

  • node.js로 구성된 프론트엔드 서버가 서버사이드 렌더링을 한다.
  • 장고 등으로 구축된 백엔드 서버가 데이터를 주고 받는다.

SSR 진행 과정

  • 프론트엔드 서버가 요청을 받아 서버사이드 렌더링을 한다.
  • 프론트엔드 서버가 만들어진 html을 브라우저에 보내면 브라우저가 이것을 그린다.
  • html에 기능을 부여할 js 파일을 다운로드 받는다.
  • 라우팅 시 이동할 페이지의 코드를 생성한다.

3️⃣ CSR: useEffect (Next.js가 아닌 React 내장 훅 사용)


❗️ 주의: Next.js에서는 fetch 사용 불가!

fetch 함수는 web API이기 때문에 브라우저에서만 실행된다.
즉 서버측에서 호출할 수 없다.
클라이언트와 서버측 모두 api를 호출할 수 있도록 axios를 쓰는 것이 좋다.



Reference

profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글