ソフトウェア開発
2019/02/16 11:00
当ブログでも使用されているReact用の静的サイトジェネレータGatsbyJsのコンセプト、技術的な仕組みや、使い方について紹介します。
GatsbyJsは、React用に作られたモダンで高速なサイトを作成できる静的サイトジェネレータです。
当ブログもGatsbyJsで構築されていますが、GatsbyJsのサイトのトップページに書かれている様に、驚くほど簡単に爆速モダンWebサイトを構築できます。
Build modern, beautiful, secure, blazing fast, apps and websites with React.
そんなGatsbyJsは大きく分けると以下の4つのコンセプトに基づいて実装されています。
GatsbyJsの魅力を十分に伝えるために、まずはそれぞれのコンセプトについて説明します。
React.js、Webpack、Babel、様々なJavascript・CSS便利なライブラリなど、モダンWeb開発の技術は次々に登場していますが、それらをすべて自前で構築するのは苦痛を伴います。
GatsbyJsでは、gatsby new
とコマンドを実行すれば、React・babel・webpack等のモダンWeb開発環境がセットアップ済みのプロジェクトを作成することが出来ます。このあたりはFacebook公式のcreate-react-appのような使い心地です。
またTypescript、styled-componentsなどの言語・ライブラリを導入する際も、GatsbyJsはプラグインをインストールし、簡単な設定を書くだけで実現することが出来ます。
さらに、gatsby-starter-typescript等のように、必要なプラグインがすでにセットアップされたスターターをプロジェクトを作成時に指定することもできます。(公開されているプラグインやスターター一覧)
もちろんWebpackやbabelの設定を自分でカスタマイズすることも可能なので、環境を構築したあとに状況変化に柔軟に対応することが出来ます。
この様に、モダンなWeb技術を手軽にためすことができるのはGatsbyJsの強みの一つです。
GatsbyJsの超絶パフォーマンスは大きくわけると
の4つの工夫によって実現されています。
GatsbyJsは静的サイトジェネレータの為、Wordpress等の既存のCMSの様にページ要求に応じてページを作成するのではなく、ページを事前に構築してそれをWebサーバーにホストすることで、ユーザーからの要求に対して迅速にページを配信することが出来ます。
GatsbyJsでビルドされたページは、SPA(Single Page Application)として動作します。Wordpress等で作成されたページでは、遷移時にページ全体のHTMLが書き換わりますが、SPAのページはJavascriptを用いてページ内のHTMLを部分的に差し替えてコンテンツを切り替える為、高速な画面遷移を実現できます。
SPAでページを構築する場合ページ全体がJavascriptで記述されている為、初回のページローディングにかかる時間が増えるというデメリットがありますが、GatsbyJsはビルドする際にSSR(Server Side Rendering)するため、ユーザーにはすでにJavascriptが実行済みのHTMLを返却することができるので、**初回ローディングのパフォーマンス劣化を防いでいます。**また、SEO的にもSSRされている方が安心できるのも嬉しいですね。
Gatsby.jsはGoogleが提唱するPRPLというProgressive Web App(PWA)を構築・配信するための実装パターンを採用しています。PRPLとは以下の言葉を表しています。
簡単に言うと、GatsbyJsがビルドするページは初回ロード時に重要なHTML, アセット類のみをローディングするため初回ローディングスピードが速く、一度ロードされると他のページのリソースをプリフェッチする為ページ遷移が爆速になるということです。
上述の4つの工夫によって、GatsbyJsでWebサイトを作ると誰がどう作っても超絶パフォーマンスなサイトを作成出来ます。
GatsbyJsはプラグインを利用することで、**1つまたは複数のデータソースから必要なデータを使ってWebサイトを構築出来ます。**データはGraphQLを介して取得する事ができ、対象とするデータソースは、ヘッドレスCMS、Sassサービス、API、DB、マークダウン等のファイルシステム等幅広く対応しています。
例えば、Wordpressでサイトを運用していたがGatsbyJsでページを作り直したいという状況であれば、gatsby-source-wordpressというプラグインを使って、WordPress REST APIからページ構築のために必要なデータを取得し、ページのテンプレートはReactで記述して、GatsbyJsで静的ページをビルドする等の構成も簡単に実現することが出来ます。
これはGatsbyJsというよりも静的サイトジェネレータ全般の特性ですが、データベースやアプリケーションサーバーなど、複雑なインフラ構成を要せず、ホスティングサーバーに事前ビルドしたファイルを配置しておけばいいだけなので、**インフラ構築・メンテナンスコスト・サイトスケーリング・セキュリティについて殆ど気にすることがありません。**個人で運営するサイトや、コーポレートサイトなどの様に専任の開発担当がいない状況において非常にありがたい特徴です。
GatsbyJsの実際の使い方を、マークダウンをデータソースとしたブログ記事ページの作成過程を具体例として説明しようと思います。
Gatsbyプロジェクトの作成・ビルドなどはGatsby CLIを使用します。Gatsby CLIはnpmパケージとして公開されており、Gatsbyプロジェクトの作成をする際はnpx経由で以下のようにコマンドを実行します。
npx gatsby new blog https://github.com/gatsbyjs/gatsby-starter-hello-world
gatsby new [rootPath] [starter]
コマンドは、rootPath
にプロジェクトのルートディレクトリ名、starter
にプロジェクトの雛形となるスタータープロジェクトのURLを指定することで、Gatsbyプロジェクトを作成するコマンドです。
作成されたGatsbyプロジェクトの構成は以下の様になります。各ディレクトリの説明は公式ドキュメントを参照してください。
次に作成したGatsbyプロジェクトに移動して、以下のコマンドを実行することで、Gatsbyプロジェクトがビルドされた開発サーバーが立ち上がります。
cd blog npm run development
そして、ブラウザでhttp://localhost:8000
にアクセスすればビルドされたページが表示されます。
このnpm run develop
コマンドは、npm scriptとしてgatsby develop
というGatsby CLIのコマンドが実行されるように定義されてあります。
"scipts": { "develop": "gatsby develop" }
Gatsby CLIの各種コマンドのより詳しい説明は公式ドキュメントをみるか、npx gatsby -h
で確認することが出来ます。
無事Gatsbyプロジェクトを作成することが出来たので、次はページの作成方法について説明します。
Gatsbyプロジェクトでページの作成する方法は大きくわけると2つあります。
先程作成したGatsbyプロジェクトのsrc/pages
ディレクトリに以下の様にabout.js
というファイルを追加します。
// src/pages/about.js import React from 'react' const About = () => ( <div> <h1>About Page</h1> <div>This is a About Page</div> </div> ) export default About
そして、ブラウザからlocalhost:8000/about
にアクセスすれば以下のページが表示されます。
この様に、GatsbyJsはビルド時にsrc/pages
ディレクトリにあるReactコンポーネントをファイル名に対応するパスのページに変換してくれるのです。
先程のやり方でWebサイトの全てのページを作成してもよいのですが、ブログを作成するとなると、すべてのコンテンツページ用のReactコンポーネントを作成するわけにはいきません。
そのため、GatsbyJsではテンプレートとなるReactコンポーネントを指定してプログラマブルにページを作成するcreatePages
というAPIを用意しています。
まずはじめに、プロジェクトのルートディレクトリ直下にgatsby-node.js
というファイルを以下の様に作成します。
// gatsby-node.js const path = require("path"); const blogs = [ { path: "blogs/1", date: "2019/02/15", title: "My first blog post" }, { path: "blogs/2", date: "2019/02/16", title: "My second blog post" } ]; exports.createPages = ({ graphql, actions }) => { const { createPage } = actions; return new Promise((resolve, reject) => { blogs.forEach(blog => createPage({ // ページのパス名 path: blog.path, // テンプレートとなるコンポーネントの指定 component: path.resolve(`src/templates/blog-template.js`), // テンプレートとなるコンポーネントに渡す変数 context: { path: blog.path, date: blog.date, title: blog.title } }) ); resolve(); }); };
次に、テンプレートに指定するコンポーネントをsrc/templates/blog-template.js
に作成します。
// src/templates/blog-template.js import React from 'react' const BlogTemplate = ({ pageContext: { title, path, date } }) => ( <div> <h1>{`${title} Page`}</h1> <div>date : {date}</div> </div> ) export default BlogTemplate
そして、npm run develop
で開発サーバーを立ち上げて、ブラウザからlocalhost:8000/blogs/1にアクセスすると、以下のページが表示されるはずです。
この時点ではブログのデータを定数で用意してますが、次の節でGraphQL経由でブログのデータを取得し、そのデータをもとにページを作成できるようにします。
GatsbyJsを使ってページを作成する方法を説明したので、次はGraphQL経由でマークダウンから記事の取得し、取得したデータを使ってページを構築する方法について説明します。
また、今回はGraphQLについては詳しく説明しませんので、詳細が気になる方は公式ドキュメントを確認してください。
はじめにマークダウンからデータを取得できるようにするためにgatsby-source-filesystem
とgatsby-transformer-remark
というプラグインをインストールします。
npm install --save gatsby-source-filesystem gatsby-transformer-remark
gatsby-source-filesystem
はGatsbyからファイルシステムを読み込めるようにするために、gatsby-transformer-remark
はマークダウンファイルのパースをするために必要なプラグインです。
次にプラグインの設定を有効化するため、gatsby-config.js
ファイルをプロジェクトのルートディレクトリに作成します。
// gatsby-config.js module.exports = { plugins: [ { resolve: `gatsby-source-filesystem`, options: { path: `${__dirname}/src/markdowns`, name: "markdown-pages", } }, `gatsby-transformer-remark`, ] }
これでマークダウンを使用する準備はできたので、次はデータソースにするマークダウンファイルをsrc/markdowns
ディレクトリ内に作成します。ファイルの先頭に追加したブロック内の情報は、gatsby-transformer-remark
によってパースされてGraphQL経由で取得できるようになります。
// src/markdowns/my-first-post.md --- path: "blogs/1" date: "2019/02/15" title: "My first blog post" --- # My First Blog Post texttexttexttexttexttexttexttexttext
// src/markdowns/my-second-post.md --- path: "blogs/2" date: "2019/02/17" title: "My second blog post" --- # My Second Blog Post texttexttexttexttexttexttexttexttext
マークダウンをデータソースにするための設定が完了したので、次はマークダウンの記事データからページを作成できるようにします。
gatsby-node.jsのソースコードを以下の様に書き直しました。
graphqlを使ってマークダウンファイルのデータを取得し、そのデータを使って
createPage`でページを作成しています。
//gatsby-node.js const path = require('path') exports.createPages = ({ graphql, actions }) => { const { createPage } = actions return graphql(` { allMarkdownRemark( sort: { order: DESC, fields: [frontmatter___date] } limit: 1000 ) { edges { node { frontmatter { path date title } } } } } `).then(result => { if (result.errors) return Promise.reject(result.errors) result.data.allMarkdownRemark.edges.forEach(({ node }) => { createPage({ path: node.frontmatter.path, component: path.resolve(`src/templates/blog-template.js`), context: { path: node.frontmatter.path, date: node.frontmatter.date, title: node.frontmatter.title, } }) }) }) }
ここで再度npm run develop
で再ビルドし、ブラウザでlocalhost:8000/blogs/1
にアクセスすると、ちゃんとマークダウンのデータからページが作成されていることが確認できます。
マークダウンのデータからページを作ることができるようになりましたが、このままだとマークダウンの項目が追加されたり変更された場合に、gatsby-node.js
やコンポーネントのファイルなどあちこち修正しなければいけないのと、createPages
APIを使ってページを作成しないとGraphQL経由でデータが取得出来ないため困ってしまいます。
GatsbyJsでは、ページ・テンプレートのコンポーネントのファイル内でGraphQLのスキーマの定義、データの受け渡しができる仕組みが用意されているので、その仕組を使って書き直します。
まずgatsby-node.js
のcontextで渡す変数としてpath
だけを渡すようにします
// gatsby-node.js exports.createPages = ({ graphql, actions }) => { // 全体的に省略 context: { path: node.frontmatter.path } }
そして、src/templates/blog-template.js
のコードを以下の様に書き直します。
// src/templates/blog-template.js import React from 'react' import { graphql } from 'gatsby' const BlogTemplate = ({ data }) => { const { markdownRemark: { html, frontmatter: { title, date } } } = data return ( <div> <h1>{`${title} Page`}</h1> <div>date : {date}</div> <div dangerouslySetInnerHTML={{ __html: html }} /> </div> ) } export default BlogTemplate export const pageQuery = graphql` query($path: String!) { markdownRemark(frontmatter: { path: { eq: $path } }) { html frontmatter { date title } } } `
マークダウンデータを取得するためのGraphQLのクエリがファイルの後半で記述されています。
export const pageQuery = graphql` query($path: String!) { markdownRemark(frontmatter: { path: { eq: $path } }) { html frontmatter { date title } } } `
Gatsbyはこのクエリの結果を、BlogTemplateのpropsにdata
プロパティとして注入します。
const BlogTemplate = ({ data }) => { const { markdownRemark: { html, frontmatter: { title, date } } } = data // 省略
そして、再度npm run develop
し直し、ブラウザでアクセスlocalhost:8000/blogs/1
にアクセスすると、正しくブログが表示されているのと、マークダウンで記述した本文もちゃんと表示されていることが確認できます。
これで、GatsbyJsを使ってマークダウンからブログページを作成することが出来ました。
同じような要領で、src/pages/index.js
でGraphQLのスキーマを記述して、ブログ一覧を表示させるなども簡単に実現できるようになります。
GatsbyJsはWordpressで構築しているサイトの用途であれば同様かそれ以上に向いているのではと思います。
例えば
など様々な利用シーンが考えられます。GatsbyJsを採用しているサービスのリストが公式に公開されているのでそれを見ると利用用途がイメージしやすいかもしれません。
一方、事前ビルドに時間がかかりすぎてしまうためページ数が数万にもなるような大規模サイトや、認証を伴う会員制サービス等はあまり向いていないと感じます。
認証機能を伴うサイト構築のチュートリアルが公式で公開されてはいますが、やはり用途は限定されてしまうのではというのと、それならNext.jsでアプリケーションを構築したほうが楽なのでは?と個人的には思います。
GatsbyJsはモダンで高速なWebサービスを簡単に構築するということに特化しており、普段Reactを書いている人が自分の個人のサイトを作ったり、コーポレートサイトを作ってくれと言われたときには非常に有力な選択肢になると思います。
また、使われている技術も非常に先進的なので、GraphQLやPWA、SSRなどGatsbyJsを使う中で様々な技術の学習をする事ができるというのもいいポイントです。
わかりやすいチュートリアルが公開されている事とexampleサイトも多数公開されているので、Webフロントエンドがそこまで詳しくない方も安心して挑戦できると思いますので、本記事でGatsbyJsに興味を持った方はぜひとも試してみてください。
COPYRIGHT TSUKAMON ALL RIGHTS RESERVED.