Please enable JavaScript to view the comments powered by Disqus.

Gatsby v1에서 달라진 점들

이 블로그는 Gatsby로 만들었다. 작년 연말 블로그를 만들기로 한 후 정적 사이트 생성기(static site generator)를 둘러보다가 Gatsby의 존재를 알게 되었다. Node.js와 Javascript 언어를 기반으로 하며 React로 페이지 구성을 할 수 있다는 건 프론트엔드 개발을 하는 나에게 무척 매력적인 요소였다. 원래 유력한 후보는 더 폭넓은 사용자와 성숙도를 가진 jekyll이었지만 Gatsby를 선택하게 되었다.

서버 렌더링을 이용한 정적인 페이지 생성

React는 SPA(Single Page App) 개발을 위한 뷰 라이브러리로서 가상 DOM을 사용하기 때문에 앱 구동시점에는 빈 페이지가 브라우저에 전달된다. SPA는 네이티브 모바일 앱처럼 빠른 화면 전환이 가능하다는 장점이 있지만 검색 엔진에는 컨텐츠를 제대로 제공할 수 없기 때문에 검색 엔진 최적화가 필요한 웹사이트에는 맞지 않다고 여겨진다.

하지만 서버 렌더링을 사용하면 앱 구동 시점의 페이지를 구성하는 가상 DOM을 서버 상에서 렌더링한 후 정적인 DOM으로 변환해서 브라우저에 전달할 수 있다. 서버 렌더링은 최초 한번만 이루어지기 때문에 SPA의 장점은 유지하면서 검색 엔진에게 데이터도 제공할 수 있다. 그래서 검색 엔진 최적화가 필요한 웹사이트의 프론트엔드 레이어를 SPA로 구성할 경우 서버 렌더링 방식은 거의 필수적으로 사용되고 있다.

Gatsby도 서버 렌더링 방식을 사용해서 페이지를 만든다. 하지만 블로그는 보통 서버 앱을 따로 구동하지 않고 github-pages나 AWS S3 같은 정적인 저장소에 올리는 것이 보통이다. 그래서 Gatsby는 빌드를 할 때 앱에서 접근 가능한 모든 라우트에 대해 서버 렌더링된 페이지를 미리 만들어 둔다. 바꿔 말하면 일반적인 SPA 웹사이트의 진입 페이지가 index.html 하나라면 Gatsby로 빌드된 웹사이트는 index.html이 모든 라우트마다 있다는 의미다.

Gatsby v0에서 아쉬웠던 점

v1 이전에서 Gatsby는 페이지를 생성하는 방식에 제한이 있었다. 우선 페이지를 만들기 위해서는 wrapper 라는 템플릿 컴포넌트가 파일 확장자별로 필요하다. 보통 블로그 컨텐츠는 마크다운 형식으로 작성하기 때문에 템플릿은 컴포넌트는 보통 하나만 필요했다. 그리고 페이지는 소스 파일 단위로 생성된다.

페이지가 파일별로 생성된다는 점, 이 부분에 다소 문제가 있었다. 포스트 본문은 마크다운 파일이 존재할 것이기에 문제가 없다. 하지만 태그별 페이지를 만드려고 한다면 까다로워진다. 태그를 직접 정리해서 직접 태그 페이지용 파일을 추가하고 삭제하는 건 전혀 스마트하지 않은 방법이다. 태그용 페이지만 하나 만들어서 태그별 포스트 목록을 동적으로 보여줄 수는 있겠지만 역시 반쪽짜리 구현으로 보인다.

Gatsby v1에서 달라진 점

앞서 언급했던 부분은 v1에서 새로운 API의 제공으로 완전히 해결되었다. 그 외에도 많은 새로운 기능을 제공함으로써 Gatsby v1은 서버 렌더링을 사용해서 정적인 페이지를 만들어낸다는 컨셉을 제외하고는 거의 모든 것이 바뀐 새로운 라이브러리라고 봐도 될 것 같다. 주요 변경점은 다음과 같다.

  • GraphQL과 node 인터페이스에 기반한 데이터 관리
  • 플러그인
  • 라이프사이클 API 제공

GraphQL

