Next.js의 SSR은 미리 pre-rendering을 해놓고 유저가 해당 경로로 접근을 할 때 그 페이지를 제공해 주는 형태이다.
이때, 주목해야 할 점은, Next.js는 빌드 과정에서 이미 어떤것을 server폴더에 있는 html을 전달해줘야할지(SSR) 아니면 static 폴더에 있는 js 파일을 전달해줘야할지(CSR) 을 결정짓고 있다는 점이다.
이것이 무엇을 의미하냐면, Next.js에선 어차피 Link나 useRouter와 같은 CSR 라우팅 메서드가 존재하지 않는 이상, 그 외에는 서버에서 빌드한 HTML을 전달할 필요가 없다고 생각하는 것이다. (랜더링 책임을 브라우저에게 js를 건네주면서 떠넘긴다)
예를들어, 첫 페이지 index.js에서 Link를 통한 이동과, a태그를 이용한 이동이 존재한다고 가정하자.
이때 Link는 CSR용 메서드이므로, 랜더링 책임이 브라우저에 있다. 따라서, 미리 빌드를 할 당시에 static 폴더에 js로 압축된 파일을 스크립트로 전달받은 후, DOM에 브라우저가 랜더링 책임을 지며 처리한다.
a태그는 페이지가 새로고침이 되며 서버에 요청이 전달되고, 이때는 SSR이 되므로 Next.js 서버가 브라우저에게 미리 pre-rendering하였던 html 파일을 전달한다.
실제로, 빌드 후 npm start를 해보면 받아오는 html의 script에는 오로지 Link를 통해 이동할 수 있는 페이지의 대상만 js청크 파일로 받아오고 있다.
요약 👍
getStaticProps : 미리 html과 json prop데이터를 만들어놓는다. revalidate 옵션을 통해 주기적으로 호출되어 json 데이터를 새로 빌드한다.
getServerSideProps : 미리 html과 json 데이터를 만들어놓지 않는다. 첫 요청시 CSR처럼 압축된 js 파일만 미리 전송하고, 해당 페이지 요청이 들어오면 그때 호출되어 json 데이터를 제작하고 응답으로 전달한다.
위 두 함수를 사용하는 것은, Next.js 서버에게 미리 props에 전달할 데이터를 json 형태로 생성해놓고 있을지 아닐지를 결정한다.
예를들어,
client 폴더의 index.js에는 getStaticProps를, portfolio 폴더의 index.js에는 getServerSideProps를 설정해준 상태이다.
그리고 나서 빌드를 해보면 그 파일에는 이런 차이가 존재한다.
clinet.json만 존재하는 이유는, getStaticProps는 빌드 과정에서 미리 해당 함수가 실행되어 완료된 결과물을 json 형태로 저장해놓고 있다가 서버에 요청이 들어오면 html을 건네줄 때 script 태그 내에 해당 데이터를 json 형태로 담아두기 때문에 그렇다.
NOTE. 근데 만약, Link와 같은 CSR형태의 페이지 이동 때에는 이 데이터를 어떻게 건네주는걸까? 정답은 간단하다. html 파일이 아닌 js를 넘겨줬던 위의 상황처럼, html에다가 심어주는 것이 아닌 json 형태로 미리 만들어놓은 것을 응답으로 건네준다.
참고로, 위 스크린샷에서 볼 수 있듯, getServerSideProps함수가 있는 파일은 Next.js에 의하여 Pre-rendering 되지 않는다!
이말인 즉슨, 서버쪽에서 html 형태로 제작이 되지 않는다는 소리다. 즉, 압축된 js 파일만 클라이언트한테 전송하여 CSR을 하도록 하게한다.
getServerSideProps는 getStaticProps와는 다르게, context로 prams 뿐만 아니라, node.js때와 같이 req,res객체를 받아올 수 있다.
parms는 qeury와 같은 엔드포인트와 관련된 정보가, req는 유저가 보내온 데이터의 쿠키와 body를 가져올 수 있고, res로는 물론 next.js가 pre-rendered된 페이지를 전송하는 작업을 하기 때문에 res.json 형태를 취해줄 필요는 없지만 미리 헤더를 설정하거나, 쿠키를 설정하는 등을 res객체를 통해서 해놓을 수 있다.
기존, getStaticProps때에는 다시금 상기하기를 미리 pre-rendering을 해서 html과 json을 만들어야 하는데 이 dynamic path에 무슨 값이 들어올지 확인이 정확히 안되므로, 미리 해당 값을 제공하기 위하여 getStaticPaths 메소드를 사용해서 리턴되는 객체의 paths 프로퍼티를 이용하여 pre-rendering을 실행하여 모든 가능 케이스들의 html을 만들어놔야 했었다.
아니면 fallback 옵션을 통해 true를 주어서 매번 dynamic path에 대한 query 정보들이 들어올 때 getStaticProps를 실행하여 html과 json 데이터를 만들고 이것을 유저에게 전달하도록 할 수 있었다. (물론 이 케이스의 경우, Client측에 html은 CSR을 실행하려 할 텐데, 그때 필요한 props 데이터가 아직 JSON으로 만들어져 전달받지 못한 상태이므로 loading 케이스를 만들어줘야 하고, 서버측에는 해당 요청에 대한 데이터가 없는 경우를 예비하여 서버측 코드가 실행되는 getStaticProps의 내부에서 redirect를 위한 return문을 만들어줘야 했다.)하지만 getServerSideProps 함수는 CSR일지라도 매번 라우팅 이동을 할 때마다 서버에게 요청을 날려서 JSON데이터를 받아온다. 즉, 매번 새로운요청이 들어와서 getServerSideProps가 호출이 되므로, getStaticPaths와 같은 pre-rendering을 위한 작업이 필요하지 않다.
위에서 설명하는 케이스는 3가지이다
1. 데이터가 빈번하게 바뀔 경우 미리 데이터를 패칭하여 pre-rendering 하는 케이스는 의미가 없다
2. 유저에게 관계성이 많은 데이터(개인정보) 같은 경우, 어차피 유저 정보를 가져오는 작업이 필요하기에 pre-rendering해놓을 필요가 없다.
3. 해당 데이터가 담당하는 부분이 아주 작은 영역일 경우, 오히려 next.js 서버에게 비효율적인 작업이 늘어나는 것과 같다.
다시 말해서, 언제나 변하지 않을 정적인 페이지를 미리 서버에 캐싱해두고 내보내고 싶을 때에 해당 함수들을 쓰는것이 좋다.