Gatsbyはどうやって静的サイトをジェネレートしているのか

こんにちは! Pairs JP事業部のWebエンジニアのOTです⚡️

GatsbyReactベースの静的サイトジェネレーターです。
生成される静的サイトはシングルページアプリケーションでもあるため、優れたUXをユーザーに提供できます。
GatsbyはReactの公式サイトを始め、多くのサイトで採用されています。
弊社でもいくつかのGatsby案件が進行中です 😎

また、Gatsbyのユニークな特長として、静的サイトのリソースのデータ取得にGraphQLを使っているというところがあります。

ローカルのMarkdownファイルやContentful・WordPressといった外部CMSのWebAPIをデータソースとして、GraphQLを通じて一元的に扱うことができます。

ページごとに必要なデータをGraphQLのクエリを一発投げて取るだけになるので実装がクリアになります。
例えばこのような感じです。

しかし、GraphQLを使うということはSchemaを定義してデータの取得実装を持ったいわゆるGraphQLサーバーを立てる必要があるな、と考えるのが自然だと思うんですが、ところがどっこいGatsbyはそのあたりをbuild処理の中ですべて自動で行なっています。

例えばデータソースにContentfulを使いたい場合、gatsby-source-contentful というプラグインを使います。プラグインを有効にする作業は

  • プラグインをインストール
npm install —-save gatsby-source-contentful
  • プラグインの設定(Contentfulのクレデンシャル情報)をgatsby-config.jsに書く
  {
resolve: `gatsby-source-contentful`,
options: {
spaceId: `your_space_id`,
accessToken: `your_access_token`,
},
},
];

だけです。

これでgatsby buildでビルドを実行すると、ContentfulのデータをGraphQLクエリで取得してページが生成されます。

これはほとんどマジックじゃないでしょうか?

このGatsbyがbuild処理の中でGraphQLスキーマ・データ取得処理を生成し、クエリを投げてページを生成する仕組みに興味を持ったので内部処理を少し読んでみました。

バージョンは
gatsby: 1.9.238
gatsby-source-contentful: 1.3.48
です。

Contentfulのセットアップについては下記が参考になりました😊

次世代Headless CMS「contentful」事始め

gatsby build

Gatsbyのbuild関数(packages/gatsby/src/commands/build.js)では大きく下記が順次実行されます。
1. bootstrap
2. onPreBuild
3. copyStaticDirectory
4. buildCSS
5. buildProductionBundle
6. buildHTML
7. onPostBuild

ちなみにビルドの状態管理にはReduxが使われています。
ビルドのようなヘッドレスな環境でReduxが出てきたことには、えっ?となりましたが、理にかなっていてユニークだと思いました。

Gatsby Node API

Gatsbyにはビルド時にプラグインがデータ取得やスキーマ生成などの処理を差し込めるフックポイントとしてNode APIというものが用意されています。

ほとんどのNode APIはbootstrapの中で実行されます。

プラグインのgatsby-node.jsにフックさせたいAPIの名前で関数を書いておけば、ビルド時に実行されます。

gatsby-node.js

// createPages API
exports.createPages = () => {
return new Promise((resolve, reject) => {
// do なにか
})
}

gatsby-source-contentful を使ったプロジェクトでのNode APIの実行順序を調べてみたところ、こんな流れでフックされていました。

  1. onPreBootstrap
  2. sourceNodes
  3. onCreateNode
  4. setFieldsOnGraphQLNodeType
  5. resolvableExtensions
  6. onCreateLayout
  7. createLayouts
  8. createPages
  9. onCreatePage
  10. onCreateNode
  11. createPagesStatefully
  12. onPreExtractQueries
  13. setFieldsOnGraphQLNodeType
  14. preprocessSource
  15. onPostBootstrap
  16. onPreBuild
  17. modifyBabelrc
  18. modifyWebpackConfig
  19. onPostBuild

gatsby-source-contentful のgatsby-node.jsで実装されているフックメソッドはこの3つだけです。

  • sourceNodes
  • setFieldsOnGraphQLNodeType
  • onPreExtractQueries

このうちコアなのはsourceNodessetFieldsOnGraphQLNodeTypeのAPIです。
sourceNodesではContentful APIから取得したデータをもとにしてGatsbyが持つNodeのデータ構造を作ります。
setFieldsOnGraphQLNodeTypeではNodeからGraphQLのスキーマを生成します。

Node Interface

NodeはGatsbyの根幹となるデータ構造です。

Gatsbyはさまざまな外部ソースのデータをNode化して、NodeをGraphQLスキーマに変換しています。
データ構造をNodeで一元管理しているからGraphQLスキーマへの変換を統一的に行えているわけですね。

まとめ

まだまだビルド処理の浅いところなのですが、時間の都合上、今回はここまでです🙏
GatsbyはReactとGraphQLを軸にしたユニークでパワフルな次世代静的サイトジェネレーターだと思います。
今後さらに採用事例が増えてくると思います。
これからもwatchしていきます!😊

Like what you read? Give Sogo Ohta a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.