시작하며
이전에 리액트가 어떻게 동작하는지, 이해하기 위해서 리액트처럼 동작하는 어플리케이션을 만들어보았었다.
이번에도 마찬가지다. 이번에는 Next의 SSR과 hydrate과정을 직접 만들어보면서 이해해보고자 한다.
배경 : SSR과 CSR
SSR이란 Server Side Rendering의 줄임말으로, 서버에서 사용자에게 보여줄 페이지를 모두 구성하여 페이지를 보여주는 방식이다.
여기서 모두 구성이란걸 한 번 눈여겨 볼 필요가 있다. 그럼 원래는 부분적으로 구성을 해서 보내주기도 한다는건가?
그렇다. React기반의 웹 어플리케이션에서 useEffect를 통해 데이터 패칭을 통해 화면을 보여주는 경우 아래와 같은 순서로 작동하게 된다.
- 서버로 부터 HTML수신
- script태그를 통해 리액트 및 어플리케이션 번들파일 수신
- js실행하여 컴포넌트 실행(렌더링) 및 root에 컴포넌트 결과물 붙이기
- useEffect를 통해 데이터 패칭
- 컴포넌트 리렌더링
이러면 반드시 네트워크 통신이 2회 일어날 수 밖에 없고, (2번과 4번) 완벽한 페이지 하나를 보내주는게 아니라, 페이지를 조각내고, 완성되지 않은채로, 부분적으로 보내주는 꼴이 된다.
애초에 첫 HTML파일은 root밖에 없거나, 혹은 아예 아무것도 없는 상태이다.
그러면 뭐가 문젠데요?
번들사이즈가 커지게되면 3번과정이 일어나는데까지 시간이 걸리게된다.
그말인즉슨, 흰 화면을 보게되는 것이다.
엥 그러면 한번에 다 받아오는게 더 이득아닌가요?
물론 그렇다. 하지만 그럴수가 없었다.
CSR이전의 웹 개발에서는 페이지 이동이란 html 파일의 교체를 의미했다. 마치 책의 페이지를 넘기듯, index.html에서 login.html으로, 다른 파일을 받아오고, 화면에 그리는 것이다. 실제로 HTML은 하나의 문서(document)다.
그래서 새로운 데이터를 받아오려면 새로운 문서를 받아와야만 했다.
그러면 새 화면 데이터를 불러오는 동안 또다시 흰화면(이번엔 깜박임)을 보게된다! 어쩌면 클라이언트는 흰화면과의 싸움일지도 모르겠다.
그러면 유저별 HTML 파일을 전부 만들어두는 건가요?
매번 맞춤형 HTML을 만들어놓을 수는 없는 법이다. 그래서 이전의 웹서버와 WAS들은 PHP, JSP와 같은 언어를 통해 동적으로 서버에서 HTML을 만들어서 전송해주도록 구성되었다. 지금도 많은 사이트들이 구성되어 있는데, 이러한 언어와 프레임워크들이 최초의 SSR 되시겠다.
정리
이전의 PHP,JSP를 사용한 SSR을 전통적인 SSR이라 이름붙이면, 이렇게 정리할 수 있다.
여기서 말하는 데이터란, 유동적으로 변할 수 있는, 네트워크에 저장된 데이터를 말한다.
전통적 SSR | CSR | |
데이터 패칭 | 데이터를 서버에서 받아오며, 서버에서 데이터로 만든 결과물을 클라이언트에서 받아옴 | 빈 HTML을 받아, 화면을 구성하는 것을 포함한 번들파일과 실제 데이터를 모두 클라이언트에서 받아옴 |
장점 | 1번의 통신을 통해 데이터를 가져옴 | 한번 번들을 받아오면 정적파일을 다시 받아올 필요가 없음 |
단점 | 페이지 이동마다 깜빡임이 있고, 하나의 페이지마다 정적파일을 한번씩 받아와야하기에 속도가 느림 | 번들이 커지면 첫 화면을 그리는데 많은 시간이 필요함. 총 2회의 통신을 통해 모든 데이터를 가져옴 |
Home화면에서 Feed로 이동하는 흐름을 CSR과 SSR에서 비교하면 이렇게 그릴 수 있다.
Next: 두마리 토끼를 다 잡을수는 없을까?
결론에서 만든 표와 그림을 합쳐서 표기하면 이렇게 표시할 수 있게된다.
과연 이런 장단점을 합칠수는 없을까?
Next는 이 상황에 대해 여러가지 방법을 제공한다.
- 초기 렌더링에 보여질 HTML을 미리 만들어두고, 요청이 오면 그걸 보여줘서 초기에 흰화면을 보여주지 않는 방법 (SSG, ISR)
- 페이지 이동시 클라이언트에서 흰화면을 보여주지 않고 SPA처럼 보이게 하는 방법(SSR)
이렇게하면 둘의 장점만 뽑아서 쓸 수 있게 된다.
How?
그런데 어떻게 이런게 가능할까? 나는 이번 프로젝트를 통해 이러한 고민들중 일부를 직접 해결해보고, 이후에는 Next 코드를 살펴보며 이해해보고자 한다.
생각해보기
위의 방법을 사용하려면 간단하게 생각해도 크게 세 개가 필요하다.
- 서버에서 HTML을 미리 만들어 두는 기능
- 서버에서 만든 HTML을 클라이언트에서 상호작용 가능하도록 만들어주는 기능 (Hydration)
- 클라이언트에서 동작할 기능
서버에서 동작하는것, 클라이언트에서 동작하는 것
서버에서 동작할 코드, 클라이언트에서 동작할 코드가 있는 것을 볼 수 있는데, 생각해보면 Next를 사용하면서 한번도 따로 작성한 적이 없다. 사실 그럴거였으면 Next가 이렇게 커지지도 않았을 것이다.
그래서 내가 떠올린 답은 JSX다.
JSX는 객체로 변환되고, 이를 통해 하나의 코드로 HTML을 생성할수도 있고, VDOM에 들어갈 ReactNode를 생성할 수도 있다.
HTML과 클라이언트의 상호작용 (Hydration)
이건 JSX를 떠올리니 자연스럽게 떠올랐다. 바로 React의 리렌더링을 활용하는 것이다.
어차피 HTML이니 DOM은 그대로 있고, 초기에 React VDOM이 생성될때, 기존 HTML을 업데이트 해주면 끝이다!
만들 것
따라서 나는 JSX와 React like(이전에 만들어둔 함수들을 활용해볼 예정이다.)를 통해 Next like를 만들어 볼 것이다.
크게는 ServerSideProps, ServerSideRendering, Hydration이 될 것 같다.
환경설정부터 진행해보자.