4장 서버 사이드 렌더링(1)
React Deep Dive ·이번 장에서는 리액트를 활용한 서버 사이드 렌더링(Server—Side Rendering: SSR)에 대해 알아보고자 한다. 과거 리액트 애플리케이션을 만들 때 Create React App(create-react-app)이 각광받았지만 요즘은 서버 사이드 렌더링을 지원하는 Next.js 같은 프레임워크를 사용해 프로젝트를 만드는 것이 큰 인기를 끌고 있다. 이에 따라 리액트 개발자라면 리액트뿐만 아니라 서버 사이드 렌더링에 대해서도 이해하는 것이 중요해 지고 있다. 서버 사이드 렌더링의 정의와 함께 이를 리액트로 구현하는 방법까지 알아보자.
4.1 서버 사이드 렌더링이란?
- 본격적으로 리액트 서버 사이드 렌더링 코드를 작성하기에 앞서 서버 사이드 렌더링이란 무엇인지, 왜 서버 사이드 렌더링이 최근에 각광받게 됐는지 먼저 이론적인 측면을 살펴보고자 한다.
4.1.1 싱글 페이지 애플리케이션의 세상
- 서버 사이드 렌더링이 무엇인지 설명하기에 앞서 먼저 서버 사이드 렌더링 애플리케이션과 반대되는 개념인 싱글 페이지 애플리케이션에 대해 먼저 살펴보자.
싱글 펭지 애플리케이션이란?
- 싱글 페이지 애플리케이션(Single Page Application; SPA)이란 렌더링과 라우팅에 필요한 대부분의 기능을 서버가 아닌 브라우저의 자바스크립트에 의존하는 방식을 의미한다. 최초에 첫 페이지에서 데이터를 모두 불러온 이후에는 페이지 전환을 위한 모든 작업이 자바스크립트와 브라우저의 history.pushstate와 history.replacestate로 이뤄지기 때문에 페이지를 불러온 이후에는 서버에서 HTML을 내려받지 않고 하나의 페이지에서 모든 작업을 처리하므로 싱글 페이지 애플리케이션이라고 한다.
전통적인 방식의 애플리케이션과 싱글 페이지 애플리케이션의 작동 비교
- 이와 반대로 과거 서버 사이드에서 작동하던 전통적인 방식의 애플리케이션을 상상해 보자. 페이지 전환이 발생할 때마다 새롭게 페이지를 요청하고, HTML 페이지를 다운로드해 파싱하는 작업을 거친다. 이 과정은 페이지를 처음부터 새로 그려야 해서 일부 사용자는 페이지가 전환될 때 부자연스러운 모습을 보게 된다.
- 그러나 이러한 페이지 전환을 모두 자바스크립트로 한다면 최초에 한번 모든 리소스를 다운로드하고 나면 이후 페이지를 전환할 때 추가로 리소스를 다운로드하는 시간이 필요 없어진다. 그리고 경우에 따라 페이지 전체를 새로 렌더링하는 것이 아니라 페이지 전환에 필요한 일부 영역만 다시 그리게 되므로 훨씬 더 매끄러운 UI를 보여줄 수 있게 된다
싱글 페이지 렌더링 방식의 유행과 JAM 스택의 등
- 이러한 장점을 발판으로 근래에 개발된 많은 웹페이지들이 싱글 페이지 렌더링 방식을 채택했다. 그렇다면 이러한 자바스크립트 위주의 싱글 페이지 렌더링 방식은 어떻게 등장하게 된 것일까?
- 과거 PHP나 JSPGavaServer Pages)를 기반으로 대부분의 웹 애플리케이션이 만들어졌을 때는 거의 대부분의 렌더링이 서버 사이드에서 이뤄졌다. 페이지를 요청하면 서버에서 완성된 HTML을 내려받고, 또 페이지 이동이 있으면 새로운 페이지를 서버에서 내려받는 방식이었다. 여기서 자바스크립트는 어디까지나 사용자에게 추가적인 경험을 주기 위한 보조적인 수단으로 사용됐다.
- 그러나 자바스크립트가 서서히 다양한 작업을 수행하게 되면서 자바스크립트를 모듈화하는 방안이 점차 논의되기 시직됐고 그에 따라 등장한 것이 CommonJS와 AMD(Asynchronous Module Definition)다. 이러한 자바스크립트 모듈화의 결실, 그리고 사용자 기기의 성능 향상과 인터넷 속도의 발전 등으로 자바스크립트에서 할 수 있는 일이 점차 다양해지기 시작했다.
- 이러한 변화에 힘입어 2010년경 Backbone.js와 Angularjs, Knockout.js 등이 등장하면서 자바스크립트 수준에서 MVx 프레임워크를 구현하기 시작했다. 이는 자바스크립트에서도 어느 정도 서버에서만 할 수 있는 복잡한 작업을 할 수 있다는 것을 의미했고, 이때부터 자바스크립트의 역할과 규모가 점점 커져갔다.
- 이러한 프레임워크의 인기는 자바스크립트의 역할을 더욱 가중시켰고, 이후로 우리가 잘 알고 있는 React, Vue, Angular의 시대가 오게 된다.
- 싱글 페이지 애플리케이션, 즉 클라이언트 사이드 라우팅이 널리 퍼지게 된 것은 단순히 사용자에게 좀 더 멋진 UX를 제공하는 것이 가능해져서만은 아니다. PHP 시절, 웹 애플리케이션을 만들기 위해서는 자바스크립트 외에도 신경 쓸 것이 많았지만 싱글 페이지 애플리케이션에서는 단지 브라우저 내부에서 작동하는 자바스크립트만 잘 작성하면 문제없다. 즉, 프런트엔드 개발자들에게 좀 더 간편한 개발 경험을 제공했고, 더욱 간편하게 웹 애플리케이션을 만들 수 있다는 장점이 있다. 이러한 장점과 시대적인 요구로 많은 싱글 페이지 애플리케이션이 개발되기 시작했다.
- 앞서 언급한 프레임워크의 등장으로 등장한 것이 바로 JAM(JavaScript, API, Markup) 스택이다. 대부분의 작업을 자바스크립트에서 수행할 수 있었기 때문에 프런트엔드는 자바스크립트와 마크업(HTML, CSS)을 미리 빌드해 두고 정적으로 사용자에게 제공하면 이후 작동은 모두 사용자의 클라이언트에서 실행되므로 서버 확장성 문제에서 좀 더 자유로워질 수 있게 됐다.
새로운 패러다임의 웹서비스를 향한 요구
- 많은 양의 리소스가 자바스크립트로 넘어오기 시작하던 때, 자바스크립트 코드의 규모도 점차 커지면서 이에 대해 우려의 목소리도 조금씩 나오기 시작했다. 다만 이 시기에 있었던 폭발적인 기술의 발전으로 이러한문제가 자연스럽게 해결될 것이라 기대하기도 했었다. 왜냐하면 인터넷 속도는 날이 갈수록 빨라졌고, 프로세서나 메모리 등 하드웨어 성능 또한눈부시게 발전을 거듭했기 때문이다. 즉, 웹페이지를 불러오는 데 필요한 부담을 일정 부분 사용자에게 전가하더라도 사용자의 기기나 인터넷 환경이 더 빠르게 발전할 것이기 때문에 괜찮을 것이라는 기대감이 팽배했다. 그러한 기대에 부응하기라도 하듯 웹 애플리케이션에서 제공하는 자바스크립트 리소스의 크기와 수가 모두 증가하기 시작했다.
- 그렇다면 웹페이지 속도는 얼마나 개선됐을까? 정말 이러한 기대에 부응할 만큼 사용자의 디바이스가 크기도 커지고 개수도 더욱 많아진 자바스크립트 리소스를 효과적으로 처리하고 있을까?
- 모바일 기기의 성능은 날이 갈수 록 좋아지고 있지만 모바일에서의 웹페이지 로딩은 여전히 20초 가까이 걸릴 정도로 오래 걸린다는 것을 알 수 있다.
- 물론 이 모든 것이 싱글 페이지 애플리케이션의 탓이라는 것은 절대 아니다. 과거 웹 애플리케이션은 단순히 무언가 정보를 보여주기 위한 수단에 불과했지만 현재의 웹 애플리케이션은 정말 다양한 작업을 처리하고 있고, 심지어 하이브리드 애플리케이션의 형태로 앱 내부에서도 마치 웹처럼 구동되는 경우도 많다. 과거의 웹과 현재의 웹의 기능을 비교하면 정말 천지차이다. 그럼에도 중요한 사실 중 하나는 사용자의 기기와 인터넷 속도 등 웹 전반을 이루는 환경이 크게 개선됐음에도 실제 사용자들이 느끼는 웹 애플리케이션의 로딩 속도는 5년 전이나 지금이나 크게 차이가 없거나 오히려 더 느리다는 것이다.
- 웹사이트 방문자들은 참을성이 없기에 개발자들은 제품의 웹 서비스 환경에 대해 한 번 더 고민 할때다.
4.1.2 서버사이드렌더링이란?
- 싱글 페이지 애플리케이션이 자바스크립트를 활용해 하나의 페이지에서만 렌더링을 수행한다면, 서버 사이드 렌더링은 최초에 사용자에게 보여줄 페이지를 서버에서 렌더링해 빠르게 사용자에게 화면을 제공하는 방식을 의미한다.
- 앞서 언급했던, 웹페이지가 점점 느려지는 상황에 대한 문제의식을 싱글 페이지 애플리케이션의 태생적인 한계에서 찾고, 이를 개선하고자 서버에서 페이지를 렌더링해 제공하는 기존 방식의 웹 개발이 다시금 떠오르고 있다.
- 싱글 페이지 애플리케이션과 서버에서 페이지를 빌드하는 서버 사이드 렌더링의 차이는 웹페이지 렌더링의 책임을 어디에 두느냐다. 싱글 페이지 애플리케이션은 사용자에게 제공되는 자바스크립트 번들에서 렌더링을 담당하지만 서버 사이드 방식을 채택하면 렌더링에 필요한 작업을 모두 서버에서 수행한다. 클라이언트의 렌더링은 사용자 기기의 성능에 영향을 받지만 서버 사이드 렌더링은 서버에서 제공하기 때문에 비교적 안정적인 렌더링이 가능하다.
서버 사이드 렌더링의 장점
- 최초 페이지 렌더링을 서버에서 수행하는 것은 싱글 페이지 애플리케이션 대비 몇 가지 장점이 있다. 서버 사이드 렌더링의 장점은 다음과 같다.
최초 페이지 진입이 비교적 빠르다
- 사용자가 최초 페이지에 진입했을 때 페이지에 유의미한 정보가 그려지는 시간(First Contentful Paint)이 더 빨라질 수 있다. 싱글 페이지 애플리케이션이라면 사용자가 해당 페이지에 진입하고, 자바스크립트 리소스를 다운로드하고, HTTP 요청을 수행한 이후에 이 응답의 결과를 가지고 화면을 렌더링해야 할 것이다. 그러나 이러한 작업이 서버에서 이뤄진다면 한결 빠르게 렌더링될 수 있다.
- 일반적으로 서버에서 HTTP 요청을 수행하는 것이 더 빠르고, 또 HTML을 그리는 작업도 서버에서 해당 HTML을 문자열로 미리 그려서 내려주는 것이 클라이언트에서 기존 HTML에 삽입하는 것보다 더 빠르기 때문이다.
- 모든 경우에 서버 사이드 렌더링이 초기 페이지 렌더링에 비해 이점을 가진다고 볼 수 없지만 화면 렌더링이 HTTP 요청에 의존적이거나 렌더링해야 할 HTML의 크기가 커진다면 상대적으로 서버 사이드 렌더링이 더 빠를수 있다.
검색 엔진과 SNS 공유 등 메타데이터 제공이 쉽다
-
서버 사이드 렌더링은 검색 엔진 최적화에 유용하다. 왜 서버 사이드 렌더링이 검색 엔진 최적화에 유용한지이해하려면 먼저 검색 엔진이 사이트에서 필요한 정보를 가져가는 과정을 알아야 한다.
- 검색 엔진 로봇(머신)이 페이지에 진입한다.
- 페이지가 HTML 정보를 제공해 로봇이 이 HTML을 다운로드한다. 단, 다운로드만 하고 자바스크립트 코드는 실행하지 않는다.
- 다운로드한 HTML 페이지 내부의 오픈 그래프(Open Graph)나 메EKmeta) 태그 정보를 기반으로 페이지의 검색(공유) 정보를 가져오고 이를 바탕으로 검색 엔진에 저장한다.
누적 레이아웃 이동이 적다
- 서버 사이드 렌더링은 누적 레이아웃 이동(Cumulative Layout Shift)을 줄일 수 있다. 누적 레이아웃 이동이란 사용자에게 페이지를 보여준 이후에 뒤늦게 어떤 HTML 정보가 추가되거나 삭제되어 마치 화면이 덜컥 거리는 것과 같은 부정적인 사용자 경험을 말한다.
- 싱글 페이지 애플리케이션에서는 페이지 콘텐츠가 API 요청에 의존하고, API 요청의 응답 속도가 제각각이며, 이를 적절히 처리해두지 않는다면 이러한 누적 레이아웃 이동 문제가 발생할 수 있다. 반면 서버 사이드 렌더링의 경우에는 이러한 요청이 완전히 완료된 이후에 완성된 페이지를 제공하므로 이러한 문제에서 비교적 자유롭다.
사용자의 디바이스 성능에 비교적 자유롭다
- 자바스크립트 리소스 실행은 사용자의 디바이스에서만 실행되므로 절대적으로 사용자 디바이스 성능에 의존적이다. 그러나 서버 사이드 렌더링을 수행하면 이러한 부담을 서버에 나눌 수 있으므로 사용자의 디바이스 성능으로부터 조금 더 자유로워질 수 있다.
보안에 좀 더 안전하다
- JAM 스택을 채택한 프로젝트의 공통된 문제점은 애플리케이션의 모든 활동이 브라우저에 노출된다는 것이다. 프런트엔드 개발자라면 모두가 알겠지만 브라우저의 개발자 도구를 사용하면 웹사이트에서 일어나는 거의 대부분의 작업을 파악할 수 있다
- 반면 서버 사이드 렌더링의 경우 인증 혹은 민감한 작업을 서버에서 수행하고 그 결과만 브라우저에 제공해 이러한 보안 위협을 피할 수 있다는 장점이 있다.
서버 사이드 렌더링의 단점
- 그러나 서버 사이드 렌더링이 마냥 좋은 것만은 아니다. 서버 사이드 렌더링을 적용하기에 앞서 몇 가지를 고려해야 한다.
소스코드를 작성할 때 항상 서버를 고려해야 한다
- 서버 사이드 렌더링을 적용하기로 결정했다면 소스코드 전반에 걸쳐 서버 환경에 대한 고려가 필요하다. 그 중 가장 큰 문제가 바로 브라우저 전역 객체인 window 또는 sessionstorage와 같이 브라우저에만 있는 전역 객체 등이다.
- 이러한 서버에 대한 고려는 작성한 코드뿐만 아니라 외부에서 의존하고 있는 라이브러리도 마찬가지다. 해당 라이브러리가 마찬가지로 서버에 대한 고려가 돼 있지 않다면 다른 대안을 찾거나 클라이언트에서만 실행될 수 있도록 처리해야 한다.
- 잠재적인 위험을 가진 코드를 모두 클라이언트에서 실행하는 것 또한 궁극적인 해결책이 되지 못한다. 클라이 언트에서만 실행되는 코드가 많아질수록 서버 사이드 렌더링의 장점을 잃는 셈이다.
적절한 서버가 구축돼 있어야 한다
- 서버 사이드 렌더 링은 말 그대로 사용자의 요청을 받아 렌더링을 수행할 서버가 필요하다. 그러나 서버를 구축하는 것은 절대 쉬운 일이 아니다. 사용자의 요청에 따라 적절하게 대응할 수 있는 물리적인 가용량을 확보해야 하고, 때로는 예기치 않은 장애 상황에 대응할 수 있도록 복구 전략도 필요하다.
서비스 지연에 따른 문제
- 예를 들어, 싱글 페이지 애플리케이션에서 무언가 느린 작업이 있다고 해보자. 싱글 페이지 애플리케이션은 그래도 최초에 어떤 화면이라도 보여준 상태에서 무언가 느린 작업이 수행되기 때문에 ‘로딩 중’과 같이 작업이 진행 중임을 적절히 안내한다면 충분히 사용자가 기다릴 여지가 있다.
- 반면 서버 사이드 렌더링에서 지연이 일어나면 어떻게 될까? 특히 이 지연 작업이 최초 렌더링에 발생한다면 큰 문제가 된다. 서버 사이드 렌더링은 서버에서 사용자에게 보여줄 페이지에 대한 렌더링 작업이 끝나기까지는 사용자에게 그 어떤 정보도 제공할 수 없다.
4.1.3 SPA와 SSR을 모두 알아야 하는 이유
- 세상의 모든 진리와 마찬가지로, 서버 사이드 렌더링 또한 모든 문제의 해결책이 될 수는 없다. 따라서 우리는 이 러한 모든 방법론을 이해할 필요가 있다. 그 이유에 대해 살펴보자.
서버 사이드 렌더링 역시 만능이 아니다
- 클라이언트에서 발생하는 모든 무거운 작업을 서버에 미루고, 작업이 모두 서버에서 이뤄진다고 해서 모든 성능 문제가 해결되는 것은 아니다. 잘못된 웹페이지 설계는 오히려 성능을 해칠 뿐만 아니라 눈에 띄는 성능 개선도 얻지 못하고 서버와 클라이언트 두 군데로 관리 포인트만 늘어나기만 하는 역효과를 낳을 수도 있다.
- 웹페이지에서 사용자에게 제공하고 싶은 내용이 무엇인지, 또 어떤 우선순위에 따라 페이지의 내용을 보여줄지를 잘 설계하는 것이 중요하다. 웹페이지의 설계와 목적, 그리고 우선순위에 따라 싱글 페이지 애플리케이션이 더 효율적일 수도 있다.
싱글 페이지 애플리케이션과 서버 사이드 렌더링 애플리케이션
-
두 방법론 중 어느 것이 옳다고 단언할 수는 없지만 적어도 싱글 페이지 애플리케이션과 LAMP 스택과 같이 서버에서 모든 페이지를 각각 빌드하는 서버 사이드 렌더링 방식인 멀티 페이지 애플리케이션에 대해서는 다음과 같이 이야기할 수 있다.
-
- 가장 뛰어난 싱글 페이지 애플리케이션은 가장 뛰어난 멀티 페이지 애플리케이션보다 낫다. 일례로 앞서 예제로 보여준 Gmail과 같이 완성도가 매우 뛰어난 싱글 페이지 애플리케이션이 있다고 가정해 보자.
- 최초 페이지 진입 시에 보여줘야할 정보만 최적화해 요청해서 렌더링하고, 이미지와 같은 중요성이 떨어지는 리소스는 게으른 로딩으로 렌더링에 방해되지 않도록 처리했으며, 코드 분할(code splitting. 사용자에게 필요한 코드만 나눠서 번들링하는 기법) 또한 칼같이 지켜서 불필요한 자바스크립트 리소스의 다운로드 및 실행을 방지했다. 라우팅이 발생하면 변경이 필요한 HTML 영역만 교체해 사용자의 피로감을 최소화했다. 모든 것이 완벽하다.
-
- 평균적인 싱글 페이지 애플리케이션은 평균적인 멀티 페이지 애플리케이션보다 느리다. 멀티 페이지 애플리케이션은 매번 서버에 렌더링 요청을 하고. 서버는 안정적인 리소스룔 기반으로 매 요청마다 비슷한 성능의 렌더링을 수행할 것이다.
- 그러나 일반적인 싱글 페이지 애플리케이션은 렌더링과 라우팅에 최적화가 돼 있지 않다면 사용자 기기에 따라 성능이 들쑥 날쑥하고, 적절한 성능 최적화도 돼 있지 않을 가능성이 높으므로 멀티 페이지 애플리케이션 대비 성능이 아쉬울 가능성이 크다. 그리고 이러한 최적화는 매우 어렵다. 페이지 전환 시에 필요한 리소스와 공통으로 사용하는 리소스로 분류하고 이에 따른 다운로드나 렌더링 우선순위 전략을 잘 수립해 서비스하기란 매우 어렵다.
-
-
결국 우리는 앞의 두 방법론이 모두 상황에 따라 유효한 방법이라는 것을 먼저 이해해야 한다. 두 가지 모두 장단점이 있으며 어느 하나가 완벽하다고 볼 수 없다. 싱글 페이지 애플리케이션이 제공하는 보일러플레이트나 라이브러리가 점차 완벽해지면서 잠재적인 모든 위험을 제거할 수도 있고, 멀티 페이지 애플리케이션이 브라우저 API의 도움을 받아 싱글 페이지 애플리케이션과 같은 끊김 없는 사용자 경험을 제공할 수도 있다.
현대의 서버 사이드 렌더링
- 먼저 기존 LAMP 스택은 모든 페이지 빌드를 서버에서 렌더링해 초기 페이지 진입이 빠르다는 장점이 있지만 이후에 라우팅이 발생할 때도 마찬가지로 서버에 의존해야 하기 때문에 싱글 페이지 렌더링 방식에 비해 라우팅이 느리다는 단점이 있다.
- 그래서 요즘의 서버 사이드 렌더링은 이 두 가지 장점을 모두 취한 방식으로 작동한다. 먼저, 최초 웹사이트 진입 시에는 서버 사이드 렌더링 방식으로 서버에서 완성된 HTML을 제공받고, 이후 라우팅에서는 서버에서 내려받은 자바스크립트를 바탕으로 마치 싱글 페이지 애플리케이션처럼 작동한다.
- 앞으로 살펴볼 Next.js, 그리고 Remix 등 요즘 각광받는 서버 사이드 렌더링 프레임워크는 모두 이러한 방식으로 작동해 사용자에게 더 나은 웹사이트 경험을 안겨준다.
4.1.4 정리
- 지금까지 서버 사이드 렌더링은 무엇이고, 또 어떠한 장단점이 있는지 살펴봤다. 리액트 개발자라면, 특히 다수의 사용자에게 좋은 사용자 경험을 제공할 수 있는 웹 애플리케이션을 만들고 싶은 개발자라면 두 가지 방법을 모두 숙지할 필요가 있다. 둘 중 어느 것이 완벽하게 옳다고 말할 수 없으므로 두 가지 모두를 이해하고 필요에 따라 맞는 방법을 사용할 수 있다.