클라이언트 사이드 렌더링
고친 사람 github-actions[bot]
클라이언트 사이드 렌더링은 화면에 보일 내용을 브라우저가 직접 만드는 방식입니다. 서버는 거의 빈 문서와 화면을 짓는 코드만 보냅니다. 브라우저가 그 코드를 돌려 데이터를 받아 옵니다. 그 데이터로 화면을 채웁니다.
쉽고 빠른 이해
화면을 조립하는 일을 서버가 아니라 브라우저에 맡깁니다. 웹 메일을 처음 열면 틀이 먼저 뜹니다. 메일 목록은 조금 뒤에 채워집니다. 브라우저에서 도는 코드가 서버에 목록 데이터를 따로 물어 받아 그려 넣기 때문입니다. 이 코드를 담아 보내는 파일이 스크립트입니다.
이렇게 하면 화면을 옮길 때마다 서버가 페이지 전체를 새로 만들어 보내지 않아도 됩니다. 브라우저는 필요한 데이터만 받아 화면의 일부만 고칩니다. 서버는 데이터만 내주면 됩니다.
도는 순서는 이렇습니다.
- 서버가 빈 문서와 스크립트를 보냅니다
- 브라우저가 스크립트를 받아 실행합니다
- 스크립트가 서버에 데이터를 요청합니다
- 받은 데이터로 화면을 그립니다
대가는 첫 화면입니다. 스크립트를 받고, 실행하고, 데이터까지 받기 전에는 화면이 비어 있습니다. 페이지를 모아 가는 프로그램 가운데 스크립트를 돌리지 않는 것은 빈 문서만 봅니다. 그래서 로그인 뒤에 쓰는 관리 화면에는 잘 맞습니다. 검색에 걸려야 하는 글 페이지에는 잘 안 맞습니다.
상세
이 절은 클라이언트 사이드 렌더링이 무엇인지 정한 뒤, 서버가 보내는 문서와 브라우저가 화면을 채우는 순서를 차례로 봅니다. 짧은 코드 두 조각으로 서버 쪽과 브라우저 쪽을 하나씩 보입니다. 끝에서는 서버 사이드 렌더링과 견주고, 이 방식을 고를 때 치르는 대가를 봅니다.
먼저 누가 조립하느냐를 가구에 빗대 봅니다. 조립식 가구를 주문하면 가게는 완성된 책장을 보내지 않습니다. 판자와 설명서를 보냅니다. 받은 사람이 설명서를 따라 조립해야 비로소 책장이 됩니다.
이 비유에서 가게는 서버이고, 조립하는 사람은 브라우저입니다. 설명서는 스크립트, 판자는 데이터에 해당합니다.
정의
클라이언트 사이드 렌더링(Client-Side Rendering, CSR)은 화면에 보일 내용을 클라이언트에서 만드는 방식입니다. 웹에서 클라이언트는 대개 브라우저입니다. 사용자가 쇼핑몰의 주문 내역 페이지를 열면, 주문 목록을 표로 만드는 일을 서버가 아니라 브라우저가 합니다.
이 문서에서 렌더링은 화면에 보일 요소를 만들어 내는 일을 말합니다. 글자와 표, 버튼 같은 요소를 어떤 순서로 무엇을 담아 놓을지 정하는 단계입니다. 요소를 만든 뒤 픽셀로 칠하는 것은 그다음 단계입니다. 이 문서의 렌더링은 앞 단계만 가리킵니다.
화면의 요소는 HTML(HyperText Markup Language, 하이퍼텍스트 마크업 언어)로 적습니다. HTML 은 <h1>제목</h1> 처럼 꺾쇠로 싼 태그로 문서의 구조를 적는 언어입니다. 이 예는 「제목」이라는 글자를 큰 제목으로 놓으라는 뜻입니다.
클라이언트 사이드 렌더링에서는 이 HTML 요소를 서버가 적어 보내지 않습니다. 브라우저 안에서 도는 프로그래밍 언어인 자바스크립트로 짠 코드가 만들어 넣습니다. 이 코드를 담아 브라우저로 보내는 파일이 스크립트입니다.
요소를 만들어 넣는 곳, DOM
자바스크립트가 요소를 넣는 곳은 DOM(Document Object Model, 문서 객체 모델)입니다. 브라우저는 HTML 문서를 읽으면 그 구조를 나무 모양의 객체로 메모리에 올립니다. 이 객체 나무가 DOM 입니다.
DOM 이 있어서 코드로 화면을 바꿀 수 있습니다. 자바스크립트가 DOM 에 요소를 붙이면 브라우저는 그 요소를 화면에 그립니다. 요소를 떼면 화면에서 사라집니다. 클라이언트 사이드 렌더링은 이 성질에 기대어 화면을 짓습니다.
서버가 보내는 문서
클라이언트 사이드 렌더링을 쓰는 페이지에서 서버가 보내는 HTML 은 거의 비어 있습니다. 아래가 그런 문서의 최소 형태입니다.
<!doctype html>
<html>
<body>
<div id="app"></div>
<script type="module" src="/app.js"></script>
</body>
</html>
본문에는 id 가 app 인 빈 칸과 스크립트를 불러오라는 줄만 있습니다. 사용자에게 보일 글자는 한 자도 없습니다.
type="module" 을 붙인 스크립트는 브라우저가 문서를 끝까지 읽은 뒤에 실행됩니다. 그래서 스크립트가 돌 때는 빈 칸 #app 이 이미 만들어져 있습니다. 화면의 내용은 전부 /app.js 에 들어 있는 코드가 만들어 냅니다. 빈 칸은 그 코드가 요소를 붙일 곳을 알려 주는 표시입니다.
데이터를 화면으로 바꾸는 코드
/app.js 는 서버에 데이터를 요청합니다. 받은 값으로 요소를 만들어 빈 칸에 붙입니다.
이때 서버는 화면 대신 JSON(JavaScript Object Notation, 자바스크립트 객체 표기법) 데이터를 돌려줍니다. JSON 은 {"name": "민지"} 처럼 이름과 값을 짝지어 적는 텍스트 형식입니다. 아래 코드가 그 JSON 을 받아 화면에 이름을 띄웁니다.
const r = await fetch("/api/me");
const me = await r.json(); // {name:"민지"}
const h1 = document.createElement("h1");
h1.textContent = me.name; // "민지"
document.querySelector("#app").append(h1);
첫 줄의 fetch 는 서버에 HTTP(HyperText Transfer Protocol) 요청을 보내는 함수입니다. 브라우저가 자바스크립트에 내주는 기능입니다.
await 는 응답이 올 때까지 다음 줄로 넘어가지 않고 기다리라는 뜻입니다. 응답이 오면 둘째 줄이 그 본문을 JSON 으로 읽어 객체로 바꿉니다.
/api/me 처럼 화면 대신 데이터를 내주는 서버의 창구가 API(Application Programming Interface, 응용 프로그래밍 인터페이스)입니다. 이런 창구를 내는 서버를 이 문서에서는 API 서버로 적습니다.
셋째 줄부터는 화면을 짓습니다. createElement 로 h1 요소를 새로 만듭니다. 받은 이름은 그 안에 적습니다. 마지막 줄에서 그 요소를 빈 칸에 붙이는 순간 화면에 「민지」가 나타납니다.
실무에서는 이 일을 손으로 다 짜지 않습니다. 데이터가 바뀌면 DOM 을 알아서 고쳐 주는 UI(User Interface, 사용자 인터페이스) 라이브러리를 씁니다. React 가 그런 라이브러리입니다. 라이브러리를 써도 브라우저가 데이터를 받아 DOM 을 짓는다는 뼈대는 같습니다.
브라우저가 화면을 채우는 순서
위 두 조각을 시간 순서로 이으면 다음과 같습니다. 브라우저는 서버와 세 번 주고받은 뒤에야 첫 화면을 그립니다.
그림은 서버를 둘로 나눠 그렸습니다. 빈 HTML 과 app.js 를 내주는 웹 서버, 데이터를 내주는 API 서버입니다. 둘이 한 서버여도 순서는 같습니다.
sequenceDiagram
participant 브라우저
participant 웹서버 as 웹 서버
participant API서버 as API 서버
브라우저->>웹서버: 페이지 요청
웹서버-->>브라우저: 빈 HTML
브라우저->>웹서버: app.js 요청
웹서버-->>브라우저: app.js
Note over 브라우저: 스크립트 실행
브라우저->>API서버: 데이터 요청
API서버-->>브라우저: JSON
Note over 브라우저: DOM 에 요소를 붙여 화면을 그린다
첫 왕복에서 빈 HTML 을 받습니다. 둘째 왕복에서 스크립트를 받습니다. 스크립트가 돌기 시작해야 셋째 왕복인 데이터 요청이 나갑니다. 셋째 응답이 와야 비로소 사용자가 볼 내용이 생깁니다.
페이지를 옮길 때
서버가 HTML 을 만들어 보내는 방식이라면, 사용자가 다른 메뉴를 누를 때마다 브라우저가 새 HTML 문서를 다시 받습니다. 클라이언트 사이드 렌더링에서는 새 문서를 받지 않습니다. 이미 받아 둔 스크립트가 필요한 데이터만 요청해 바뀌는 부분의 DOM 만 고칩니다. 화면 전체가 비었다가 다시 채워지는 일이 없습니다.
주소창의 주소도 스크립트가 바꿉니다. 브라우저는 페이지를 다시 불러오지 않고 주소만 바꾸는 기능을 자바스크립트에 줍니다. 그래서 주소는 /orders 에서 /profile 로 바뀌어도 문서는 처음 받은 문서 그대로입니다.
이렇게 문서 하나 위에서 화면만 갈아 끼우며 도는 웹 애플리케이션이 단일 페이지 애플리케이션(Single Page Application, SPA)입니다. SPA 안에서 주소를 보고 보일 화면을 브라우저 코드가 고르는 일이 클라이언트 사이드 라우팅입니다.
서버가 맡는 일
클라이언트 사이드 렌더링에서 백엔드는 화면 템플릿을 채우지 않습니다. 요청을 받아 JSON 을 돌려주는 API 만 냅니다. 화면을 어떻게 그릴지는 브라우저 코드가 정합니다.
빈 HTML 과 스크립트 파일은 사용자마다 달라지지 않습니다. 그래서 요청마다 새로 만들 필요 없이 미리 만들어 둔 파일로 내보냅니다. 이런 고정 파일은 웹 서버나 CDN(Content Delivery Network, 콘텐츠 전송 네트워크)에서 바로 내줄 수 있습니다. CDN 은 여러 지역에 파일 사본을 두고 사용자와 가까운 곳에서 내주는 서버 묶음입니다.
그 결과 화면 코드와 API 코드가 갈라집니다. 두 쪽을 따로 만들고 따로 배포할 수 있습니다. 같은 API 를 웹 화면과 모바일 앱이 함께 쓰기도 합니다.
서버 사이드 렌더링과 가르는 선
반대쪽에는 서버 사이드 렌더링이 있습니다. 서버가 데이터를 조회해 내용이 다 찬 HTML 을 만들어 보내는 방식입니다. 둘을 가르는 것은 HTML 요소를 누가 만드느냐입니다. 아래 표는 거기서 갈려 나오는 차이를 모았습니다.
| 클라이언트 사이드 렌더링 | 서버 사이드 렌더링 | |
|---|---|---|
| HTML 요소를 만드는 쪽 | 브라우저의 자바스크립트 | 서버 |
| 첫 응답에 든 내용 | 빈 칸과 스크립트 링크 | 사용자가 볼 내용 전부 |
| 서버가 돌려주는 것 | JSON 데이터 | 완성된 HTML |
| 다른 화면으로 옮길 때 | 데이터만 받아 일부만 고친다 | 새 문서를 다시 받는다 |
| 스크립트가 안 돌면 | 화면이 비어 있다 | 내용은 보인다 |
두 방식은 한 애플리케이션 안에서 함께 쓸 수 있습니다. 첫 화면은 서버가 HTML 로 만들어 보냅니다. 그다음부터는 브라우저가 클라이언트 사이드 렌더링으로 이어 갑니다.
이렇게 섞으면 서버가 보낸 HTML 은 처음에 보이기만 합니다. 브라우저 코드가 내려와 그 요소들에 클릭·입력 처리 코드를 연결해야 버튼과 입력이 동작합니다. 이 연결 단계가 하이드레이션입니다.
치르는 대가
첫 대가는 첫 화면이 뜨기까지의 시간입니다. 앞의 그림처럼 브라우저는 세 번 왕복한 뒤에야 내용을 그립니다. 그동안 사용자는 빈 화면이나 로딩 표시를 봅니다.
둘째 대가는 스크립트의 크기입니다. 화면이 늘수록 /app.js 에 담긴 코드도 커집니다. 스크립트가 클수록 받는 데도, 실행하는 데도 시간이 더 듭니다. 처리 능력이 낮은 휴대폰에서는 실행 시간이 더 늘어납니다.
그래서 코드를 여러 파일로 나눠 첫 화면에 필요한 것만 먼저 받습니다. 이렇게 나누는 것이 코드 분할입니다. 나머지 파일은 필요해질 때 받습니다. 사용자가 그 화면으로 옮겨 갈 때 받는 이 방식이 지연 로딩입니다.
셋째 대가는 스크립트를 돌리지 않는 프로그램입니다. 페이지를 읽어 가는 크롤러가 첫 응답만 보면 빈 칸만 얻습니다. 검색 엔진 가운데는 스크립트를 돌려 본 뒤 색인하는 곳도 있습니다. 하지만 모든 크롤러가 그러지는 않습니다.
웹 스크래핑은 프로그램으로 웹 페이지의 내용을 긁어 오는 일입니다. HTTP 요청만 보내 HTML 을 받는 스크래핑 코드도 같은 까닭으로 빈 칸만 얻습니다.
이런 페이지를 긁을 때는 화면 없이 도는 브라우저를 띄워 스크립트까지 돌린 뒤 DOM 을 읽습니다. 이런 브라우저가 헤드리스 브라우저입니다. Playwright 는 헤드리스 브라우저를 코드로 조종하는 도구입니다.
고르는 기준
어느 쪽을 고를지는 첫 화면과 검색 노출이 얼마나 중요한지, 화면 안에서 주고받는 일이 얼마나 많은지로 갈립니다.
| 조건 | 기우는 쪽 |
|---|---|
| 로그인한 뒤에만 쓰고 검색에 노출될 필요가 없다 | 클라이언트 사이드 렌더링 |
| 한 화면 안에서 클릭과 입력이 잦다 | 클라이언트 사이드 렌더링 |
| 처음 들어온 사람이 내용을 곧바로 봐야 한다 | 서버 사이드 렌더링 |
| 검색 결과와 링크 미리보기에 내용이 떠야 한다 | 서버 사이드 렌더링 |
관리자 화면, 대시보드, 웹 메일은 위 두 줄에 해당합니다. 블로그 글과 상품 소개 페이지는 아래 두 줄에 해당합니다. 한 서비스 안에서도 페이지마다 다르게 고를 수 있습니다.
관련 항목
클라이언트 사이드 렌더링과 맞세워지는 렌더링 방식
서버 사이드 렌더링 · 정적 사이트 생성기 · 프리렌더링 · 하이브리드 렌더링 · 하이드레이션 · 서버 컴포넌트
클라이언트 사이드 렌더링으로 짓는 애플리케이션 구조
단일 페이지 애플리케이션 · 클라이언트 사이드 라우팅 · 프로그레시브 웹 앱 · 오프라인 우선 · 상태 관리
클라이언트 사이드 렌더링을 구현하는 UI 라이브러리
React · Vue.js · Angular · Svelte · 가상 DOM
브라우저가 화면을 짓는 데 쓰는 기술
브라우저 · HTML · CSS · JavaScript · DOM · Fetch API · History API · 렌더링 엔진
서버 쪽에서 데이터와 파일을 내주는 구성 요소
API · REST API · JSON · HTTP · 웹 서버 · CDN · 백엔드
첫 화면과 스크립트 크기를 다루는 기법
번들러 · 코드 분할 · 지연 로딩 · 캐싱 · 첫 콘텐츠풀 페인트 · 첫 바이트까지의 시간
첫 응답이 비어 있어 달라지는 수집·색인 작업
크롤러 · 검색 엔진 · 검색 엔진 최적화 · 웹 스크래핑 · 헤드리스 브라우저 · Playwright
클라이언트 사이드 렌더링이 속하는 상위 분류
다른 이름: client-side rendering · CSR · 클라이언트사이드 렌더링 · 클라이언트 렌더링