우리 회사는 Next.js로 웹 프로덕트를 개발, 유지보수, 배포 중이다. 하지만 SPA에 익숙한 나는 Next.js에서 제공하는 Server Side Rendering을 잘 활용하고 있나라는 의문이 들었고, 토스의 SSR에 관련된 영상을 보며 다시 한 번 알아봐야겠다는 생각을 하였다.
data fetch를 기준으로 생각하고 작성하였습니다.
Server Side Rendering (SSR)
- SSR은 서버에서 사용자에게 보여줄 페이지를 모두 구성한 후에 브라우저에 보여주는 Rendering 방식이다. 따라서 data fetching이 필요한 경우, 서버에서 data fetch한 상태의 페이지를 구성하여 사용자에게 보여준다.
- 👍 : 브라우저에 보여줄 페이지를 Load하는 동안은 사용자는 Loading을 겪게 될 것이다. 하지만 Load 된 이후에 사용자는 이미 구성된 페이지를 보기 때문에 빠르게 페이지를 볼 수 있게 된다.(Time To View, TTV가 짧다.)
- 👎 : 하지만 SSR은 구성된 페이지가 보여진 이후에 브라우저에서 React를 실행하고, React가 실행된 이후에 사용자가 Interaction을 할 수 있다(Time To Interact, TTI). TTV와 TTI 사이에 사용자가 빠르게 Interaction을 시도한다면 아무런 반응도 없게 된다.
출처 : The Benefits of Server Side Rendering Over Client Side Rendering
Client Side Rendering (CSR)
- CSR은 사용자의 요청에 따라 HTML, JS 등 필요한 것들만 먼저 Load하고 data를 클라이언트에서 axios,swr과 같은 비동기처리를 통해 하는 것이다. HTML 다운로드 -> JS 다운로드 -> JS 실행 -> 보여짐 과정이 있기 때문에 사용자에게 TTV가 길다.
- 👍 : 한 번 JS, HTML을 다운로드 받으면 이후의 interaction이 굉장히 빠르다.
- 👎 : JS 파일을 모두 다운로드 받아야하기 때문에 TTV가 길고, data fetching이 필요한 경우에 사용자가에 필요한 정보를 보여주기 위해서는 data fetch가 될 때까지 사용자는 Loading을 기다려야한다.
출처 : The Benefits of Server Side Rendering Over Client Side Rendering
CSR ? SSR ?
내 개인적인 생각에 결국 둘의 큰 차이는 data fetch를 어디서 하여서 페이지를 구성하느냐 차이인 것 같다. 이 차이점에서 TTV의 차이도 발생하는 것 같다.
Next.js
Next.js는 페이지 Load까지는 SSR, 페이지 Load 이후는 React의 CSR을 이용하는 방식이다.
- pages/ 의 page file은 서버 사이드에서 Load
- page가 그려진 이후 data fetch는 클라이언트 사이드에서
따라서 페이지가 Load될 때 함께 data fetch를 하고 싶다면 Next.js에서 제공하는 getInitialProps, getServerSideProps, getStaticProps를 사용하여 SSR를 만들어야한다.
SSR 요청 순서
- 서버에 페이지 요청
- 서버에서는 요청 받은 페이지를 찾음
- _app.tsx의 getInitialProps가 있다면 실행
- pages/ 아래의 페이지 파일에 getInitialProps가 있다면 실행하고 페이지의 pageProps를 받는다.
- _document.tsx의 getInitialProps가 있다면 실행하고 custom document의 pageProps를 받는다.
- 모든 props를 구성하고 _app.tsx -> 페이지 순으로 Rendering
- 모든 content를 구성하고 _document.tsx로 HTML을 출력
getInitialProps
Recommended: getStaticProps or getServerSideProps instead of getInitialProps. These data fetching methods allow you to have a granular choice between static generation and server-side rendering.
Next.js의 공식문서에서는 getInitialProps보다는 9.3 버전 이후에 나온 getServerSideProps와 getStaticProps의 사용을 권장한다.
- _app.tsx에서 getInitialProps를 전역으로 사용하게 될 경우 Next.js에서 제공하는 자동정적최적화가 비활성화되어 모든 페이지가 SSR 된다.
- getInitialProps를 사용한다면, getServerSideProps와 getServerSideProps는 실행되지 않음
- 자동정적최적화 : Next.js에서는 페이지가 정적인지 확인하고, getInitialProps나 getServerSideProps를 사용하지 않는다면 페이지를 정적 HTML로 사전에 렌더링하여 클라이언트에 전달. 이후 js도 전달. hydration을 하여 최적화한다. SSR이 없기 때문에 사전에 렌더링 된 HTML이 사용자에게는 즉시 뿌려지는 매우 빠른 로딩.
- hydration: Server Side 단에서 렌더링 된 정적 페이지와 번들링 된 JS 파일을 클라이언트에게 보낸 뒤, 클라이언트 단에서 HTML 코드와 JS코드를 서로 매칭시키는 과정
참고 : Next.js - Automatic Static Optimization
getStaticProps
- Static Site Generation (SSG)
- getStaticProps를 사용하면 build time 한 번에만 data fetch가 이루어진다. 따라서 유저에 따라 정보가 변경되거나 하는 data는 getStaticProps에는 맞지 않을 것 같다.
- 유저에 따라 변하지 않고 퍼블릭하게 사용할 수 있는 데이터에 사용하는 것이 좋을 것 같다. 예를 들어 식단 관련 서비스인 우리 회사 서비스라면, 백앤드에서 알러지 리스트를 받아오는데 이것은 유저에 따라 변하지 않기 때문에 getStaticProps를 통해서 받아오면 좋을 것 같다.
getStaticPaths
- Static Site Generation (SSG)
- 동적 routing에서 사용. getStaticProps와 함께 사용한다.
- 정확히 이해하지는 못했지만, 동적 routing에서 /[id].tsx에 id에 들어갈 수 있는 id list들을 미리 static하게 두고, getStaticProps에서 해당 id를 params로 받아서 data fetch하는데 사용한다.
getServerSideProps
- server에서 해당 페이지를 request할 때마다 실행하여 data fetch
- 자주 바뀌는 data에 대해 SSR을 하기 위해서는 getServerSideProps가 적절한 것 같다.
But,
Fetching data on the client side
If your page contains frequently updating data, and you don’t need to pre-render the data, you can fetch the data on the client side. An example of this is user-specific data. Here’s how it works:
First, immediately show the page without data. Parts of the page can be pre-rendered using Static Generation. You can show loading states for missing data.
Then, fetch the data on the client side and display it when ready.
출처: Next.js 공식 문서 Fetching data on the client side
이것을 보고 우리 서비스와 맞나라는 생각이 들었다..
1. 우리 서비스는 localStorage로 token 관리하고 있다. 그래서 SSR을 위한 함수에서 token 값을 받아올 수가 없었다. 해결하기 위해서는 token을 localStorage에서 cookie로 바꾸는 작업이 선행 되어야한다. 이후 다음 포스트를 참고하면 될 것 같다.
https://wonmocyberschool.tistory.com/93?category=959185
2. 우리 서비스는 개인 맞춤 식단 서비스라서 대부분은 user-specific data이다.
사이드 프로젝트나 포트폴리오 프로젝트에 적용해 봐야지 ,,