웹 페이지를 렌더링하는 방식들인
위의 개념들에 대해 학습한다.
사용자가 사이트에 접속하면 서버에 이미 저장되어 있는 HTML 문서들을 가져와서 보여주는 방식의 사이트다. 마트에서 이미 진열된 물건을 고객이 사가는 것처럼, 고정된 HTML, CSS, 자바스크립트, 이미지 등을 서버가 가지고 있어 사이트의 내용이 변하지 않는다. 소개 페이지나 랜딩 페이지가 Static Site
의 예이다. 반대 개념으로는 Dynamic Site
가 있는데, 게시판이나 통계 페이지처럼 데이터베이스 등 바뀌는 내용에 따라 페이지의 내용물이 변화한다. 사용자가 방문할 때마다 서버가 HTML 안의 내용들을 렌더링해서 전달한다.
페이지에서 다른 링크를 클릭하면 다시 서버에서 그 페이지의 HTML를 받아와서 페이지 전체를 업데이트하게 된다. 페이지를 이동할 때마다 새로고침이 되면서 뚝뚝 끊어지는 느낌이 들어 나쁜 User Experience를 주게 된다.
<iframe>
태그가 도입 되면서 페이지 내에서 부분적으로 문서를 업데이트 할 수 있게 되고, XMLHttpRequest
가 등장하면서 JSON
형식으로 부분적인 데이터를 가져올 수 있게 되었다. 이JSON
데이터를 자바스크립트를 이용해서 동적으로 HTML에 반영할수 있게 되었고, 이런 방식을 AJAX
라고 부른다.
AJAX
를 활용하여 사용자가 한 페이지 내에서 필요한 데이터를 서버에서 받아와서 부분적으로 업데이트 하는 방식으로 웹이 발전했는데, 이것을 SPA(Single Page Application)
이라고 부른다. 비유하자면 손님이 불판만 받아와서 고기라는 데이터를 계속 요청해서 스스로 구워먹는 고깃집 같은 것이다.
기존의 동적 웹사이트처럼 링크를 클릭할 때마다 다른 페이지로 이동하는 것이 아니라, 같은 페이지에서 자바스크립트를 사용해서 HTML 요소를 동적으로 바꿔주는 것이기 때문에 한 페이지에서 모든 게 다 되는 Single Page
인 것이다. SPA
는 원 페이지이기 때문에 클릭할 때마다 링크의 이동 없이 깔끔하고 쾌적한 UX를 갖게 된다.
자바스크립트 파일을 브라우저에서 해석해 렌더링하는 방식이다. 위에서 설명한 SPA
웹사이트는 주요 컨텐츠가 서버가 아닌 클라이언트, 즉 사용자가 사용하는 브라우저에서 데이터에 따라 HTML 요소들이 렌더링되기 때문에 CSR
방식을 사용한다고 할 수 있다. CSR
이 SPA
에서만 되는 건 아니니까 CSR==SPA
라고는 할 수는 없다.
예를 들어 서버에서 index.html
파일을 클라이언트에 보내주면,
<body>
<div id="root"></div>
<script src="app.js"></script>
</body>
바디 안에는 <div id="root"></div>
와 자바스크립트 링크 app.js
만 들어있다. 어플리케이션이 텅 비워져 있기 때문에 처음에 접속하면 빈 화면이 보인다. 링크된 자바스크립트 파일(app.js
)을 서버로부터 전달받게 되는데, 이 app.js
에는 자바스크립트 로직 뿐만 아니라 어플리케이션을 구동하는 프레임워크나 라이브러리들이 전부 들어 있다. 추가로 필요한 데이터가 있다면 서버의 데이터베이스에서 받아온 다음, 이것들을 기반으로 동적으로 HTML을 생성해서 화면에 보여주게 된다.
CSR
의 문제는 사용자가 첫 화면을 보기까지의 시간이 오래 걸린다는 점과, SEO 성능이 좋지 않다는 점이다.
이
app.js
에는 자바스크립트 로직 뿐만 아니라 어플리케이션을 구동하는 프레임워크나 라이브러리들이 전부 들어 있다.
위에서 이렇게 설명했는데, 당연히 app.js
는 용량이 클 수밖에 없다. 이걸 다운로드 받는 데 걸리는 시간 만큼 사용자는 빈 화면을 봐야 할 것이다.
SEO
란 Search Engine Optimization
으로, 사이트가 검색 엔진으로 찾아지기에 적합하게 만드는 것을 뜻한다. 구글, 네이버와 같은 검색엔진들은 서버에 등록된 사이트를 돌아다니면서 HTML 안에 포함된 링크와 타이틀, 태그들을 보고 사용자가 빠르게 검색할 수 있도록 한다. 하지만 CSR
에서 사용하는 HTML body는
<body>
<div id="root"></div>
<script src="app.js"></script>
</body>
대부분 이런 모양이기 때문에, 검색엔진들이 html을 분석하기가 어렵다. 이러한 CSR
의 문제점 때문에, 과거에 사용했던 Static site
에서 영감을 받은 SSR
이 도입된다.
브라우저에서 자바스크립트 코드를 다운로드 받아 해석 할 때까지 기다리지 않고, 서버에서 보여질 HTML을 미리 준비해 클라이언트한테 응답해주는 방식이다. 클라이언트에서 모든 것을 처리하는 방식과는 다르게, 웹사이트에 접속하면 서버에서 필요한 데이터들을 가져와 HTML파일을 만들게 된다. 서버는 만들어진 HTML 파일을 동적으로 제어할 수 있는 자바스크립트 파일과 함께 클라이언트에게 보낸다. 클라이언트 측은 잘 만들어진 HTML 파일을 가져와서 보여주기만 하면 된다.
CSR
보다 첫 페이지 로딩이 빨라지고, 컨텐츠가 HTML에 담겨 있기 때문에 SEO
성능도 좋아지게 된다.
Static site
에서 발생했던 화면 끊김, 깜빡임 문제가 여전히 존재한다. 사용자가 클릭을 하게 되면 전체 웹사이트를 서버에서 가져오는 것이기 때문에 사용성이 떨어진다.
두 번째로는 서버에 무리가 간다는 점이다. 특히 사용자가 많은 사이트일수록 사용자가 클릭을 할 때마다 서버에 요청이 가게 되므로.
세 번째 문제는 사용자가 html 화면은 빠르게 볼 수 있지만, js파일을 아직 다운로드 받지 못한 상태에서 여기저기 클릭을 했을 때 반응이 없는 경우가 발생할 수 있다는 것이다. 즉 사용자 입장에서 화면은 보이는데 js가 로드되지 않았기 때문에 버튼을 눌러도 아무 반응이 없는 상황을 겪게 된다.
Next.js
와 Nuxt.js
SPA
는 기본적으로 CSR
방식을 사용한다고 위에서 설명했다. CSR
이 가진 단점을 극복하기 위해 SSR
을 부분적으로 적용하면 좋을 것이다. 즉 SSR
처럼 사용자에게 바로 보여져야 할 데이터를 미리 가진 HTML을 먼저 보여주고, 그 다음에 CSR
방식처럼 동적인 데이터들을 가져오면 좋을 것이다.
이것을 가능하게 해 주는 게 Next.js
, Nuxt.js
라는 라이브러리이다. Next.js
, Nuxt.js
는 각각 React
, Vue
에 SSR로 페이지를 제공하는 기능들을 추가한 것이다. 이 라이브러리들을 활용하면 사이트의 원하는 부분을 SSR로 만들 수 있다.
Next.js
는 브라우저에 렌더링 할때 기본적으로 pre-rendering(사전 렌더링)
을 해준다. 사전 렌더링이란 서버단에서 DOM 요소들을 Build하여 HTML 문서를 렌더링하는 것을 말한다. 위 사진처럼 HTML을 미리 렌더링하고, 그 뒤에 요청이 오면 Chunk 단위로 js를 보내주어 이벤트가 작동하게 해 준다. 이 pre-rendering
을 동적으로 해서 페이지를 생성하느냐, 정적으로 페이지를 생성하느냐의 차이가 SSR
과 SSG
의 차이이다.
이것이 가능하려면, 일반적인 React
, Vue
처럼 프론트엔드 코딩한 것을 정적 파일로 서버에 올려두는 것이 아니라 어플리케이션 서버가 돌고 있어야 한다. API 서버와 별개로, Next.js
, Nuxt.js
서버가 또 돌고 있어야 한다는 말이다. 그래서, Next.js
, Nuxt.js
로 만든 웹을 SSR 모드로 돌리면 정적 파일들로 빌드해서 올리는 것이 아니라, Node.js
가 깔린 서버에서 프로젝트를 어플리케이션으로 실행해서 프론트엔드를 배포하게 된다. 이런 방식으로 페이지의 요소들 중에 페이지 접속 시 바로 나타나야 할 것들을 정해서 서버에서 미리 렌더링해서 보내줄 수 있게 된다. 그 이후에 다른 요소들은 기존의 CSR
방식대로 ajax
등을 사용해서 동적으로 나타나게 되는 것이다. 따라서 SSR
처럼 첫 로딩이 빠르지만 CSR
처럼 이후 동작은 부드러운, SSR
과 CSR
의 장점만을 가져올 수 있게 된다.
SSG
란 Static Site Generator
, 사전 렌더링을 정적 페이지로 생성해주는 방식이다. SSR
처럼 서버로부터 완성된 HTML을 받아오지만 다른 점은 HTML 파일의 생성시점이 빌드 타임이라는 것이다(SSR
은 사용자가 요청 시에 생성한다). 예시로는 Gatsby
, Jekylle
, Hugo
가 있다.
Gatsby
를 예로 들어보자. 기본적으로 React
를 사용해서 코딩을 하는데, 결과물을 내놓을 때는 렌더링을 다 마친 정적 파일들을 생성해서 배포해준다. 페이지에 필요한 데이터들을 json
이나 yaml
등의 정적 파일에 저장하고, 이걸 읽어와서 React
방식으로 렌더링을 하는 코드들을 짠 다음 빌드하면 모든 페이지들을 컨텐츠가 들어있는 HTML파일로 생성해준다. 즉, 사이트에서 접속하는 모든 페이지마다 정적 HTML 파일들이 이미 빌드한 시점에서 생성되어 서버에 올라가 있는 것이다. React
나 Vue
의 편리한 방식대로 코딩은 하지만, 배포할 때는 정적 파일로 생성해서 내보내는 것이다.
SSG
방식은 페이지들이 많이 있기는 하지만 내용이 크게 변할 일이 없고, 동적인 요소들이 적은 사이트를 만들 때에 적합하다. 변하지 않을 내용들을 보여줄 페이지이니 굳이 API서버를 따로 두기보다는 간편하게 정적 배포를 하는 것이다. 이를테면 블로그를 운영하는데, Spring
이나 Express
같은 웹 어플리케이션을 구동하는 것보단 SSG
방식을 사용하는 것이 효율적일 것이다.
React
, Vue
와 같은 SPA
들이 채택하는 방식SEO
최적화에 불리함pre-rendering
)해 클라이언트한테 응답해주는 방식SEO
최적화에 유리함SPA
의 편리함과 SSR
의 장점을 동시에 가져오기 위해 사용하는 라이브러리React
생태계에서는 Next.js
와 Gatsby
사용Vue
생태계에서는 Nuxt.js
사용SSR
처럼 pre-rendering
이 되지만 빌드 타임에 HTML을 생성SSR
: 요청이 올 때 마다 해당하는 HTML 문서를 그때 그때 생성하여 반환SSG
: HTML을 빌드 타임에 각 페이지별로 생성하고 해당 페이지로 요청이 올 경우 이미 생성된 HTML 문서를 반환[위키백과] 정적 웹페이지
[위키백과] 동적 웹페이지
[Next.js] SSG, SSR 개념 정리
[드림코딩] 서버사이드 렌더링 (개발자라면 상식으로 알고 있어야 하는 개념 정리 ⭐️)
[얄팍한 코딩사전] SSR, SSG, JAM Stack이 뭔가요? (+ CSR, SEO, Next.js, Nuxt.js, Gatsby)