Jamstack は Web 開発のアーキテクチャです。この記事では Jamstack についてご紹介し、Jamstack 構成のシンプルなブログサイトを作ります。
Jamstack とは
Jamstack は Netlify の 創業者 Matt Biilmann 氏が名付けたアーキテクチャです。Jamstack とは一体なんでしょうか。Jamstack の公式サイト jamstack.org では、Jamstack を次のように定義しています。
A modern architecture —
Create fast and secure sites and dynamic apps with JavaScript, APIs, and prerendered Markup, served without web servers.
https://jamstack.org/
和訳すると「JavaScript、API、プリレンダリングされた Markup を使用し、Web サーバなしで提供される高速で安全なサイトおよび動的アプリケーションを作成するモダンアーキテクチャ」となります。
Jamstack は「JavaScript」「API」「プリレンダリングされた Markup」の3つの要素を持ちます。「Jam」の「J」が「JavaScript」、「a」が「API」、そして「m」が「Markup」です。また、Jamstack は Web サーバに依存しないという特徴があります。
JavaScript
すべての動的プログラミングはクライアント(ブラウザ)の JavaScript が行います。クライアントの JavaScript は特定の方法を指しません。フレームワークやライブラリを使ってもよいですし、Vanilla JavaScript でもかまいません。
API
すべてのサーバの処理は Web API を通じて行います。クライアントの JavaScript が Web API を呼び出し、データの送受信を行います。サードパーティのサービスを利用したい場合は Web API を通じて利用します。
プリレンダリングされた Markup
プリレンダリングとは、サイトやアプリケーションの各ページの初期状態を HTML ファイルとして事前に生成することを指します。ページの見た目を定義するテンプレートに実際のデータを注入し、その結果を HTML ファイルとして生成します。プリレンダリングは静的サイトジェネレータやビルドツールを用いてビルド時に行います。
なお、2020年1月時点の公式サイトでは Jamstack の定義から「JavaScript」「API」「Markup」の文字が消えています。しかし、「Jam」の説明のため、この記事では 2019年12月時点の定義をご紹介しました。2020年1月時点の公式サイトの Jamstack の定義は次の通りです。
Fast and secure sites and apps delivered by pre-rendering files and serving them directly from a CDN, removing the requirement to manage or run web servers.
https://jamstack.org/
和訳すると「ファイルをプリレンダリングし CDN から配信される、高速で安全なサイトとアプリケーションで、Webサーバの管理・実行の必要がない」となります。
また、2019年11月時点の公式サイトでは Jamstack の表記が「JAMstack」となっていましたが、2019年12月半ばに「Jamstack」に変更されています。この記事では引き続き、変更後の「Jamstack」と表記します。
ブログサイトの作成
それでは Jamstack 構成のブログサイトを作ってみましょう。
今回は、データソースとして Markdown ファイルを用意します。次に Gatsby を使って Markdown ファイルの内容をデータとして取得し、ブログサイトを作ります。静的サイトジェネレータの Gatsby を使うことで、ビルド時に静的ファイルを出力します。最後に Netlify を使ってブログサイトのビルド、デプロイを行います。
- データソース:Markdown ファイル
- 静的サイトジェネレータ:Gatsby
- ビルド、デプロイ:Netlify
※Gatsby: React ベースの静的サイトジェネレータ
※Netlify: Web サイトの自動化のためのオールインワンのプラットフォーム。ビルド、デプロイ、ホスティングといった機能を提供している
また、サンプルコードは GitHub にアップしています。合わせてご参照ください。
https://github.com/mokajima/jamstack-demo
※後述の Netlify にデプロイするにて、デプロイ時に Git のリポジトリを使用します。ご自身のリポジトリをご用意いただくか、サンプルコードをフォークいただき、お試しください。
環境構築
Gatsby の CLI を使って環境構築を行います。以下のコマンドを実行してください。
$ npx gatsby new jamstack-demo https://github.com/gatsbyjs/gatsby-starter-default
このコマンドは gatsby-starter-default というスターターコードを使い、jamstack-demo というディレクトリ名で Gatsby のプロジェクトを作成します。
プロジェクトの作成が終わったら cd jamstack-demo
で jamstack-demo
ディレクトリに移動し、yarn start
で開発サーバを起動します。開発サーバを起動すると http://localhost:8000 でサイトの表示を確認できるようになります。
$ cd jamstack-demo; yarn start
データソースの追加
データソースの Markdown ファイルを追加しましょう。src
ディレクトリ直下に markdown-pages
ディレクトリを作り、post1.md
post2.md
post3.md
を追加します。
---
のブロック内は frontmatter と呼ばれるデータです。「キー: 値」の形式で記述し、Markdown ファイルにデータを持たせることができます。ここでは title
date
slug
を指定しています。
なお、Gatsby では様々なデータソースを扱うことができ、Markdown ファイルの他にも、API、データベース、CMS、ローカルファイルなどを利用可能です。
ソースプラグインの追加
Gatsby で各種データソースを扱うには「ソースプラグイン」と呼ばれる専用のプラグインを追加する必要があります。ソースプラグインはデータソースからデータを取得するために使用します。Markdown ファイルをデータソースとして扱うには gatsby-source-filesystem
が必要です。このプラグインは gatsby-starter-default
ではインストール済みですが、設定の追加が必要です。そこで gatsby-config.js
を編集します。gatsby-config.js
はその名の通り、Gatsby の設定に関する記述を行うためのファイルです。
gatsby-config.js
の plugins
配列の中に resolve: gatsby-source-filesystem
の箇所があります。その下の options
を書き換えてください。
resolve
には使用するプラグイン名を指定します。使用するプラグインによってはオプションを持たせることができ、options
を使って指定します。ここでは name
に識別用の名前、path
にデータソースの場所を指定しています。
gatsby-config.js
を書き換えたら開発サーバを再起動してください。
開発サーバを再起動したら、Markdown ファイルをデータとして取得できているか確認してみましょう。Gatsby では GraphQL を使ってデータにアクセスします。
GraphQL
GraphQL は Facebook が開発した API のためのクエリ言語です。GraphQL のクエリは query クエリ名 {}
の形で定義します。query
キーワードとクエリ名は省略可能です。
以下のクエリは、データソースの追加で追加した Markdown ファイルをデータとして取得できているかを確認するためのクエリです。ファイルの相対パスの relativePath
とファイルの識別名(データソースの追加の gatsby-config.js
の gatsby-source-filesystem
の設定で指定した name
)の2つのフィールドを取得しています。
query MyQuery {
allFile {
edges {
node {
relativePath,
sourceInstanceName
}
}
}
}
query
は「データを取得する」という操作を表します。query
では取得したいデータの構造を定義すると、その通りのレスポンスを得ることができます。例えば、上記のクエリを実行した結果は次のようになります。
※GraphQL では query
の他にも mutations
や subscription
という操作が存在します。
allFile
edges
node
relativePath
sourceInstanceName
はデータのフィールドです。allFile
はソースプラグイン gatsby-source-filesystem
によって利用可能となったフィールドで、すべてのファイルを取得します。使用するソースプラグインによって、利用可能なフィールドが変わります。
GraphiQL
GraphiQL は GraphQL の IDE(統合開発環境)です。GraphQL のクエリを実行したり、各フィールドの構造を確認したりすることができます。開発サーバの起動中は http://localhost:8000/___graphql で利用可能です。
以下のクエリを GraphiQL 上で実行してみましょう。GraphiQL を開くと左側にエクスプローラがあり、その右隣にはクエリを入力するエディタがあります。エディタに以下のクエリを入力し、再生ボタンをクリック、ないしは Ctrl-Enter を押すとクエリが実行されます。クエリ結果はエディタの右隣に表示されます。
query MyQuery {
allFile {
edges {
node {
relativePath,
sourceInstanceName
}
}
}
}
クエリの実行結果から、データソースの追加で追加した Markdown ファイルをデータとして取得できていることがわかります。
なお、GraphiQL のエクスプローラでは各フィールドの構造を確認したり、クエリを組み立てたりすることが可能です。例えば、allFile
の左横の三角形を開いていくと、edges
に node
が、node
に relativePath
や sourceInstanceName
が含まれているのがわかります。また、各フィールド名の左横のチェックボックスにチェックを入れると、そのフィールドがエディタのクエリに追加されます。
トランスフォーマープラグインの追加
ソースプラグインの追加で Markdown ファイルをデータとして取得できるようになりました。次は Markdown ファイルをパースし、HTML データとして利用可能にする必要があります。そこで、トランスフォーマープラグインの gatsby-transformer-remark
を追加します。トランスフォーマープラグインは「トランスフォーマー(transformer)」とあるように、あるデータを別のデータに変換するためのプラグインです。gatsby-transformer-remark
は Markdown ファイルをパースし、HTML データに変換します。
$ yarn add gatsby-transformer-remark
gatsby-transformer-remark
をインストールしたら、gatsby-config.js
に gatsby-transformer-remark
を追記します。
追記したら、開発サーバを再起動してください。
gatsby-transformer-remark
によって、allMarkdownRemark
や MarkdownRemark
といったフィールドがクエリで利用可能になります。GraphiQL で以下のクエリを実行すると、Markdown ファイル内で指定した title
slug
date
に加えて、本文の HTML データを取得することができます。
query MyQuery {
allMarkdownRemark {
edges {
node {
frontmatter {
title
date
slug
}
html
}
}
}
}
このデータを使ってページの作成を行っていきましょう。
一覧ページの作成
Gatsby では、src/pages
に追加したコンポーネントファイルがそのままルーティングとなります。そのため、src/pages/
に hoge.js
があれば、/hoge
というページが生成されます。
今回はブログサイトを作るため、トップページを一覧ページとしましょう。src/pages/
の index.js
がトップページに該当します。index.js
を以下のように変更してください。
export const query = graphql
ではページのクエリを定義しています。allMarkdownRemark
はすべての Markdown ファイルを取得するためのフィールドです。ここでは allMarkdownRemark
の構造に従い、4つのフィールド title
date
slug
excerpt
の値を取得するクエリを定義しています(allMarkdownRemark
の構造は GraphiQL のエクスプローラで確認可能です)。
また、フィールドによっては引数を渡すことができます。ここでは date
に formatString
を引数として渡し、日付のフォーマット方法を指定しています。
そして、export const 任意の変数名 = graphql``
の形でクエリを囲うことで、Gatsby がページのクエリとして認識し、その実行結果をそのページのコンポーネント(ここでは IndexPage
)に渡します。
IndexPage
コンポーネントでは data
を props として受け取り、それを元に一覧ページを作成しています。
これで一覧ページが作成できました。
一覧ページの並び替え
一覧ページを見てみると、並び順が日付順になっていないようです。一覧のソートを行うため、date
と同じように、allMarkdownRemark
に引数を指定します。
allMarkdownRemark
では sort
を引数として指定可能です。引数の情報は GraphiQL で確認することができます。GraphiQL のエディタ上のフィールド名を Ctrl を押した状態でクリックします。すると、クエリの実行結果の右隣に allMarkdownRemark
の情報が表示され、ARGUMENTS(引数) に filter
limit
skip
sort
があるのがわかります。
ARGUMENTS の sort: MarkdownRemarkSortInput
の MarkdownRemarkSortInput
は sort
の型を表しています。MarkdownRemarkSortInput
をクリックすると、MarkdownRemarkSortInput
の情報が表示され、fields
と order
を持つことがわかります。
また、fields: [MarkdownRemarkFieldsEnum]
の MarkdownRemarkFieldsEnum
をクリックすると、fields
に指定可能な値がわかります。このサンプルコードでは id
frontmatter___title
frontmatter___date
frontmatter___slug
を指定可能です。
ここでは fields
に [frontmatter___date]
を、order
に DESC
を指定し、date
の降順で表示するようにしました。
詳細ページの作成
次は詳細ページを作っていきましょう。一覧ページの作成では、トップページを一覧ページとするため、src/pages/index.js
を編集しました。詳細ページの場合は記事によって URL が変わるため、src/pages/
内の単一ファイルでページを作成することができません。詳細ページを動的に生成するためには、ページの雛形となるテンプレートを作成し、gatsby-node.js
にページの生成ロジックを記述します。
テンプレートの作成
まず、データを注入する元となるテンプレートを作成します。src
上で templates
ディレクトリを作成し、post.js
を追加します。
src/pages/index.js
では allMarkdownRemark
を使いましたが、今回は markdownRemark
を使っています。allMarkdownRemark
がすべての Markdown ファイルを取得するためのフィールドであるのに対し、markdownRemark
は単独の Markdown ファイルを取得するためのフィールドです。
src/pages/index.js
の allMarkdownRemark
では sort
を引数として渡しましたが、markdownRemark
では frontmatter
を引数として渡しています。frontmatter
では取得する記事の条件を指定でき、ここでは frontmatter
の slug
が $slug
と等しい記事を指定しています。そして、2つのフィールド html
と title
の値を取得しています。
※markdownRemark
の引数の情報は一覧ページの並び替えと同様に GraphiQL で確認可能です。
※$slug
と query($slug: String!)
については後述します。
ページの生成ロジックを作成
ページの動的生成を行うには Gatsby Node API を使用する必要があります。Gatsby Node API が利用可能となるのが gatsby-node.js
というファイル内です。そこで、gatsby-node.js
にページの生成ロジックを記述します。
gatsby-node.js
を以下のように書き換えてください。
gatsby-node.js
では exports.API名 = gatsbyNodeHelpers => {}
の形で API を使用します。API は第一引数に gatsbyNodeHelpers
を受け取ります。gatsbyNodeHelpers
はヘルパーオブジェクトで、Gatsby Node API で共通です(一部 API 特有のフィールドもあります)。ここでは gatsbyNodeHelpers
の graphql
と actions
を使用しています。
actions
は関数の集まりで、その中の createPage
を用いてページを動的に生成することができます。なお、Gatsby では状態管理のために内部で Redux を使っており、actions
の持つ各関数は Redux の bindActionCreators
でバインドされた action creators と同等です。
const result = await graphql(
では allMarkdownRemark
を使い、各記事の slug
を取得するクエリを定義しています。取得結果をループで回しているのが result.data.allMarkdownRemark...
の箇所です。ループごとに createPage
を呼び出し、ページを生成します。
createPage
には path
component
context
を持つオブジェクトを渡しています。path
はその記事のパス、component
はテンプレートの作成で作成したテンプレートを指定しています。context
に渡すデータはページクエリ内で GraphQL の変数として使用することができます。ここでは slug
を渡しており、それが src/templates/post.js
の query($slug: String!) {
の部分です。String!
の部分は変数 $slug
の型が文字列型で null
を許容しないことを意味します。
gatsby-node.js
を書き換えたら開発サーバを再起動してください。/post1
や /post2
にアクセスすると、詳細ページが表示されます。
ブログサイトをプリレンダリングする
一通りブログサイトの実装が終わりました。Jamstack 構成ではプリレンダリングした静的ファイルをデプロイするため、試しに静的ファイルを出力してみましょう。yarn build
を行うと、public
ディレクトリに静的ファイルが出力されます。
$ yarn build
yarn serve
を実行すると、出力した静的ファイルをローカルで実行することができます。
$ yarn serve
Netlify にデプロイする
作成したブログサイトを Netlify にデプロイします。Netlify のアカウントを作成するか、ログインを行ってください。Netlify のデプロイはサインアップ・ログイン後の画面の「New site from Git」から行います。
「New site from Git」をクリックしたら、リポジトリの選択を行います。リポジトリがホスティングされているサービスを「GitHub」「GitLab」「Bitbucket」のいずれかから選択します。サンプルコードは GitHub のため、GitHub を選択します。
リポジトリの一覧が表示されるため、デプロイを行うリポジトリを選択してください。
リポジトリを選択したら、デプロイの設定を行います。「Branch to deploy」ではデプロイしたいブランチ名を選択します。master
以外を指定することも可能です。「Basic build settings」は初期設定のままで問題ありません。設定を確認したら、「Deploy site」をクリックします。
「Deploy site」をクリックすると、デプロイしたサイトの詳細ページに遷移します。黄色の文字で「Site deploy in progress」と表示されている場合はデプロイ中です。デプロイが終わると緑色の文字でサイトの URL が表示されます。サイトの URL は自動的に割り当てられます。
サイトの詳細ページでは「Site settings」の「Change site name」からサイトの URL を変更したり、「Domain settings」からカスタムドメインの設定を行ったりなど、様々な操作、設定を行うことが可能です。ここではサイトの URL を mokajima-jamstack-demo.netlify.com に変更してみました。
また、デプロイの設定の「Branch to deploy」ではデプロイしたいブランチ名を選択しましたが、このブランチに新しいコミットをプッシュすると、Netlify がそれを検知して自動でビルド、デプロイを行ってくれます。デプロイの履歴は管理され、クリックひとつで前のデプロイの状態に戻す、といったことも可能です。
なお、ブログサイトをプリレンダリングするで出力した public
ディレクトリを「Want to deploy a new site without connecting to Git?」と書かれたエリアにドラッグ&ドロップし、デプロイすることも可能ですが、この場合は Netlify の自動ビルド、デプロイが行われません。
これでデプロイは完了です。
最後に
今回はデータソースとして Markdown ファイルを扱いましたが、Gatsby では WordPress の REST API や Contentful、microCMS のような Headless CMS など、様々なデータソースを扱うことができます。また、Jamstack は Gatsby に限定されないため、要件に応じて任意の静的サイトジェネレータを使うことが可能です。
この記事ではご紹介しませんでしたが、外部 API を利用することで Jamstack 構成のサイトに検索機能や決済機能などの機能を盛り込む、といったことも可能です。
フロントエンドの技術で行える Jamstack 構成の開発をぜひ試してみてください。
参考
Jamstack
Gatsby
Netlify
フロントエンドエンジニア積極採用中
株式会社トゥーアールでは現在フロントエンドエンジニア積極的に採用中です!
興味がある人は採用ページをチェック!!