📖 개요

SPA와 SSR, 그리고 브라우저 동작 원리에 대해 알아보겠습니다. 이전 사내 개발자 컨퍼런스에서, SPA와 SSR, 그리고 브라우저 동작 원리에 대한 내용을 주제로 발표를 하게 되었는데 아무래도 다른 분야에서는 크게 중요하지 않은 내용이지만 결국엔 우리가 개발하는 모든 과정이 서로 긴밀하게 연결되어 있고 그 과정에서 다른 직군의 기술이나 정보를 얻게 되면 각자의 역할을 이해하며 더 좋은 결과를 만들어낼 수 있다고 생각합니다

앞으로도 이런 기초적인 원리들을 잘 이해하고, 최신 기술들을 적극적으로 도입하여 더 나은 제품을 만들기 위해 노력하면 좋겠습니다.

이 내용이 여러분의 업무에도 도움이 되기를 바라며, 함께 제품을 만들어 가는 과정에서 서로의 역할을 더 깊이 이해하고 협력하는 계기가 되었으면 합니다.

지! 이제 발표 내용을 간단히 정리해보겠습니다.


🧎🏻‍♂️ 프론트엔드와 백엔드가 왜 분리됐는가

본 주제를 시작하기에 앞서 간단하게 프론트엔드와 백엔드가 왜 분리됐는지를 알아야합니다. 다양한 이유가 있겠지만 가장 큰 이유는 웹 트렌드의 변화에 있습니다. web_trend.png

웹 기술이 발전하며 사용자는 더 많은 상호작용을 하면서도 우수한 사용성의 서비스를 원했습니다. 위 요구사항을 충족하기 위해서 각각의 상호작용마다 필요한 데이터만을 전송하는 비동기 통신 방식이 발전했습니다. 이 기술을 통해서 사용자와의 많은 상호작용에도 빠르고 효율적으로 작동하는 웹서비스 개발이 가능해졌습니다.

이를 반영하여 화면의 공통된 부분을 서버와 분리해서 집중적으로 관리하고 고도화할 필요성이 커지면서 프론트와 백엔드가 분리되게 되었습니다.


🏃🏻‍♂️ 브라우저 동작원리

먼저 브라우저가 클라이언트 단에서 어떻게 렌더링되는지 짧게 설명해드릴게요. 브라우저 구성요소는 다음과 같습니다.

browser_structure.png

가운데 브라우저 엔진을 기준으로 위쪽 ‘유저 인터페이스’는 말 그대로 유저와 상호작용하는 부분입니다.

브라우저 엔진 아래쪽의 렌더링 엔진이 화면을 그리는 화가이고, 맨 밑에 ‘네트워크’, ‘자바스크립트 엔진’, ‘ui 백엔드’는 렌더링 엔진을 도와주는 조수입니다. ‘브라우저 엔진’은 위, 아래 두가지 중요 요소 사이의 중개자라고 생각하시면 됩니다.

추가로 말씀드리자면,

우측 하단의 브라우저 내의 ‘ui 백엔드’는 우리가 흔히 생각하는 백엔드와는 다른 개념입니다.

여기서 말하는 ‘브라우저의 ui 백엔드’는 기본적인 사용자 인터페이스 요소를 렌더링하고 관리하는 부분입니다. 특히 여러 운영체제에서 일관된 ui를 제공할 수 있도록 합니다.

우리가 생각하는 일반적인 백엔드인 서버는 여기 ‘네트워크’와 상호작용합니다.

브라우저는 네트워크를 통해 웹 페이지의 html 문서를 얻어오고 이를 해석하면서 다음과 같이 렌더링을 구현합니다. browser_rendering.png

  1. “파싱” 과정을 수행합니다. 브라우저는 HTML과 CSS를 DOM과 CSSOM 트리로 변환합니다. 조금 더 자세하게 설명하면 파싱 과정을 전문적으로 하는 Parsar를 통해 토큰화된 코드를 구조화하는 과정입니다. 브라우저는 html, css, javascript 세 종류의 언어를 해석하는데 이 중 js는 렌더링 엔진이 아니라 앞선 그림의 ‘자바스크립트 엔진’ 이라는 별도의 레이어에서 해석하므로 렌더링 엔진은 html, css 파싱을 담당합니다.
  2. ”파싱”과정이 끝나면 그 과정에서 만들어진 DOM과 CSSOM 트리를 기반으로 “렌더 트리 생성”을 시작합니다. 랜더트리는 화면에 나타나는 요소를 결정하는 트리이며, DOM과 CSSOM을 조합하여 만들어집니다.
  3. ”레이아웃” 과정을 통해서 각 노드의 위치와 크기를 계산합니다.
  4. 마지막으로 레이아웃을 통해 화면에 배치된 엘리먼트들에게 디자인적 요소를 적용하는 “페인트” 과정을 거쳐 픽셀단위로 화면에 나타나게 됩니다.

