Next.js SSR 서버사이드 렌더링 스터디 기초

김아현·2023년 4월 10일

Next.js

목록 보기
1/1

What is Next.js

SSR 어플리케이션 도입의 이유

Learn | Next.js

서버 통신이 많은 멀티플레이 웹앱 특성 상, 다수의 프로젝트들이 서버 연산에 SSR을 사용하고 있음

특히, 성능이 좋은 어플리케이션들은 Svelte로 빌드된 것이 보이나, Svelte 사용법에 익숙치 않으므로 Next.js로 테스트를 함. → Next.js 튜토리얼 따라감 ..

레퍼런스

How To Build A Real-Time Multi-User Game From Scratch — Smashing Magazine

Summer Afternoon

그래서, 우리 프로젝트의 클라이언트 렌더링 담당 및 UI component 제작을 위해서는 React를 쓰고, 친구, 마켓 등의 기능에서의 Data Fetch나 Routing, Server Side Rendering과 클라이언트 렌더링 조합등의 어플리케이션 구조화를 위해서 Next.js를 써보자! Next.js가 canvas같은 요소에 접근하진 못한다 하지만.. 이 부분은 react-three-fiber나 drei등 다른 라이브러리 도움을 좀 받자

UI 렌더링의 구조 : React의 작동 방식의 이해

예를 들어 사용자가 우리가 만든 웹에 접속했다 가정해보자. 서버는 유저의 브라우저에 HTML파일을 보낸다. 그럼, 유저의 브라우저는 이 HTML 파일을 기반으로 Doument Object Model (DOM)을 구성한다. 그렇기 때문에 파싱에선 script 컴파일이 이루어지지 않는다.

여기서, 개발자들은 DOM update를 위해 다양한 방법을 사용한다. 이중에서도 나는 Declarative programming인 리액트 라이브러리를 개발에 주로 사용한다.

리액트는 JavaScript기반의 라이브러리로, 웹 컴포넌트 단위로 쪼개어 DOM을 조립해 최종적으로 유저가 웹을 방문했을 때, 브라우저에 리턴할 가상 DOM 트리를 만들어 두었다가 빠르게 보내주는 방식이다.

https://junilhwang.github.io/TIL/Javascript/Design/Vanilla-JS-Virtual-DOM/#_3-레이아웃


pages 하위 디렉토리가 곧 route가 된다. 디렉토리와 파일로 손쉽게 경로를 관리할 수 있다.

페이지간의 이동을 할 때, a태그 대신 Next.js의 빌트인 Link 컴포넌트를 사용한다. routing 라이브러리 없이 손쉽게 client-side의 페이지 네비게이션을 다룰 수 있으며 Link에 해당하는 javascript code만을 로드하기 때문에 최적의 효율성을 보인다.

Image 컴포넌트


이미지 최적화 지원

Next.js는 image optimazation을 기본으로 지원한다. 브라우저가 기술적으로 지원한다면 resizing, optimizing, serving in modern format 모두 가능하다. 따라서 작은 사이즈의 viewport를 가지는 디바이스에 큰 파일을 보내는 대신 최적화된 이미지를 전송한다.

Image 컴포넌트 사용하기

Next.js는 빌드 타임에 이미지를 최적화하는 대신에 유저가 요청할 때 최적화를 수행한다. 이로 인해 이미지 전송 수가 얼마나 되건 SSG 방식과 다르게 빌드 타임을 유지할 수 있다.

동시에 viewport를 벗어난 이미지들은 로드되지 않고, 스크롤 액션을 통해 viewport에 들어온 순간에 로드된다.

Image에 priority 속성 주기

특히 페이지내에서 큰 이미지나 텍스트 블록의 경우, priority 속성을 주어 LCP element 임을 표기해 최적화를 하자.

Pre-rendering


default 설정으로 Net.js에서는 모든 페이지의 pre-rendering이 일어난다. 클라이언트 사이드 렌더링 대신 서버 사이드 렌더링을 통해 SEO와 성능 개선에서 좋은 지표를 보여준다. 서버에서 미리 파싱된 HTML은 최소한으로 딱 해당 페이지에 필요한 jS 코드와 브라우저로 로드되고, 해당 페이지를 인터랙티브하게 만든다. 이 과정을 ‘hydration’이라 부른다.

Static Generation & Server-side Rendering

Build 타임마다 HTML을 생성해놓고 재사용한다.

사용자 요청시에 HTML을 생성하고 반환한다.

Next.js는 두가지 방법을 모두 사용할 수 있기 때문에, 각 페이지 마다 엉떤 렌더링 방법을 사용할 것인지 골라서 효율적으로 사용할 수 있다. 이 점으로 보아, 단일 유저가 사용하는 3D 컨텐츠의경우 SSG 방식으로 렌더링하는 게 더 좋은 성능을 발휘할 것 같다. 공식 문서에서도 사용 예시로는 정적 페이지들을 이야기하고 있으며 그 종류는 아래와 같다.

  • Marketing pages
  • Blog posts
  • E-commerce product listings
  • Help and documentation

이와 반대로, 유저의 요청에 따라 렌더링이 변화하고 항상 up-to-date 상태여야하는 페이지의 경우 Server-Side-Rendering을 권장하고 있다. 유저마다 상호 위치를 교환하고 최신 데이터로 적용해야하는 3D web game의 경우, WASM을 곁들인 SSR이어야 할 거 같다

Static Generation with Data fetching

async 함수인 getStaticProps 를 통해 페이지 컴포넌트에 필요한 데이터를 가져올 수 있다. Build time에 data dependency를 확인하고, 그 다음 data fetch를 통해 페이지의 props로 사용하게 한다. HTML은 data fetching 이후에 생성된다.

Server-side Rendering with Data fetching

반면에 Server-Side Rendering에서 Data fetching은 어떻게 이루어질까? 앞에서 살펴본 바와 같이, SSR은 Build time이 아닌 Request time에 data fetch가 이루어진다. 이땐, 앞에서 사용한 getStaticProps 함수 대신, getServerSideProps 함수를 export 해야한다.

기본적인 getServerSideProps 함수의 구조는 아래와 같다.

export async function getServerSideProps(context) {
  return {
    props: {
      // props for your component
    },
  };
}

Client-side Rendering with Data fetching

이외에 Next.js에서, Client-side Rendering을 사용하게 되면 data fetching이나 SEO 최적화와 관계없이 페이지를 렌더링할 수 있다. 이럴 경우에 Next.js의 개발팀은 SWR 이라는 리액트 hook library를 맞춤 개발했고 그 사용을 권장하고 있다. interval 사이의 refetching이나 focus tracking, revalidation, caching의 기능을 지원한다.

import useSWR from 'swr'

const fetcher = (...args) => fetch(...args).then((res) => res.json())

function Profile() {
  const { data, error } = useSWR('/api/profile-data', fetcher)

  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
    </div>
  )
}
profile
멘티를 넘어 멘토가 되는 그날까지 파이팅

0개의 댓글