Gatsbyはどうやって静的サイトをジェネレートしているのか
こんにちは! Pairs JP事業部のWebエンジニアのOTです⚡️
GatsbyはReactベースの静的サイトジェネレーターです。
生成される静的サイトはシングルページアプリケーションでもあるため、優れた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の実行順序を調べてみたところ、こんな流れでフックされていました。
- onPreBootstrap
- sourceNodes
- onCreateNode
- setFieldsOnGraphQLNodeType
- resolvableExtensions
- onCreateLayout
- createLayouts
- createPages
- onCreatePage
- onCreateNode
- createPagesStatefully
- onPreExtractQueries
- setFieldsOnGraphQLNodeType
- preprocessSource
- onPostBootstrap
- onPreBuild
- modifyBabelrc
- modifyWebpackConfig
- onPostBuild
gatsby-source-contentful のgatsby-node.jsで実装されているフックメソッドはこの3つだけです。
- sourceNodes
- setFieldsOnGraphQLNodeType
- onPreExtractQueries
このうちコアなのはsourceNodes
とsetFieldsOnGraphQLNodeType
のAPIです。sourceNodes
ではContentful APIから取得したデータをもとにしてGatsbyが持つNodeのデータ構造を作ります。setFieldsOnGraphQLNodeType
ではNodeからGraphQLのスキーマを生成します。
Node Interface
NodeはGatsbyの根幹となるデータ構造です。
Gatsbyはさまざまな外部ソースのデータをNode化して、NodeをGraphQLスキーマに変換しています。
データ構造をNodeで一元管理しているからGraphQLスキーマへの変換を統一的に行えているわけですね。
まとめ
まだまだビルド処理の浅いところなのですが、時間の都合上、今回はここまでです🙏
GatsbyはReactとGraphQLを軸にしたユニークでパワフルな次世代静的サイトジェネレーターだと思います。
今後さらに採用事例が増えてくると思います。
これからもwatchしていきます!😊