이와 같은 주요한 렌더링 과정을 크리티컬 랜더링 패스라고 부릅니다.

자, 여기까지 브라우저 렌더링에 대해 알아보았습니다. 이제 좀 더 자세히 들어가서 주요 렌더링 방식에 대해 비교를 해보겠습니다!


🚴🏻‍♂️ SSR & CSR

SSR 서버 사이드 렌더링에서 화면을 구성하는 방법입니다

ssr1.png ssr2.png

  1. 프론트엔드에서 원하는 페이지를 백엔드에게 요청합니다.
  2. 서버는 렌더링 준비를 마친 HTML, JavaScript만을 응답하고, 브라우저는 HTML을 화면에 ‘바로’ 렌더

잠깐! 어떻게 HTML을 바로 화면에 렌더할 수 있었을까요?

ssr3.png

그 이유는 이미 서버에서 렌더링 준비를 마치고 응답했기 때문입니다!

ssr4.png

그리고 나서 자바스크립트를 다운로드 하고, 비로소 HTML에 자바스크립트 로직을 매칭하는 하이드레이션(hydration)과정을 진행합니다.

매번 클라이언트에서 서버에 요청할 때마다 이러한 과정을 반복하는 것이 서버 사이드 렌더링이 화면을 구성하는 방법입니다!


CSR 클라이언트 사이드 렌더링이 화면을 구성하는 방법입니다

csr1.png

  1. 첫 번째로 클라이언트에서 서버로 컨텐츠를 요청합니다. 서버에서는 HTML 뼈대 그리고 연결된 자바스크립트 링크를 응답합니다. 그리고 이때 클라이언트에서는 서버로부터 전체 자바스크립트를 다운 받습니다.
  2. 브라우저 엔진은 받아온 자바스크립트로 동적 DOM을 생성하고 화면을 띄웁니다. 이후에 추가 페이지 요청이 있는 경우, 필요한 부분만 변경합니다

두 렌더링 방식의 장점을 알아보겠습니다.

SSR

  1. 초기 구동 속도가 상대적으로 빠릅니다.
  2. 서버에서 렌더링을 수행하기 때문에 디바이스 성능을 덜 고려해도 됩니다. 이 장점은 클라이언트 사이드 렌더링의 단점이기도 하죠.
  3. 웹 엔진 크롤러 봇은 HTML의 내용을 바탕으로 정보를 수집합니다. 그래서 빈 HTML을 받아오는 CSR 보다 완성된 html을 받는 SSR이 검색 엔진 최적화에 더 적합합니다

CSR

  1. 초기 구동 속도를 제외하고는 화면 전환 속도가 빠릅니다. 초기 구동 속도는 느리지만 서버의 문제가 있을 때 로딩 중임을 띄워줄 수 있습니다. 사용자가 덜 어색해하겠죠? 또한 이미 자바스크립트를 다운받아서 완성된 화면이 띄워지기 때문에 서버사이드렌더링 처럼 초기 먹통 문제가 발생하지 않습니다.
  2. 클라이언트 측에서 직접 연산과 라우팅 처리를 하기 때문에 전체페이지 리로딩(새로고침)이 없습니다! 서버사이드 렌더링 처럼 화면이 깜빡!이는 현상이 없다는 것입니다. 이는 유연한 사용자 경험을 제공합니다.

🤸🏻 SPA & MPA

SPA

SPA를 이해하려면 SPA의 핵심 개념인 Virtual DOM에 대해 알아야 합니다. Virtual DOM이란 React에서 도입한 개념으로 실제 DOM의 가벼운 복사본입니다. JS 객체 형태로 메모리에 상주하며, 브라우저의 실제 DOM과는 별도로 관리됩니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const virtualDOM = {
  type: 'div',
  props: {
    children: [
      {
        type: 'h1',
        props: {
          children: 'Count: 0',
        },
      },
    ],
  },
};