Gatsby는 이제 로컬 서버에서 GraphQL을 사용해 데이터를 관리한다. 모든 정보는 node interface라는 데이터 구조를 기반으로 구성되며 GraphQL 쿼리를 사용해서 데이터를 가져와야 한다. GraphQL에 대해 잘 모른다고 하더라도 마이그레이션 가이드, Gatsby에서 GraphQL을 사용하는 방법을 설명하는 아티클을 참조하면 대략 어떻게 사용해야 하는지는 파악할 수 있다. 아래는 페이지 템플릿 컴포넌트에서 사용하는 쿼리 예제다.

export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      timeToRead
      fields {
        tagSlugs
      }
      frontmatter {
        title
        tags
        date(formatString: "YYYY-MM-DD")
        description
      }
    }
  }
`

위의 쿼리를 간략히 설명하자면 다음과 같다.

  • BlogPostBySlug라는 이름의 쿼리는 $slug(현재 페이지 경로)에 해당하는 markdownRemark(마크다운 파일을 node 인터페이스로 변환한 데이터)를 가져온다.
  • markdownRemark 데이터에서 html, timeToRead, frontmatter 등 필요한 필드만 선택해서 가져온다.
  • 쿼리 결과는 컴포넌트의 props 객체의 필드로 전달된다.

v0에서는 쿼리 없이도 필요한 데이터가 기본적으로 제공되었지만 이제는 무조건 쿼리를 작성해야 한다.

플러그인

v1에서 Gatsby 라이브러리는 GraphQL로 데이터를 구조화하고 서버 렌더링으로 페이지를 생성하는 핵심 기능 외에는 모두 플러그인을 통해 기능을 구현하도록 했다. 예를 들어 마크다운 파일을 Gatsby에서 사용할 수 있는 형태로 변환하는 기능도 v0에서는 gastby에 포함되어 있었지만 v1에서는 별도의 플러그인을 사용해야 한다. 하지만 필요한 대부분의 플러그인이 이미 구현되어 있으니 공식 홈페이지의 플러그인 목록을 참조해서 필요한 플러그인들을 선택해서 사용하면 된다. 하지만 플러그인이 무척 작은 단위로 구분되어 있고 종류가 다양하기 때문에 예제 프로젝트를 참조해서 플러그인을 설치하는 편이 좋을 것이다.

플러그인을 사용하면 링크된 모든 정적인 파일을 public 폴더로 옮기는 기능, css-in-js 관련 라이브러리를 사용, 구글 애널리틱스와 태그 매니저 연결, 웹앱 manifest, sitemap, RSS feed 파일 생성 등 매우 다양하고 유용한 기능들을 사용할 수 있다. 다만 플러그인은 모두 독립적인 npm 모듈이라서 Gatsby 라이브러리에는 포함되어 있지 않으며 직접 설치해서 사용해야 한다.

라이프사이클 API 제공

v0에서도 빌드 시점, 브라우저 시점에서 코드를 실행할 수 있었다. v1에서는 빌드, 서버 사이드 렌더링, 브라우저 시점에서 사용할 수 있는 API를 보다 다양하게 제공한다. 예를 들어 브라우저 API는 최초 구동 시점, 최초 렌더링 시점, 라우트가 변경되는 시점에 사용할 수 있는 API를 구분해서 제공한다. 이는 마치 React의 컴포넌트 라이프사이클 메소드와 유사하다.

특히 빌드 시점에서 사용하는 Node API는 페이지를 직접 생성할 수 있는 API를 제공한다. 예를 들자면 GraphQL 쿼리로 마크다운 데이터를 불러온 후 쿼리 결과 배열이 가지고 있는 객체별로 페이지를 생성하는 과정을 사용할 수 있을 것이다. 그리고 v0에서는 만들기 어려웠던 태그별 페이지도 마크다운 데이터의 frontmatter 데이터를 사용해서 빌드 시점에서 생성해둘 수 있다.


포스트를 작성하는 시점에서 Gatsby는 v1이 배포된지 약 한 달이 지났으며 지속적으로 마이너 버전이 배포되면서 새로운 플러그인도 추가되고 있다. Gatsby 공식 홈페이지에도 초기에는 없었던 Starters 메뉴가 추가되었는데, 기본적인 기능이 구현된 데모 사이트와 소스 파일을 제공하고 있다. v1에서는 간단한 사이트를 만들기 위해서도 제법 많은 종류의 플러그인을 사용해야 하기 때문에 빠른 시작을 위한다면 데모 사이트가 큰 도움이 될 것으로 보인다.