이 글은 드림코딩 유튜브 채널의 무료 영상인 서버사이드 렌더링 (개발자라면 상식으로 알고 있어야 하는 개념 정리)를 정리한 것입니다.
1990년 중반까지는 모두 static sites였다. 서버에 이미 잘 만들어진 html 문서들이 있고, 사용자가 사이트에 접속하면 해당하는 HTML문서를 서버로부터 받아와 보여주는 형식이다.
문서내에서 또 다른 문서를 담을 수 있는 iframe 태그가 도입돼 페이지 내에서 부분적으로 문서를 받아와 업데이트 할 수 있게 되었다.
fetch API의 원조인 XMLHttpRequest API가 개발되어 HTML문서 전체가 아니라 JSON과 같은 포맷으로 서버에서 가볍게 필요한 데이터만 받아올 수 있게 되었다. 받아온 데이터를 자바스크립트를 이용해서 동적으로 HTML 요소를 생성해서 페이지에서 업데이트 하는 방식임
이러한 방식이 공식적으로 AJAX라는 이름을 가지게 됨
사용자가 한 페이지 내에 머무르면서 AJAX로 필요한 데이터를 받아와 부분적으로만 업데이트 하게 되어, 하나의 어플리케이션을 사용하듯 사용성이 좋아졌다.
이런 SPA 트렌드 + 사용자들의 PC성능 향상 + JS 표준화 + 강력한 커뮤니티 바탕 => Angular, React, Vue와 같은 프레임워크가 나와 본격적으로 CSR 시대로 접어든다.
사용자가 사이트에 접속하면 서버에서 index라는 HTML파일을 클라이언트에 보내준다. 이때 받는 index 파일은 body 안에는 id="root"만, 그리고 어플리케이션에서 필요한 자바스크립트 링크만 들어있는 가장 추상적이고 심플하게 이루어져 있다.
이 HTML이 텅텅 비어져 있기 때문에 처음 접속 시 빈 화면만 보인다. 다시 링크된 JS파일을 서버로부터 받아오는데 이때 이 JS파일에는 어플리케이션에 필요한 로직들 뿐만 아니라 어플리케이션을 구동하는 프레임워크와 라이브러리의 소스코드들도 다 포함되어 있다. 그러므로 굉장히 사이즈가 커서 다운로드 받는 데 시간이 꽤 소요된다.
이후 추가로 필요한 데이터가 있다면 서버로 요청해서 데이터를 받아온 다음, 이것들을 기반으로 동적으로 HTML을 생성해 드디어 사용자에게 최종적인 어플리케이션을 보여주게 된다.
사용자가 첫 화면을 보기까지 시간이 오래 걸릴 수 있다.
썩 좋지 않은 SEO(Search Engine Optimization)
구글, 네이버와 같은 검색엔진들은 서버에 등록된 웹사이트를 하나씩 돌아다니면서 웹사이트의 HTML 문서를 분석해 '어떤 title과 description이 있으니깐 이런 검색어로 찾아줄 수 있는 웹사이트군! 그리고 여기 이런 링크들이 있으니깐 이것도 검색엔진에 등록해 놔야겠어!' 라고 판단하여 우리가 웹사이트를 빠르게 검색할 수 있도록 도와주는데, SCR에서 사용되어지고 있는 HTML body는 대부분 텅텅 비어져 있기 때문에 검색엔진들이 CSR로 작성된 웹페이지를 분석하는 데 어려움이 있다.
CSR의 문제점으로 인해 이전의 Static Sites에서 영감을 받은 SSR이 도입되게 된다.
SSR은 웹사이트에 접속하면 서버에서 미리 필요한 데이터들을 모두 가져와 만든 HTML 파일 보내주어, 사용자가 웹사이트를 볼 수 있게 한다. 이후 서버에 HTML 파일을 동적으로 제어할 수 있는 JS파일을 요청해 받아오게 되면 이때부터 사용자의 클릭과 같은 인터렉션들을 처리할 수 있게 된다.
웹사이트 성능 분석시 TTV와 TTI도 중요한 요소로 사용된다.
TTV(Time To View)
사용자가 웹사이트를 보는데까지 걸리는 시간
TTI(Time To Interact)
사용자가 클릭을 하거나 인터렉션이 가능하게 되는데 걸리는 시간
CSR은 사용자가 웹사이트를 볼 수 있음과 동시에 사용자가 인터렉션이 가능해진다.
그러므로 최종적으로 번들링해서 사용자에게 보내주는 자바스크립트 파일을 어떻게 하면 효율적으로 분할할 수 있을지, 어떻게 하면 사용자가 첫 페이지를 보기위해 필수적으로 필요한 것만 보낼 수 있을지 고민해봐야한다.
SSR은 사용자가 웹사이트를 볼 수 있는 시기와 인터렉션이 가능한 시기의 공백기간이 꽤 존재한다.
그러므로 이 시간의 단차를 줄이기 위해 어떤 노력을 해야할지, 어떻게 더 매끄러운 UI와 UX를 제공할 수 있을지 고민해봐야한다.
리액트 같은 경우 CSR에 특화된 라이브러리지만 Gatsby라는 라이브러리와 함께 사용하면 라액트로 만든 웹 어플리케이션을 정적으로 웹페이지를 미리 생성해두어 서버에 배포해 놓을 수가 있다. 이때 만들어둔 웹페이지는 꼭 정적인 것만은 아니다. 추가적으로 데이터를 서버에서 받아오거나 동적으로 처리해야하는 로직이 있다면 자바스크립트 파일을 함께 가지고 있을 수 있기 때문에 동적인 요소도 충분히 추가할 수 있다.
Next.JS는 강력한 서버사이드 렌더링을 지원하는 라이브러리로, Gatsby 다음으로 많이 사용되어지는 것이다. 이는 CSR과 SSR를 잘 섞어서 좀 더 강력하고 유연하게 사용할 수 있도록 지원하고 있다. (SSG O)
사이트가 동적인지 정적인지, 얼마나 자주, 얼마나 많은 사용자가 있는지에 따라 TTV와 TTI를 고려해 유연하게 섞어서 개발해 나가는 걸 추천한다. 로그인을 하고, 동적인 데이터가 있는 경우 무리하게 SSR을 하기 보다는 CSR을 이용해서 하나의 번들링이 아니라 splitting을 해두어서 cache를 적극적으로 사용하는게 좋은 것 같다.
어떤 방식이라도 HTML을 받아와야 어떤 JS가 필요한지 브라우저가 인식하고 그걸 다시 받아온다. 그 과정이 결국엔 사용자 컴퓨터 성능과 네트워크 환경에 영향을 받기 때문에 ServiceWorker를 적극 활용하는 것도 방법이다.
어차피 모듈화된 JS들은 빌드시에 이름과 디렉토리를 전부 인지하고 있기에 첫 스크립트 로딩직후에 ServiceWorker로 미리 받아와서 캐싱해두는 형태로 활용하자.
SSG를 쓰면 그래도 랜더링 로직이 최소화되면서 스크립트 다운로드 + 로딩 시간이 짧아지긴 하지만, 어플리케이션이 커지고 인터렉티브 요소가 많아지면 CSR이나 SSR대비 큰 차이를 느끼긴 힘들다.
CI/CD환경 구축시점에서도 빌드에 많은 리소스가 요구되는 SSG의 특성상 개발 파이프라인에 빌드용 클라우드 컴퓨터가 따로 있지만, 이는 빌드용으로만 쓰이므로 성능이 좋지 못하고 디플로이까지 시간이 오래걸린다.
따라서 로그인이 필요없는 페이지는 SEO때문에 SSR로, 로그인이 필요한 페이지는 어차피 SEO에 영향을 안받으니까 CSR로 만든후에 ServiceWorker를 붙이는 방식으로 만드는 것을 추천한다.
🔥 추가 정보
ServiceWorker best practice와 보일러플레이트 코드를 줄여줄 수 있는 라이브러리
https://developers.google.com/web/tools/workbox