Hugo + Netlify の静的ブログに Contentful で管理画面を取り付けた
背景
このブログ ezeroms.com は、昔ながらの静的サイトという形にこだわって作っている。ユーザーがサイトを閲覧するときに、サーバー側で動的なページ生成を行わず、ただそこに置いていた HTML ファイルをそのまま開くという仕組みだ。
このことにこだわっているのは、ローディングが阿部寛的に爆速であるとか、セキュリティリスクが抑えられるとか、それっぽい理由も挙げられるが、実際のところは僕のフェティッシュでしかない。
静的サイトにはロマンがある。そこには、昔ながらのインターネットの美しさがあり、僕はそれをいつまでも大事にしたいと思っているのだ。
僕が小学生の頃、同級生とホームページビルダーで HTML ファイルを量産していたように、初期のウェブ文化はすべて手書きの HTML から始まった。あの頃の僕らは font color="red" を駆使して世界を彩り、更新履歴を自分で書き足すことで統治を実現しようとしていた。しかし、日記のページが100日を超えたあたりで人類は悟る。この手作業では文明が維持できない、と。
こうして歴史は動き、WordPress のような CMS や、FC2ブログのような巨大プラットフォームが誕生する。いずれも、「書く」と「公開する」のあいだに横たわっていた苦行を取り除き、個人の創作エネルギーをもっと軽やかに解放するための、文明的な発明だったといえる。
僕が十代の頃、文明は一瞬にして発展を遂げていった。PHP が動き、データベースが喋り、SNS がリアルタイムでタイムラインを描き換えるようになり、ウェブは急激に賢く、忙しく、そして複雑になった。WordPress が世界の大半のサイトを支配し、開発者たちが Ruby on Rails や Django や Laravel を愛するようになった頃には、ページを動的に生成する方式が現代のウェブの標準的な作法として定着していった。
もちろん、これらの技術は素晴らしい。ユーザー認証もできるし、検索もできるし、記事の一覧も自動で並ぶ。巨大なサービスには動的サイトの柔軟さが不可欠だ。
ただ、僕はその進化の流れを横目に見ながら、いつも思っていた。大量の動的処理やデータベースが裏でうごめく現代のウェブは便利だけれど、僕は、「ただのテキストデータがそこにある」という素朴さが好きだったのだ。
だからこそ、自分のブログだけは原点の感触を残しておきたい。静的サイトにこだわる理由は、もはや文化保存に近い感情なのかもしれない。
では、僕が静的サイトにこだわりながら、一方で更新のしやすさという問題をどうやって解決しているのか。その答えが Hugo という静的サイトジェネレーターだ。
Hugo とは、Markdown で書いた記事を HTML に変換し、ファイル一式をまとめて静的なサイトとして出力してくれるビルドツールである。昔ながらのウェブを現代の道具で再生産するための仕組みであり、動的 CMS が支配する時代にも Movable Type がひそやかに守り続けてきた思想を継ぐ、静的サイト文明の末裔だ。
Hugo プロジェクトでは、ローカルで md ファイルを書いて GitHub に push すれば、あとは Netlify が自動的にビルドして公開してくれる。記事は Markdown として構造化されたまま Repository に保存されるため、利用者はコンテンツ管理を Git という形でおこなっていることになる。
当初、僕はその方法でサイトを更新していたが、次第に「ブラウザでサッと更新できる管理画面がほしい」と思うようになり、途中から NetlifyCMS(旧 DecapCMS)を導入して、ブラウザ上に簡易的な CMS を持たせる運用に切り替えた。
NetlifyCMS の仕組みはシンプルで、次のように動いている。
NetlifyCMS = 管理画面で記事を書く
NetlifyCMS が md ファイルを自動生成して GitHub に commit
Netlify がそれを検知して再ビルド
サイトが更新される
つまり、本質的には以前と同じ「md → GitHub → Netlify」の流れを維持したまま、編集体験だけをブラウザ側に持ってくるという設計だ。
ところが、ここで思わぬ落とし穴があった。
NetlifyCMS は、記事編集画面で日本語入力をしようとすると、カーソルが前後移動を繰り返して、まともに文章を入力することができなかったのだ。
この事実に気づいたのは、ひととおり実装が終わった後で、思わず膝から崩れ落ちてしまった。
そのときは「コミュニティでも報告されているし、そのうち直るだろう」と楽観していたのだが、待てど暮らせど一向に修正される気配がない。
この間、僕はずっとテキストエディタで文章を書き、NetlifyCMS にペーストして更新するという、なんともむなしい運用を続けていた。そうして一年半ほどが過ぎ、ようやく「これはもう自分で別の管理画面を用意するしかない」と重い腰を上げることにした。
作業内容
新たに管理画面として選んだのは Contentful。インターフェースが優れており、API 経由で静的サイトに記事を流し込むことができる。
静的サイトを愛する僕としては、できればより純朴な世界観を守りたかったのだが、NetlifyCMS が日本語入力で致命的な問題を抱えている以上、もはや他に選択肢がなかった。
これは理念を曲げたというより、「文明社会で生きるための最低限の妥協」といったほうが近い。完全であろうとする心は尊いが、人は完全ではない手段の中で生きていかなければならない。
旧構成
NetlifyCMS で Markdown を作成・編集
NetlifyCMS で Publish → GitHub に commit & push
Netlify が GitHub を監視しており、push をトリガーに build
Netlify のサーバー上で Hugo が走り content/ 以下の Markdown を読み取り、静的サイトを生成
Netlify が公開
新構成
Contentful の管理画面で記事を作成・編集
記事を Publish(Contentful が Webhook を発火)
Netlify が Webhook を受け取り、build を開始
build 前処理として Node スクリプトが実行され、Contentful から記事を取得して content/ 以下に
Markdown を自動生成
Netlify のサーバー上で Hugo が走り、Markdown を読み取って静的サイトを生成
Netlify が公開
これにより、日本語の記事作成ができない NetlifyCMS から脱却し、Contentful を使って快適な記事管理ができるようになった。
変更の影響と今後の展望
今回の構成変更によって、GitHub を経由しない更新ルートができたため、本番環境の内容と GitHub Repository にある内容が一致しなくなった。
考えようによっては、「アプリケーションは GitHub に置き、記事データは Contentful に置く」という、いわば「アプリとデータベースの分離」として割り切ることもできる。
ただ、僕としてはこれまで 「すべての記事が GitHub 上で完結している」という状態がとても気に入っていた。
ローカルに clone すれば記事の全履歴が残っているし、grep も diff も効く。静的サイトでありながら、ログやアーカイブを GitHub 上に持っているような感覚があった。その状態が損なわれるのは残念だ。もし誤って GitHub で編集してしまったときに先祖返りが発生する可能性もある。(まあ、そんな運用をするなという話ではあるけれど……。)
さて、この問題をきちんと解決するとしたら、GitHub Actions を使って Contentful → Markdown → GitHub の同期を自動化する、というやり方が考えられる。
GitHub Actions 上で Node.js を起動し、Contentful API から記事データを取得して content/ 以下に Markdown を生成し、最後に git commit & git push でリポジトリを更新する、という処理だ。
実行タイミングとしては、まずは手動トリガーや、daily or weekly の定期実行から始めるのが現実的だろう。もちろん、より丁寧にやるなら Contentful の更新を Webhook で検知し、それをきっかけに GitHub Actions を走らせるほうがスマートだろう。
でも、これはこれで、Contentful で Publish → Netlify が反応 → サイト更新、のすぐ後に、今度は GitHub Actions が Contentful を読みに行き、同じ内容を GitHub に push する……という二重更新が発生するので、だいぶキモいかんじもする。
このあたりはもう少し悩みつつ、近日中に GitHub Actions のプロトタイプを作ってみようと思う。



