내가 SSR은 풀스택이 아니다 라는 글을 적었는데, 좀 어수선하게 적어서 명확하게 알려주고자 다시한번 싸지르도록 하겠다.
특히 애초에 프론트엔드에 입문하거나, 구직 중이거나, 혹은 소속 중인 프론트엔드 개발자에게 확실히 좋은 양식이 될 것이다.

뭐? 10년 물먹은 코더 주제에 프론트엔드 얼마나 쳐했다고 감히 이딴글을 쓰냐?

실제로 누가 이런 맨션을 나한테 싸질렀다... 그래... 기술 부채가 심한 SI/SM 위주로 했으니 그럴 만도 하다.
하지만 알아둬야 할 것은, 10년도 못채우고 그만둔 개발자가 많다 보니, 10년 이상 개발자가 생각보다 별로 없다. (공급도 줄었는데 수요도 줄었다)
따라서 10년 웹을 해왔다는 건 본인이 혐오하거나 그러지 않는 이상은 척 보면 알고 개발하니 무시하지 않길 바란다.
특히, 요즘 vue 도입이 많아지고 있는데, vue 경험 없어도 10년차를 믿고 따른다. 다 잘 따라가고 있기 때문에.
이건 SI 기준이다. 패키지나 솔루션은 SI에 비해 커리어가 험악한데, 따라가지 못하면 도태되는 건 알고있다. 그러니 이런 출신의 개발자가 선호되는 이유기도 하다.

좋아, 각설하고, 본론으로 들어가겠다.

음... 내 글 보는 독자들 보니까 리액트 개발자가 많아 보이기에 리액트 기준으로 설명하겠다. 사실 나도 이게 편하다.
어자피 SSR 원리가 어느 프론트엔드를 쓰든 거기서 거기기 때문에 다른 프론트엔드 예시 없다고 불만 가지는 일은 없기 바란다.


출처: React and Server Side Rendering (SSR)

먼저, 위 그림 안에 영문을 제시한 순서대로 해석해 주도록 하겠다.

  1. 서버가 렌더링할 HTML 응답 결과를 브라우저에 보낸다.
  2. 브라우저가 페이지를 표시하면, 브라우저가 HTML 소스 내 JS 파일들을 받는다.
  3. 브라우저가 리액트 라이브러리를 불러들인다.
  4. 이제 상호 작용이 가능하다. (주: 기존 리액트와 동일하게 동작)

여기서 내가 설명할 사항은 1번이다. 2번은 SSR 아닌 CSR도 동일한 과정이기 때문이다.
1번에서 렌더링한 결과물을 뿌린다고 한 게 뭐냐면, 바로 리액트 같은 각 프론트엔드 코어가 직접 HTML 결과물을 그려준다는 건데,
초기에 뿌릴 결과물을 먼저 구성해서 뿌려준다, 이게 뭔소린가 하면은,
보통 리액트라면, create-react-app 기준으로,

  1. 웹 사이트에 접속하면 당연히 서버는 index.html 따위의 색인 HTML 파일을 찾아 뿌려준다.
  2. 이 때, 빌드한 HTML 파일 내 리액트 등의 코어와 사용자가 개발하여 패키징된 JS 파일을 브라우저가 받는다.
  3. 그리고 리액트 등의 코어가 실행되면서 상호작용이 가능해진다.

여기서 1번 과정을 서버를 통해 뿌려준다는 얘기다.
이렇게 하면, 각 라우팅 경로를 서버가 인지해서 각 라우팅 경로에 따라 결과물을 뿌려줄 수 있기 때문에,
검색 엔진은 해당 페이지의 정보를 얻기 수월해진다. SSR이 SEO에 최적이라는 말이 여기서 나온다.

좋아, 만약 기존 CSR 방식이 왜 SEO에 안좋은지 알려주겠다.
별 거 없다. 웹 서버를 세팅할 때, CSR은 보통 SPA, 단일 페이지 앱로 빌드하게 된다.
따라서 검색 엔진은 어떤 경로를 불러와도, index.html 페이지로 리디렉트를 하게 되고, 엔진은 그걸 따라간다.
하지만 정작 가져오는 정보는 맨 초기 HTML 정보다 보니, 가져올 수 있는 데이터에 한계가 있는 것이다.
어자피 스크립트를 통헤 헤더를 변조하는 수밖에 없으니, 그거까지 대응 안 한 검색엔진은 뭘 가져갈 것인가?
게다가, SPA 라우팅 특성 상 해당 라우팅이 없으면 페이지가 없다는 화면이야 뿌릴 수 있지만, 404 헤더는 뿌릴 수가 없다.
그러니 검색 엔진 입장에서는 매우 모호하게 수집할 수밖에 없다. 구글처럼 아예 헤드레스로 지능적인 수집을 하지 않는 이상은.

사실 이렇게 따지면, 서버에서 결과를 뿌려주기 때문에 당연히 서버단 코드를 실행할 수 있다.
서버단 코드를 실행한다는 건, 서버 기준의 리소스를 실행 가능한 것이 되므로, 서버단 파일 처리나 DB 처리가 가능해진다.
물론 이론상으로.
하지만 현실적으로는 그냥 안 된다. 이걸 쉽게 해주는 Next.js 같은 프레임워크가 존재하는 이유이기도 하다.