그럼 여기서 말하는 DOM이란 무엇일까요? 웹 사이트에 접속하면 Element를 볼 수 있습니다. 이 Element들이 모여 하나의 Document를 구성합니다. 이러한 문서의 구조를 프로그래밍 언어가 이해할 수 있도록 표현한 것이 바로 DOM입니다.

spa1.png

DOM은 tree 형태로 표현되며, 각 요소에 해당하는 Node가 존재합니다. 우리가 알고 있는 getElementById, getElementsByClassName 이러한 메소드들이 DOM을 직접 조작하는 방식입니다.

spa2.png

우리가 어떤 Element의 색상을 변경한다고 가정해봅시다. 우리는 해당 코드를 통해 바꿀 수 있죠. 명령을 받은 브라우저는 HTML을 탐색해 해당 Element를 찾고, 해당 Element와 그 밑 tree에 해당하는 자식 Element를 DOM에서 제거합니다.

spa3.png

이러한 작업을 리플로우, 리페인트 작업이라고 하는데 리플로우는 Element의 레이아웃에 영향을 주는 속성들, 크기 변경이나 위치, 형태등이 변경될 때 발생하고, 리페인트는 Element의 시각적 속성, 색상, 배경 색 등이 변경될 때 발생합니다. 이러한 작은 하나의 변경들은 DOM의 성능에 무리가 있는 작업은 아니나, 계속 반복적으로 변경이 일어나면 충분히 무거워질 수 있는 작업입니다.

spa4.png

Virtual DOM은 이를 해결하기 위해 나왔습니다. Virtual DOM은 앞서 말한 것과 같이 실제 DOM을 복사하여 JS 객체 형태로 존재합니다. SPA는 핵심 개념인 Virtual DOM을 활용하여, 바뀐 부분만 빠르게 변경시킬 수 있는 것 입니다.


MPA

MPA는 다중 페이지 애플리케이션을 의미하며, 이는 각 페이지가 별도의 HTML 문서인 전통적 접근 방식입니다. 웹서버에 페이지 html을 모두 저장하고 있다가, 요청이 오면 적절한 페이지를 꺼내서 반환하는 형태로 웹서버에 여러개의 파일을 가지고 있는 어플리케이션이 MPA입니다.

mpa1.png

MPA의 주요 특징으로는 새로운 페이지를 ‘요청 할 때마다’ 서버에서 렌더링 된 정적 리소스가 다운로드 됩니다. 그러니깐 페이지 이동 혹은 새로고침을 할 때 기존 페이지를 모두 제거하고, 새로운 페이지를 처음부터 다시 렌더링 합니다.

페이지 내 공통 요소들까지 모두 제거하고 페이지를 처음부터 새로 그려내는 과정을 거치기 때문에 비효율적이기도 하고, 만약에 동시에 다수의 사용자들이 웹서버에 새로운 페이지를 요청하기라도 한다면, 서버 과부화의 가능성이 매우 높아질 수 있습니다.


그럼 사용자의 경험 측면에서 두 가지를 비교해 볼까요?

MPA는 각 페이지 로드는 전체 새로고침과 같은 동작입니다. 그래서 페이지 깜빡임이 있을 수 있습니다. 사용자는 어떤 것을 변경 할 때 깜빡거리는 화면을 보게 되는 것이죠. 반면에 SPA 같은 경우, 페이지를 다시 로드 하는 횟수가 적어 원활하고 유동적인 사용자 경험을 합니다.

또 어떤 차이가 있을까요?

spa5.png

MPA같은 경우 각 페이지가 독립적이므로 개발자의 개발이 더 간단해 질 수 있습니다. 또한 MPA는 완성된 형태의 HTML 파일을 서버로부터 전달 받기 때문에 검색엔진이 페이지를 크롤링하기에 적합합니다.

spa6.png

반면 SPA의 경우 자바스크립트를 통해 동적 랜더링을 하기때문에 크롤링이 콘텐츠를 잘 찾지 못합니다. 페이지의 요소를 보면 이렇게만 있는 경우가 있습니다. 이는 SPA의 방식대로 id가 app인 root element 안에 자바스크립트가 동적으로 요소들을 채워넣기 때문입니다.

spa7.png 또한 클라이언트 측 라우팅과 상태관리로 인해 복잡성이 높아질 수 있습니다.


마치며

앞서 개요에서 말씀드렸다시피 아무래도 다른 분야에서는 크게 중요하지 않은 내용이지만 개발을 할 때 아주 중요하고 기초적인 개념이니 꼭 알아가셨으면 좋겠습니다 감사합니다. 😄