Gatsbyによるブログ構築
この記事では、本ブログをWordPressからGatsbyに移行しましたので、理由と手順をまとめています。 なお、この記事公開時点で、本ブログは、Gatsby+Netlifyの組み合わせで公開されています。
本ブログは自宅サーバ上に立てたWordPressで、markdown記法の記事を公開していましたが、常々記事を「githubで管理」&「よりシームレスに公開・管理」と思っていました。
そこで、本記事では、以下の目次の流れでブログを構築していきます。 なお、記事量が多くなってしまったため、別記事として切り出している箇所もあります。
サービス・技術選定
まず、以下の理由を解消するためのサービス・技術を選定します。
- 現在の自分の運用では、markdownで書いた記事をWordPressで公開する際に投稿欄に貼り付ける必要があるので、面倒。
- 記事を書いているコマンドラインからプレビュー画面への出力がダイレクトにできれば良いので、ローカルで開発環境をたてられる静的サイトジェネレータ(Static Site Generator、以下SSG)を使えば、できそう。
- WordPressのプレビュー画面から正確な記事デザインが見えるので、記事公開直前にWordPressと手元のMarkdownファイルをいったりきたり。
- 1つ目と同様にSSGで解消できそう。
- どんな更新をしたのか差分が分かりづらい(たまにWordPress上での自分の誤操作で文章がおかしくなってた…)。
- Githubで管理すれば、差分が確認できるし、切り戻しも簡単。
- WordPressのプラグインは凄く便利だけど、プラグイン更新がちょっと大変。
- 動的サイトより静的サイトのほうがセキ ュリティリスクが低いので、頻繁なプラグイン更新を気にしなくても良いかも。なら、静的サイトが作れるSSGだな。
- masterリポジトリにpushしたら、ブログを自動更新したい。
- Github Actionsを使えば、BuildとDeployができそう。
- なにやらSSGっておもしろそう。
- うん、SGGやってみよう。
ちょっとSSGありきな感じがしますが、使うサービス・技術としては、SSGとGithub(+ Actions)が良さそうです。
また、デプロイ先としては、自宅サーバ上のNginxか静的コンテンツのホスティングサービスの2つの選択があります。 Github ActionsからDeployをするつもりなので、自宅サーバへDeployする場合は、sshで外部からアクセスできるようにしなければなりません。 心情的にVPNを通さない自宅サーバへのsshアクセスを許可したくなかったので、今回はホスティングサービスを利用することにしました(ホスティングサービスを使ってみたかったというのもあります)。
つまり、SSGとGithub(+ Actions)とホスティングサービスの構成になりました。
SSGの選定
SSGとは
SSGの詳細については、具体的に解説されているサイトが多いので、そちらをご参照いただければと思います。
SSGとは、簡単にいうと静的サイトを生成するためのソフトウェアです。 SSGでは、生成(ビルド)時に全てのHTMLを最初に生成し、生成されたファイルをホスティングサービスやWebサーバ上で公開します。 WordPressは、動的サイトといってアクセスがあった際にDBのデータを元にサーバでHTMLを生成して返します。 一般的なSSGのメリット・デリットには以下があります。
-
SSGのメリット
- 動的サイトに比べ、セキュリティのメンテナンスコストが低い
- 事前にHTMLを生成しているので、動的サイトと比較してレスポンスが高速
- DB等がないため、バックアップが容易(Githubで管理ができる)
-
SSGのデメリット
- ページ数が多いと、生成に時間がかかる
- SSG単体では動的な機能(コメント機能やアクセス数管理)が利用できない
- API等で外部から情報を取得している場合は、生成したタイミングのデータで固定される
- プログラミング知識が必要(私はむしろうれしい…)
つまり、私のようなアウトプットを目的とした個人ブログならば、動的サイトでなくとも静的サイトでほぼ問題がありません。
SSGの選定
SSGには、Nuxt(JavaScript/Vue)、Next(JavaScript/React)、Gatsby(JavaScript/React)、Hugo(Go)など多数存在しています。
私は、JavaScriptとGraphQLをちゃんと使ってみたかったので、Gatsbyを選択しました。
ホスティングサービスの選定
SSGで生成したhtmlを公開するためには、ホスティング先が必要です。 Gatsbyのドキュメントを見ると、対応しているホスティングサービスが大量にあります。
今回は、GatsbyとGithubの連携記事も多く、私のブログだと無料枠で収まりそうなNetlifyを選択しました。
Gatsbyでのブログ構築準備
Starterの選択
Gatsbyでは、最初に構築する際にテンプレート(Starter)を選択して構築する仕組みになっています。 色々なテンプレートが公式やコミュニティで公開されていますので、その中から自分が作りたいブログに近いStarterを選択するとすぐにブログが公開できます。
私はなるべく自分でブログ自体を構築したかったので、公式のgatsby-starter-blogを選択しました。 gatsby-starter-blogのリンク先をみてもらうと分かるとおりシンプルな一覧ページと記事で構成されたstarterです。カスタマイズのしがいがありそうです。
Nodejsのインストール
gatsbyをローカル環境で動かすためには、Node.jsが必要になります。 Node.jsのインストールについてはOSごとで異なり、複雑なので、今回は割愛します(いつか記事にしたい)。
とりあえず、nodebrewを使って安定バージョンであるNode.js v14.15.5をインストールしています。
Gatsby CLIのインストール
Gatsbyのコマンドを実行するために、ターミナル上で以下のコマンドを実行します。
npm install -g gatsby-cli
ターミナルを再起動して、以下のコマンドが正常に実行できたら、インストール成功です。
gatsby --help
初回構築
以下のコマンドでgatsby-starter-blogをもとにブログを初期構築します。
gatsby new mako-note https://github.com/gatsbyjs/gatsby-starter-blog
mako-noteはディレクトリ名なので、任意の名前にしてください。
https://github.com/gatsbyjs/gatsby-starter-blog
がStarterのURLです。
生成されたディレクトリに移動して、develop(開発モード)でブログを起動します。
cd mako-note
gatsby develop
これで、http://localhost:8000 にブログが以下のように構築されました。
Gatsbyで実現したい機能
とりあえず、WordPressで気にいっていた機能をなるべくGatsbyでも実現したいです。 この初期状態から追加したい機能をリストアップすると以下になります。 大量にありますね… 全部をこの記事に載せると大変なので、手順が多いものは別記事として紹介します。
- PostCSSとSCSSの有効化
- Header・Footer・SideBarの追加
- 本文の目次の追加
- 記事の更新日時をgithubでの更新日時に変更
- paginationの追加
- categoryページ・tagページの追加
- 関連記事ぺージの追加
- 日付のフォーマットを日本用に変更
- Shareボタンの追加
- コメント機能の追加
- Sidebarのコンテンツ拡充
- 検索バーの追加
- 人気記事リストの追加
- twitterタイムライン追加
- カテゴリ一覧の追加
- タグクラウドの追加
- 最新記事一覧の追加
- 追従する目次の追加
- お問い合わせページ・プロフィールページの追加
- プラグイン対応
- gatsby-plugin-sitemap
- gatsby-plugin-robots-txt
- gatsby-remark-external-links
- gatsby-remark-line-breaks
- Google AnalyticsとGoogle Searchコンソールへの登録
- デザインの修正
- レスポンシブル対応
- Google AdSenseの登録
では、一つずつやっていきましょう。
PostCSSとSCSSの有効化
PostCSS
PosCSSは、生成されたCSSをJavaScriptのプラグインで変換することができるツールです。
PostCSSのプラグインは色々あるのですが私は以下を使っています。
- autoprefixer:ベンダープレフィック スを自動で付与するプラグイン
- postcss-pxtorem px表記をrem表記に変換するプラグイン
以下のコマンドでプラグインをインストールします。 なお、Gatsbyのプラグインをインストールする場合は、コマンドを作業ディレクトリ(ローカルリポジトリ)内で実行してください。
npm install --save-dev autoprefixer postcss-pxtorem
リポジトリ直下に以下のpostcss-config.jsを作成します。 このpostcss-config.jsでプラグインのロードとプラグインごとの設定をしています。
'use strict'
const pxtorem = require('postcss-pxtorem')
const autoprefixer = require('autoprefixer')
module.exports = [
pxtorem({
rootValue: 16,
unitPrecision: 5,
propList: [
'font',
'font-size',
'height',
'line-height',
'letter-spacing',
'margin',
'margin-top',
'margin-left',
'margin-bottom',
'margin-right',
'padding',
'padding-top',
'padding-left',
'padding-bottom',
'padding-right',
'border-radius',
'width',
'max-width'
],
selectorBlackList: [],
replace: true,
mediaQuery: false,
minPixelValue: 0
}),
autoprefixer()
]
gatsby-config.jsの先頭付近に以下を追記してpostcss-config.jsを読み込みます。
const postCssPlugins = require('./postcss-config.js')
読み込んだPostCSSは後述のSCSSのプラグインと組み合せて有効化します。
SCSS
スタイルシートをCSSからSCSSに変更します。 SCSSはCSSを拡張しており、入れ子構造や変数利用等、格段にスタイルシートの記述が楽になります。 今まで使ったことがないという方はぜひ調べてみてください。その便利さの虜になると思います。
GatsbyでSCSSを有効化するには、gatsby-plugin-sassプラグインを使います。 また、このプラグインは、CSS Moduleにも対応していますので、SCSS とCSS Moduleを組み合せてスタイルシートを記述します。
以下のコマンドでgatsby-plugin-sassをインストールします。
npm install sass gatsby-plugin-sass
次にgatsby-config.jsに以下を追記してプラグインを有効化します。 5行目で先ほどのPostCssPluginsを読み込んでいます。
plugins: [
{
resolve: 'gatsby-plugin-sass',
options: {
postCssPlugins: [...postCssPlugins],
cssLoaderOptions: {
camelCase: false
}
}
}
]
ついでにnormalize-scssもインストールしておきます。
npm i normalize-scss
normalize-scssは、適宜、以下のようにbaseとなるscssファイルで読み込んでおきます。
@import 'normalize-scss';
Header・Footer・SideBarの追加
ボリューム多いので、別記事として、また書きます。
本文の目次の追加
ボリューム多いので、別記事として、また書きます。
記事の更新日時をgithubでの更新日時に変更
ボリューム多いので、別記事として、また書きます。
paginationの追加
ボリューム多いので、別記事として、また書きます。
categoryページ・tagページの追加
ボリューム多いので、別記事として、また書きます。
関連記事ぺージの追加
ボリューム多いので、別記事として、また書きます。
日付のフォーマットを日本用に変更
ボリューム多いので、別記事として、また書きます。
Shareボタンの追加
ボリューム多いので、別記事として、また書きます。
コメント機能の追加
ボリューム多いので、別記事として、また書きます。
Sidebarのコンテンツ拡充
ボリューム多いので、別記事として、また書きます。
お問い合わせページ・プロフィールページの追加
ボリューム多いので、別記事として、また書きます。
プラグイン対応
便利なGatsybyプラグインを導入します。
gatsby-plugin-sitemap
gatsby-plugin-sitemapは、サイトマップを生成してくれるプラグインです。
プラグインのインストールは以下の通りです。
npm install gatsby-plugin-sitemap
プラグインの読み込みは以下の通りです。
siteMetadata: {
siteUrl: `https://www.example.com`,
},
plugins: [
{
resolve: `gatsby-plugin-sitemap`,
options: {
exclude: [`/page/*`, `/tag/*`],
},
},
]
gatsby-config.jsのSiteMetadata.SiteUrlが必要となりますので、SiteMetadata.SiteUrlの情報が無い場合はgatsby-config.jsに追記します。 また、excludeオプションで任意のページをサイトマップから除外できます(上記設定では、page配下とtag配下を除外しています)。
gatsby-plugin-robots-txt
gatsby-plugin-robots-txtは、robots.txtを生成してくれるプラグインです。
プラグインのインストールは以下の通りです。
npm install gatsby-plugin-robots-txt
プラグインの読み込みは以下の通りです。
siteMetadata: {
siteUrl: `https://www.example.com`,
},
plugins: [`gatsby-plugin-robots-txt`]
gatsby-plugin-sitemapと同様にgatsby-config.jsのSiteMetadata.SiteUrlが必要となりますので、SiteMetadata.SiteUrlの情報が無い場合はgatsby-config.jsに追記します。
gatsby-remark-external-links
gatsby-remark-external-linksは、外部リンクを別タブで開くようにしてくれるプラグインです。
プラグインのインストールは以下の通りです。
npm install gatsby-remark-external-links
プラグインの読み込みは以下の通りです。
plugins: [
{
resolve: 'gatsby-remark-external-links',
options: {
target: '_blank',
rel: 'noopener noreferrer',
},
},
]
gatsby-remark-line-breaks
gatsby-remark-line-breaksは、以下のようにMarkdown上で改行されていると、<br>
タグを挿入してくれます。
今日は良い天気だ。
明日も良い天気だろう。
テレビで野球の結果を見てしまった。
明日はリアルタイムで見よう。
<p>今日は良い天気だ。<br>
明日も良い天気だろう</p>
<p>テレビで野球の結果を見てしまった。<br>
明日はリアルタイムで見よう。</p>
上記のhtmlはブラウザで以下のように表示されます。
今日は良い天気だ。
明日も良い天気だろう
テレビで野球の結果を見てしまった。
明日はリアルタイムで見よう。
markdownで書いたものがそのまま反映されているように見えますね。
私はmarkdownでの空白の改行を<p>
タグ(段落)、普通の改行を<br>
タグ(改行)というふうに段落と改行の違いを表しています。
プラグインのインストールは以下の通りです。
npm install gatsby-remark-line-breaks
プラグインの読み込みは以下の通りです。
gatsby-transformer-remark
プラグインのオプションとして読み込みます。
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
`gatsby-remark-line-breaks`
]
},
},
]
Google AnalyticsとGoogle Searchコンソールへの登録
Google Analyticsの登録
gatsby-plugin-google-gtagプラグインを使用します。
プラグインのインストールは以下の通りです。 私の環境では、Gatsbyのバージョンが2系のため、2.8.0のバージョンを指定しています。
npm install gatsby-plugin-google-gtag@2.8.0
プラグインの読み込みは以下の通りです。
plugins: [
{
resolve: "gatsby-plugin-google-gtag",
options: {
trackingIds: ["UA-XXXXXXXX-X"],
pluginConfig: {
head: true,
},
},
},
]
すでにWordPressでGoogle Analyticsを利用しているので、5行目でそのtrackingIDをtrackingIdsを指定して、7行目でhead
内に記述されるようにしています。
Google Searchコンソールへの登録
すでにWordPressでサイトマップを登録しています。サイトマップのURLは同じなので、特に対応は不要ですが、移行完了に念のためサイトマップを登録しなおしました。
デザインの修正
SCSSを修正して、好きなデザインに修正します。 SCSSとCSS Moduleの組み合わせなので、スタイルシートは書きやすかったですが、時間が一番かかったかも。まだPCでの表示のみの対応です。
レスポンシブル対応
とりあえず、CSS Gridを使って1024px未満と以上で少し変えています。 このブログのアクセスはPCからが多いので、とりあえずは問題ないかなと思います。
Google AdSenseの登録
ボリューム多いので、別記事として、また書きます。
NetlifyでのBuildとDeploy
ここまでで、ローカルの開発環境でとりあえず満足がいくブログが作成できましたので、公開していきます。 今回はDeploy先の静的ホスティングサービスとして、Netlifyを利用します。
アカウント作成
Netlifyのアカウントを作成します。 その際に、GithubやGitbucket等と連携してアカウントを作成できます。
余談になりますが、私はアカウント作成時にあまりサービス間で連携させたくない(主となったサービスが終了したときにどうなるか予測がつかない&登録メールアドレスをサイト別にわけている)ので、メールアドレスでの新規登録を好んでやっています(ログイン情報等は、別途パスワード管理ツールで管理しています)。
ブログのDeploy
以下の手順でブログのDeployを進めていきます。
- Netlifyにログイン後、
New site from Git
を押下 - Continuous Deploymentで、
GitHub
を選択 - Github上のブログのリポジトリを選択
- 以下の通り設定をして
Deploy site
を押下
項目 | 設定値 | 備考 |
---|---|---|
Owner | default値 | 変更なし |
Branch to deploy | main | default branchをmainにしているため |
Build command | gatsby build | gatsbyのbuildコマンド |
Publish deirectory | public | 公開ディレクトリ |
デプロイが完了すると、Netlifyから割当てられたドメインでブログが公開されていますので、確認します。 すでにssl化までしてくれ ていますね。素晴らしい!
ブログドメインの変更
今回はWordPressからの移行ですので、すでにブログ用のドメイン(mako-note.com)をxdomainでもっています。
Netlifyのcustom domainにブログ用ドメインを登録して、NetlifyのDNSサーバをxdomainに登録して完了です。 ただし、今回は移行のため、反映に数時間から72時間程度かかります。
また、このままではNetlifyからデフォルトで付与されたサブドメインからもアクセスできてしまいます。 SEO上の観点から良くないかと思いましたが、 Improved SEO with canonical link headersによると、Netlify側でcanonicalリンクを付与しているとのことですので、特に対応は不要そうです。
もし、サブドメイン自体へのアクセスを拒否したいのならば、static/_redirects
に以下のように記載すればリダイレクトの設定ができますが、デバッグ用にサブドメインへのアクセスは残しても良いと思います。
# These rules will change if you change your site’s custom domains or HTTPS settings
# Redirect default Netlify subdomain to primary domain
https://xxxxxxx.netlify.app/* https://mako-note.com/:splat 301!
上記のファイルでは、https://xxxxxxx.netlify.app
からhttps://mako-note.com
へリダイレクトしています。
Github ActionでのBuildとDeploy
Netlifyでの公開時点で、mainブランチにpushすると、自動でブログ更新ができるようになりました。 このままでは、Github Actionsの出番はありません。Github Actions使ってみたい…
ところで、Netlifyの無料プランは、Build時間の制限が300分/月となっており、それを超過すると自動で追加料金が発生してしまうようです。300分なので、毎日Buildしても10分の猶予があります。
このブログの記事量でのbuild時間は3分程度です。今後の更 新頻度を考えても問題ないような気がします。 しかし、私はサイドバーの人気記事一覧を毎日更新(build)したいのです(SSGのためbuildしたタイミングの人気記事が反映されるため)。
となると、300分はで心許無いです。そこで、Github Actionsの登場です。 Github ActionsでBuildを実行します。 プライベートリポジトリでのGithub Actionsの無料枠は2000分/月となっており、超過した時点でワークフローが実行されなくなるので、追加料金も発生しません。
流れとしては、以下の通りになります。
- ローカルで記事を更新
- mainブランチにpush
- Github ActionsでBuild & NetlifyへDeploy
Github Actionsのワークフロー作成
リポジトリ配下に/.github/workflows/build.ymlを以下のように作成します。
name: Build Gatsby and deploy to Netlify
on:
push:
branches: [main] # main branchにpushされた時に実行
shedule:
- cron: '0 20 * * *' # UTC20:00(JST05:00)時に実行
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2.1.5
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
env:
CLIENT_EMAIL: ${{ secrets.CLIENT_EMAIL }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
- name: Publish
run: npx netlify-cli deploy --dir=public --prod
env:
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
5行目のpush時にBuildするbranches
はmain
としています。
また、7行目で、前日までのアクセスログから人気記事一覧を作成するために5:00に自動的にBuildをするようにしています。
18行目で、git cloneのfetch-depth
を0に指定しています。default値だと1となり、gitのauthor dateが正しく取得できず、記事の更新日時がおかしくなってしまいます。
24、25行目のCLIENT_EMAIL
とPRIVATE_KEY
はBuild時にGoogle Analyticsへアクセスするための情報です(Google Analyticsの情報を元に人気記事一覧を作成しています)。
こちらは、人気記事一覧の作成時に取得しているので、そちらを参照ください。
31、32行目のNETLIFY_SITE_ID
とNETLIFY_AUTH_TOKEN
はNetlifyにDeployするために必要となります。以下のリンクに取得方法が記載されています。
NETLIFY_SITE_ID
: Link with an environment variableNETLIFY_AUTH_TOKEN
: Obtain a token in the Netlify UI
24、25、31、32行目の値は機密性の高い情報ですので、ワークフローにべた書きせずに、リポジトリの「Setting」→「Secrets」に登録して参照するようにしています。
終わりに
やっとブログの移行が完了しました。 夜にちまちまやっていたので、移行のために三ヶ月くらいかかりました。 (移行中にGatsbyが2系から3系にあがってしまったことが悲しみです。そのうち3系に移行しないと…)
今までWordPressやそのテーマにまかせていた部分、Javascript、React、GraphQLの理解がかなり深まりました(といってもプラグインも色々活用させていただきました)。 Starterに存在していたファイルにはすべて手を入れたので、全体像がかなり把握できて大満足です。
まだまだ直したい・良くしたいところがいっぱいあるので、これからもこのブログを記事だけでなくコードの観点からも育てていきたいと思います。
ここまで読んでいただき、ありがとうございました。 少しでもどなたかの参考になれば嬉しいです。