SSG를 위한 Vite 셋업

lynj·2023년 4월 14일
0

계기

다음과 같이, 랜딩페이지/소개용 홈페이지/포트폴리오 웹사이트 등 하나의 페이지로 이루어진 정적 사이트를 서비스하고자 한다.

(위의 참고용 사진은 포트폴리오를 위해 직접 제작한 가상의 사이트 디자인이다. 후술할 내용은 이를 실제 동작하는 사이트로 개발하기 위한 탐색과정이다)

.

대부분 간단한 정보 전달을 위한 정적 페이지이니, 사실 HTML+CSS만으로 구성해도 충분하다. 무엇보다 홍보가 주 목적인 이런 페이지들은 검색엔진 노출을 위한 최적화가 중요하므로, CSR 방식을 채택한 메이저한 FE 프레임워크를 활용하는 것은 적절치 않다.

그렇지만 HTML+CSS만을 활용하기엔 컴포넌트를 이용한 작업을 포기할 수 없고, 아무리 정적 페이지라고 해도 개발 단계에서 데이터를 HTML에 그대로 포함하기보다는 파일 시스템 내에서라도 따로 관리하고 싶었기에 해당 방식을 따르는 것도 문제가 있었다.

그렇다면 JS를 사용해야하고, 결국 클라이언트 사이드에서 렌더링하게 되는 꼴이니 다시 SEO 이슈로 돌아오게 된다. 물론 요즘은 JS 실행 결과도 봇이 파싱할 수 있지만, 그래도 내가 만들고자 하는 페이지의 이상적인 형태인 'HTML+CSS만으로 이루어진 정적 페이지'의 형태로 배포하기를 원한다.

즉, 개발 단계에서는 JS를 활용하고, 배포 단계에서는 정적 파일로 서비스하기를 원하는 것이다. 자연스럽게 Static Stie Generation에 관해 알아보게 되었다. 빌드 과정에서 정적 페이지와 리소스를 모두 렌더링하고, 그 결과물을 배포하는 형태를 채택하기로 한 것이다! 그리고 이제 방황이 시작된다.

탐색

시작은 Gatsby였다.
Gatsby는 SSG를 디폴트로 사용한다.
Next.js는 내 사례에는 오버스펙이다. 라우팅이 필요하지 않고, SSR을 활용하지도 않으므로 필요에 비해 과하다. 용량도 많이 잡아먹는다.. 

Gatsby와 Next.js를 비교할 때, 간단한 구조에서는 Gatsby가 적합하다는 의견이 많이 보였다. 사담을 덧붙이자면, 애니메이션 효과를 위해 framer-motion을 공부하고 있는데, Wrong Akam의 튜토리얼이 너무 매력적이고 뛰어났다. 그런데 이 분의 튜토리얼 중 Gatsby를 활용한 예제가 많더라. 호감을 갖게 된 계기 중 하나 였다.

그런 고로 Gatsby를 활용해보았으나 굉장히 실망스러웠다. 빌드가 너무 느리고 오류가 잦았다. gatsby clean을 몇 번이나 실행했는지 모르겠다.. 내가 잘못 사용한 걸 수도 있지만, 아무튼 내겐 맞지 않았다.
보다 나은 개발 경험을 위해선 이보다 가벼운 옵션이 나을 것 같다는 결론에 이르게 되었다. 물론 이미지 최적화를 위해 Gastby가 제공하는 기능은 유용하며 이는 SEO를 위해 중요하지만, 이미지가 많고 로딩 속도가 눈에 보일 정도로 현저히 떨어질 때에 고려하기로 했다.

그러면 다시 원점이다. 그러니까,

  • HTML+CSS로? 개발하기 불편해!
  • 순수 JS로? 빈 html이 아닌, 컨텐츠가 렌더링된 결과물을 배포하고 싶어!
  • SSG를 지원하는 프레임워크? 필요해 비해 과하네.
  • 기본으로 돌아가서, 프레임워크 없이 사전렌더링하는 방법을 알아보자..

라는 과정을 거쳐온 것이다.

결과

그렇게 알아본 결과, Vite에서 제공하는 SSG를 위한 가이드를 발견했다! 리액트를 사용한 예제도 존재한다.

그래서 예제가 어떻게 돌아가는지 이해하기 위해 열심히 들여다봤다.
하나의 페이지로 서비스할 계획이므로 리액트 라우터를 사용할 이유가 없어 예제를 조금 변형했다. entry-sever.jsx파일과 prerenderer.js 파일을 좀 더 간소화한 것 외에 큰 차이는 없다.

사전 렌더링을 위한 명령어는 다음과 같다.

vite build --outDir dist/static && npm run build:server && node prerender 입력하세요

먼저 vite build 를 통해 dist/static 폴더에 프로젝트를 빌드한다.
해당 빌드 결과물은 하나의 html, css, js 파일이다.
이 시점의 결과물은 브라우저가 이해할 수 있지만, 여전히 html 내 컨텐츠는 비어있는 상황이다.

예제에서는 아이디가 root인 루트 div 안에 과 같은 주석만 존재하는 상태이다.

이때 npm run build:server , 즉 다음 명령어를 통해 서버를 빌드한다.

vite build --ssr src/entry-server.jsx --outDir dist/server 

이 명령어를 통해 빌드된 서버 파일, entry-server.jsdist/server로 내보내게 된다. 이 파일은 render 함수를 export한다.
render 함수에서는 ReactDOM/server에서 제공하는 renderToString 메소드를 활용하여 jsx 문법으로 작성된 <App />, 즉 우리가 html 내에 위치시키고자 하는 컨텐츠를 string 형태로 렌더링한다.

이제 남은 것은, 이를 실제 index.html 파일 내에 주입하는 것이다. prerender.js가 이 동작을 수행한다.

node prerender

prerender가 실행되면, 일단 앞서 빌드된 dist/static 디렉토리 안의 index.html을 읽어온다. 그리고 해당 html 내에 컨텐츠가 들어갈 자리, 즉 주석 <! - root-html - >을 찾아 앞서 렌더링된 string으로 replace한다.
이렇게 수정된 파일을 dist/static/index.html로 생성한다.
이제 컨텐츠가 존재하는 index.html이 완성되었다!
이제 이렇게 생성된 dist 디렉토리내의 정적 파일을 배포하면 된다.


+) 기존 예제에서는 react-router를 활용하였으며, 사전 렌더링 과정에서 pages 내의 파일이 각각의 html로 만들어진다.

profile
Define, Design, Develop

0개의 댓글

관련 채용 정보