그냥 안되는 이유가 바로 "검증" 기능 때문이다.

누구나 변조된 웹 페이지를 개인정보 줘가면서 이용하는 건 원치 않을 것이다.
리액트의 경우, 디~기 번거로운 검증 과정을 거치는데,

  1. SSR Hydrate 통해 컴포넌트 불러올 때, 초기 상태에 따른 HTML 결과물을 출력한다.
  2. 클라이언트 리액트가 실행 후, 초기 상태에 따른 DOM 변경을 실시한다.
  3. 이 대, 서버단 초기 상태와 클라이언트단 초기 상태가 다르면, 무결성 오류를 출력한다. (단, 개발자 모드 실행 시에만)
  4. 이걸 이대로 배포하면, SSR은 그대로 실행하지만, 클라이언트 상태 기준으로 초기 상태의 렌더링 결과로 완전히 재렌더링한다.

만약 Next.js 사용 시 페이지 불러올 때마다 한번씩 깜박임을 봤다면, 4번 요인이 가장 크다.
만약 고의적으로 재현하고 싶다면, React Hydration Error - Next.js 문서 내 Example Code를 참고하면 된다.
간단하다. window 객체 존재 여부에 따라 초기 상태값을 달리하면 된다. (node.js 는 없으니까)

그다음 흔한 일이 바로 emotion 이나 styled-components 같은 CSS 컴포넌트형 라이브러리와 SSR 연계인데,
이는 각 라이브러리 문서에 해결법이 적혀 있으므로 이대로 하면 보통은 일어나지 않는다... Remix만 빼고...

따라서 날로는 SSR에다가 서버단 코드를 단순히 집어넣을 수가 없다. 서버단에서만 허용하는 입력 결과는 서버만 받을 수 있기 때문에 클라이언트는 받을 방법이 없다보니, 무결성 오류를 뱉기 때문이다.
또한, Next.js 에서는 페이지 컴포넌트에만 서버단 코드를 넣어 속성으로 전달할 수 있도록 허용하는 이유이기도 하다.

하지만 그렇다고 포기하지 마라. 이런 React의 한계를 극복하기 위해 아예 리액트 공식으로 Next.js 팀과 함께 서버 컴포넌트(Server Components)를 개발하고 있다.
말 그대로, 아예 서버단에서 가져오는 컴포넌트와 클라이언트단에서만 가져오는 컴포넌트를 분리 관리해서 일관성을 유지하고 무결성을 해결하는 수단이다.
이 서버단 컴포넌트를 사용하면, API나 페이지 컴포넌트만 가능했던 서버단 코드였던 방식이 서버 컴포넌트 정의만으로 서버 내 파일 관리나 DB 입출력이 가능해진다.
그러면 컴포넌트 관리도 예술적이지 아니한가?

아예 Deno의 Fresh 처럼 아예 상태관리를 서버에서 위임해버리는 경우도 있다. 내가 생각하는 가장 이상적인 방법이기도 하고.

쓰고 나니 길어졌다. 이제 이해가 되길 바란다.

좋아, 3줄 요약 들어간다. 아니 이걸 3줄요약이 가능하다고? 외않됀되?

  • SSR 은 서버에서 각 경로별로 초기 상태에 따른 렌더링 결과를 브라우저에 출력하기 때문에 SEO에 유리하다.
  • 하지만 SSR은 변조 방지를 위해 서버단 상태와 클라이언트 상태 일치 여부를 검증하는 과정을 거치다 보니, 서버단 코드를 단독으로 사용할 수 없어서 풀스택이 아닌 것이다.
  • React의 경우, 이를 극복하기 위해 서버 컴포넌트를 개발중이며, 이게 해결되면 SSR 풀스택이 가능해진다. (혹시 Vue 등 다른 프론트엔드의 서버단 컴포넌트 소식 있으면 제보바람)

크으, 프론트엔드 입문자에게 도움이 됐다니 벌써부터 흥분되는걸?
이 과정은 왠만한 프론트엔드 다 거치는 과정이니 react만 썼다고 실망하지 않길 바란다. 다 똑같다. 신뢰성을 확보하기 위한 수단이기 때문이다.

끗.

profile
지옥에서 온 개발자

2개의 댓글

comment-user-thumbnail
2022년 11월 26일

이 글에서 설명하는 풀스택의 기준이 뭐 인지는 정확히 모르겠지만...

저는 SSR 프레임워크 자체는 풀스택이라고 생각합니다.

현재 사용되는 SSR 프레임워크들은 결국은 CSR 기술을 기반에 둔 프레임워크 들이고, 클라이언트 부분에 서버 코드를 작성할 시 작동 안 하긴 합니다.

다만 결국 next 나 nuxt 같은 SSR 프레임워크들은 결국 express 기반 서버를 사용하고 있고, express 기반 서버가 돌아가고 있기 때문에 기존 백엔드가 하던 일을 하려고 하면 할 수 있습니다.

쉽게 봐서 next,nuxt의 /api/* 라우팅은 express를 사용하는 것과 마찬가지이기 때문에 express에서 할 수 있는 거의 모든 일을 할 수 있습니다. 현재 백엔드 / 프론트 분리라는 추세에 안 맞을뿐.. (대게 프록시 서버나 BFF 정도로만 이용합니다.)

1개의 답글