클라이언트 - 서버간 통신에서 html을 반환하는 웹 서버의 대략적인 흐름을 보자면 크게 다음과 같이 정리할 수 있을 것 같다.
정적 페이지만 반환 --> DB연동 및 API 요청 필요성 대두 --> 동적 페이지 반환
여기서 정적 페이지란 HTML / CSS / JS 로 이루어진 웹 문서이고,
동적 페이지란 정적 페이지 + 서버에서의 비지니스 로직이 가미되어 완성되는 문서라고 볼 수 있다.
웹 브라우저와 관련 기술 스택의 발전으로 단순히 고정된 HTML문서만 반환하던 방식에서, CSS와 JS로 디자인적인 부분도 신경쓰고 유저와의 인터랙션 등도 고려하여 조금 더 인터랙티브한 HTML문서로 넘어가 AJAX요청 및 실시간 처리까지 모두 반영하는 문서를 반환하는 형태로 이해해도 좋을 거 같다.
다시 본론으로 돌아와 정적 페이지를 반환하는 웹 사이트의 경우엔,
요청(또는 클릭)시 마다 이미 만들어진 새로운 페이지를 반환하며 이때 화면의 깜빡임(불러오는데 걸리는 시간만큼)이 발생한다. 이 같은 방식의 웹 어플리케이션을 MPA(Multiple Page Application)이라고 부른다.
반면 React 또는 Vue와 같은 프레임워크로 만드는 웹 페이지는 기본적으로 SPA(Single Page Application)이라고 부른다. 앞의 경우와 달리 하나의 페이지에서 모든 페이지를 이동하고 보여주는 방식이다. CSR과 SSR에 대해 본격적으로 알아보기 전에 이 둘의 차이를 먼저 살펴보자.
각각의 개념은 이미 위에서 설명이 되었다.
간단하게 다시 정리하자면 MPA는 다수의 페이지로 구성되어 요청마다 정해진 페이지를 반환하는 반면, SPA는 단일 페이지로 구성되어 해당 페이지 자체에서 요청에 따라 화면을 재구성한다.
그렇다면 CSR과 SSR은 무엇일까?
각각의 용어의 뜻 풀이는 클라이언트 사이드에서 HTML문서 렌더링을 할 것이냐 아니면 서버 사이드에서 HTML문서를 렌더링 할 것이냐로 구분할 수 있다.
앞서 살펴본 MPA와 SPA의 개념을 보면 이 두가지 방식이 각각 어떤 렌더링 방식을 취하고 있는지 알 수 있다. 위 그림에서도 알 수 있듯이 MPA 형태가 SSR 방식으로, SPA 형태가 CSR 방식으로 HTML문서를 렌더링하고 있다.
MPA 형태에서는 이미 하드코딩된 정적페이지들을 개별적으로 서버가 가지고 있다. 따라서 요청마다 서버는 해당 요청에 상응하는 정적페이지를 하나 찾아서 반환을 해주게 된다. 이는 결국 렌더링이 서버 사이드에서 완료되어 최종 문서를 반환하고 있는 형태이다.
반면 SPA 형태에서는 최초 요청 시에 서버로부터 HTML문서를 전달받는다. 추후 자세히 보겠지만 해당 문서는 비어있는 HTML문서나 다름이 없다. 최초로 받아온 HTML문서를 가지고 렌더링에 필요한 기타 다른 파일(JS 등..)을 로드하여 클라이언트(브라우저)단에서 렌더링을 실시해 화면을 구성한다.
여담으로 당연히 MPA 개념보다 SPA 개념이 이후에 탄생했다. 탄생 배경으로는 여러가지 요인이 있는데, 대표적인것으로는 대모바일(스마트폰) 시대가 도래하면서 상대적으로 성능이 PC보다 떨어지는 모바일 디바이스에서 최적화를 보장하기 위해서와 또 SPA 형태의 웹 사이트가 조금 더 유저 친화적인 사용자 경험을 선사해준다는 이유 등이 있다. (매번 페이지 이동 시 깜빡임과 대기시간이 발생하면 불편할 수 밖에 없다..)
MPA === SSR 또는 SPA === CSR은 엄연히 틀린 개념이다. MPA/SPA는 웹 어플리케이션을 구성하는 형태를 말하고, SSR/CSR은 렌더링 방식을 말한다. 다만 MPA는 SSR 방식만, SPA는 CSR 방식만 가능한 것은 맞다. (전통적인 개념이라는 가정 하에)
그렇다면 각 렌더링 방식에 대해 조금 더 자세히 살펴보자.
사실 전통적인 SSR 방식의 이해는 크게 어렵지가 않다. SPA가 등장하기 전엔 대부분의 웹 사이트는 MPA 방식으로 운영되었고, (나이대에 따라 다르겠지만) 우리는 기본적으로 이러한 방식의 웹 사이트들을 어렸을 적 경험해 보았기 때문이다. SSR의 기본적인 사이클은 아래 사진을 참고하자. 서버에서 요청한 HTML파일을 렌더링을 마친 상태로 응답하기에 로딩시간이 상대적으로 짧다는 것을 볼 수 있다. (위 사례는 전통적인 SSR, 즉 고전방식의 SSR 방식에서 그러하다. 여기서 전통적인 SSR이라 함은 정적페이지만 서버측에서 렌더링해주는 것으로 이해할 수 있을 듯 하다.)
따라서 SSR 방식의 장점은 다음과 같은 것이 있다.
반면 단점으로는 각 페이지별로 매번 로딩시간 및 새로고침 현상이 발생한다는 점은 UX및 UI에 심각한 영향을 초래할 수 있다. 또한 서버에서 렌더링을 마친다는 것은 서버가 담당하는 일이 더욱 많아지는 것이므로 부하에 걸릴 위험도 존재한다고 한다.
그렇다면 SPA 개념과 등장한 CSR 방식의 작동원리를 보자. 하나의 페이지에서 여러 페이지를 보여준다는 것은 결국엔 자바스크립트를 이용해서 페이지의 일부분이나 전체를 갈아치우는 것으로 생각해볼 수 있다. 리액트 라이브러리를 이용해 링크 이동과 같은 기능울 내부적으로 구현 시 Router를 설치하여 사용하지만 결국 이러한 파일(jsx 및 js)들은 (CRA 환경 이라면) Webpack과 같은 번들링 도구를 거쳐 하나의 (또는 여러개의 chunk파일로) 거대한 js파일로 번들링되게 될 것이다. SPA에서는 이처럼 번들링 된 js를 전달받아 Single Page Application을 구축하게 되는 것이다.
즉 이 말은 CSR 방식에서는 이 번들링이 완료된 js 파일을 모두 로드하기 전에는 첫 페이지를 로드할 수가 없다. 엄연히 말해서 첫 페이지는 이미 로드가 되었지만, 로드된 페이지는 빈 HTML 파일이다. 실제로 npx create-react-app ... 실행 후 public/index.html 파일을 확인해보면 다음과 같이 구성되어 있다.
...
<div id='app'></div>
...
즉 유저는 로딩이 완료되기까지 그저 빈 화면을 보고 있을 수 밖에 없다. 또한 첫 페이지가 위와 같은 빈 화면이라는 말은 검색 엔진이 해당 문서를 바라볼 때 기입된 내용이 없기 때문에 SEO 최적화에도 많은 어려움이 따른다. (또한 CSR에서는 meta tag 수정 등의 어려움 등도 존재하기에 더욱 어렵다) 물론 Code Splitting 등의 기법으로 로딩 시간을 줄일 수 있는 기법들이 있지만 이번 포스팅에서는 생략하고 본론에 다시 집중하도록 하자.
그럼에도 CSR 방식은 다음과 같은 장점이 있다.
이 부분은 개발자의 선택에 달려있다. CSR 방식의 초기 로딩 속도가 SSR에 비해 느리다고 하지만, 자신이 코딩한 파일이 대용량의 데이터가 아니라면 크게 지장이 되는 지연시간이 아닐 수도 있다. 또한 이런 로딩 지연 시간은 SSR을 채택하지 않더라도 개선할 수 있는 기법 등이 다양하다.
반면 개발할 페이지가 검색 엔진에 노출이 되어야 하는 것이 우선일 수 있다. 이 경우에는 SSR 적용이 우선시 되어야 할 것이다.
이런 생각을 한 번 해보자. 첫 로딩에 시간이 오래 걸리는 CSR의 단점과, 각 페이지마다 새로 로딩이 요구되는 SSR의 단점을 합친다면 이를 극복할 수 있지 않을까?
이러한 생각에서 탄생한 여러 프레임워크들이 존재한다. Vue의 경우엔 Nuxt.js가 대표격인 것 같고, React의 경우엔 Next.js / Gatsby.js 등이 있다. 물론 프레임워크를 사용하지 않고 순수 React에서 여러 설정들을 건드려 SSR을 지원하도록 할 수도 있다고 한다.
이렇게 SPA 형태에 SSR을 지원하도록 설정한다면,
첫 페이지 로딩은 SSR 방식으로 기존 CSR 방식보다 빠르게 문서를 받아옴과 동시에 해당 문서는 서버측에서 렌더링이 완료되었으므로 SEO 적용 또한 가능하다. 그 이후에 렌더링 될 페이지는 그 사이 번들링 된 js 파일을 받아서 CSR 방식으로 수행한다면 두 가지 렌더링 방식들이 가지고 있던 단점들을 어느정도 극복할 수 있다. 즉 SPA 형태에서 두 가지 렌더링 방식을 적절히 혼합해 사용함으로써 기존 방식들이 가지고 있던 단점을 극복하는 것이다.
다음 포스팅에서는 React에서 SSR 지원이 가능하도록 해주는 프레임워크인 Next.js를 사용하여 실제 CSR 방식과 SSR 방식의 차이점과 이 둘을 혼합하여 구동하는 방식의 실제 예시를 살펴보자.
오타 및 오류 지적 등은 언제든지 댓글로 부탁드립니다.