Edited at

WordpressからHugo+AWS Amplifyに移行した


背景と全般


きっかけ

ながらくさくらのレンタルサーバ スタンダードでWordpressを動かしていたのだけど、めちゃくちゃ古いphp 5.2.17をWordpressがサポートしなくなってエラーがでるようになってしまった。さくらのレンサバはコンパネでphpのバージョンを上げられるのでそれをすればWordpressは引き続き使えるのだが、せっかくなので何か新しいことをしてみたい、と思いいろいろ調べていたところ、どうやら "静的サイトジェネレータ(Static Site Generator, SSG)" なるものがあるらしい、ということで、かっこよさそうなのでやってみた、というなりゆき。

だから目標としては、Wordpressでやっている個人ブログが概ね再現できること、になった。結果を先に言うと、まあまあ成功と言っていいんじゃないかと。移行前がここ http://mkiuchi.org/diary/ で、移行先がここ https://blog.mkiuchi.org/

結果としては非常に満足度が高かったのと、世の中にあるHugoの情報が自分のやったことと少し違っていた(たぶんバージョンの違いでやりかたに違いが出るのか?)ので、記事として残しておく。

相変わらず自分のやったことのメモとして書いているので、他のHugo記事を見ている人からすると内容の重複とかあるので、そこは勘弁してほしい。


とりあえず成果だけ見たいor使いたい

できたものはこれ https://blog.mkiuchi.org

再利用できるものはこちら https://github.com/mkiuchi/hugo-twentysixteen に切り出してます。


そもそも静的サイトジェネレータってどういう風に使うの

登場人物をまとめてみた。

まずサイトを作成する時は、SSGのお作法に従ってページを記述する。どのフレームワークでもページそのものはMarkdownで書けるが、周辺の様々なテンプレートや拡張機能を操作する時はフレームワーク固有、言語固有の知識が必要になる。Hugoをはじめほとんどの静的サイトジェネレータにはプレビュー機能が入っていて、編集内容はリアルタイムでブラウザで確認することができる。

できあがったものをGithubなどのリポジトリに上げる。このリポジトリはプライベートリポジトリでもよい。リポジトリにコミットできるわけなので、別に複数で編集しても構わない。特定ページの編集ロック、不可視、予約投稿などのWordpressの機能は構造上ないので、Wordpressの機能に依存したサイトに対してSSGを使用するのは不向きかもしれない。このあたりは Awesome Hugo(https://github.com/budparr/awesome-hugo)とか見ると解決できるかもしれない。

リポジトリの準備ができたら、ホスティングプロバイダーからリポジトリに対して連携の設定をする。今回私が選んだのは AWS Amplify だけど、Netlify(https://www.netlify.com/)や、Google Firebase(https://firebase.google.com/?hl=ja)でも同様のことができるようだ。プロバイダーが行うことは以下のようなこと。


  • プロバイダーは定期的にリポジトリを監視し、変更があれば自動的に内部のビルド環境にコードをpullし、静的ファイルをコンパイルする。

  • コンパイルされたファイルは所定のエンドポイント(ホスト名)で公開される。デフォルトではプロバイダーが勝手につけたエンドポイントになるが、自分のドメイン内のホスト名を使用することもできる。このホストは仮想マシンのような実体ではないようだ。AWS Amplify の場合はこの部分がサーバレスCDN(AWS Cloudfront)で行われているらしい。多分他のサービスも似た感じだと思う。AWS Amplify の場合はリポジトリのブランチ毎に公開ポイントを変えることもできる。ロードバランス(カナリアリリース)まではできないみたいだけど。たぶん仕組み的にはできなくはなさそう、という感じ。

  • (自分が希望すれば、)プロバイダは公開するときにSSL化もやってくれる。AWS Amplifyの場合はDNSの設定こそ若干手動で行う部分があるが、証明書の取得からCDN内へのホスト名の伝播まで勝手にやってくれて至れり尽くせり。

  • 上記の工程は概ね自動化されていて、簡便に設定できる。AWS Amplify の場合この工程は自動化されていて、最初の設定もマウスをポチポチやってるだけで終わってしまう。

公開されたら、公開されたエンドポイントを閲覧者がアクセスして、ページを見ることができる、という塩梅。


どの静的サイトジェネレータがいいの

https://yoshinorin.net/2018/10/18/world-of-ssg2/ とか見て、jekyllは古そうだしRubyだしパス、Hexo, Gatsby は特に悪い評価は見受けれれなかった。特にGatsbyはアツいらしいのだが、Javascriptで何か作ってGitHubに上げるとvulnerabilityの警告が死ぬほど来てげんなりするのでパス。で、私はHugoを選んだ。Go はこれから頑張りたい系のやつだと思ったので。

ただ以下に書くけどテーマがあまりいけてなかったり、ちょっとした追加機能(例えばスライドショーとか)を追加するのに結構戸惑ったので、比較的クセが強いのかもしれない。Hexo, Gatsby などであればその辺は楽勝なのかも。やってないのでわからない。

あと今のところ Hugo 使ってみて感じたことは、意図通りに動かない時のデバッグがやりづらいなとは思った。例えば range で展開しようとした時にどんなデータが入っているのかとか、そういうのがまだよくわかってない。Javascriptだとそのへん console.log とか入れればなんとなく見えたりするので Hugo はちょっとしんどい。なんかいいものがあったら教えてください。


Hugo

ここから Hugo のことを書く。Howto的なものは他の記事にいろいろ書かれているのでそちらをざっと読んでおいていただけると。


テーマに頼らない(というか、あまり信用できないかも)

Hugoにはテーマをプラグインできる機能があって、テーマギャラリー(https://themes.gohugo.io/)でいろいろ見ることができるが、Wordpress的なものをイメージしてサクっと使おうとすると意図通り動かなかったりして結構ストレスがある。

私の場合テーマに頼らずテンプレートを作ることで割と意図通りの動きをさせることができた。以下に私がやったことの要点をいくつか書いておく。


テンプレートを活用してURLによって内容を出し分ける

hugo new site XXX で作成されるテンプレートや、他のページで見かけるテンプレートは少し公式の用法とは異なっているようにも見えたので、自分なりに理解したテンプレートの関係性を図示してみた。

まずあるURL / でアクセスした場合、Homepage Template が呼び出される。ただし、Base Template が定義されている場合、Homepage Templateは実際には Base Template内の {{ block "main" }} 部分に展開される。

同様にURL /archives/yyyy のURLでアクセスした場合、(事前にarchivesがtaxonomyとして定義されている場合は)所定の Taxonomy Template が呼び出される。同様に Base Template が定義されている場合、Taxonomy Templateは実際には Base Template内の {{ block "main" }} 部分に展開される。

実際に私が Homepage Template(=layouts/index.html)と、Taxonomy Template(=layouts/archives/list.html)で定義した内容を見てみる。


layouts/index.html

{{ define "main" }}

{{ $paginator := .Paginate (where .Data.Pages "Type" "posts") }}
{{ range $paginator.Pages }}
{{ .Render "list" }}
{{ end }}
{{ end }}


layouts/archives/list.html

{{ define "main" }}

<h1>Archive: {{ .Title }}</h1>
{{ range (where .Data.Pages "Type" "posts") }}
{{ .Render "list" }}
{{ end }}
{{ end }}

ほぼ同じ内容であることがわかる。じゃあなんで Taxonomy Template にはそれだけで絞り込まれた内容にしかなっていないかというと、記事を作成した時に Front matter を指定しているから。以下は記事の Front matter の抜粋。


content/posts/1111.md

---

title: "iphone用に動画をffmpegでエンコードする"
date: 2008-12-17T23:17:12+0900
archives: ["2008", "2008/12"] <-- ここで絞り込みを指定している
draft: false
categories: ["Linux", "オプソ", "雑記"]
tags: ["Linux", "オプソ", "雑記"]
author: "mkiuchi"
---
以下本文・・・

この辺の関係性が見えてくると、わりと自分でいい感じに組めてくると思う。


年毎、月毎のアーカイブを作る

ぐぐるといろいろ情報が出て来る。今のところの私の中での結論は「wordpressでいうところのアーカイブを、記事のpublish datetimeだけを頼りに動的に作ることはできない」となっている。じゃあどうするかというと、Taxonomy を定義するしかない。

仕方ないね。

下の方法はアーカイブ用の投稿をつくらないといけないので、ちょっと私の好みには合わないなと思った。


月毎、カテゴリ毎の記事件数を表示する

以下のように、サイト内のページ一覧を .GroupByParamDate して、"年/月" のキーを作ってカウントしている。このコードはビルド時に実行されるので、エンドユーザが見るページにはコンパイル後の静的な値しか入っていない、ということになる。


layouts/_default/baseof.html(抜粋)

<section class="widget widget_archive">

<h2 class="widget-title">アーカイブ</h2>
<ul>
{{ $burl := .Site.BaseURL }}
{{ range (where .Site.RegularPages "Type" "posts").GroupByParamDate "date" "2006/01" }}
{{ $key := .Key }}
{{ $count := len .Pages }}
<li><a href="/archives/{{ $key }}/">{{ $key }}</a>({{ $count }})</li>
{{ end }}
</ul>
</section>

カテゴリも似たような感じに。このへんはわりと試行錯誤した感じ。この時は切実にデバッガ欲しかった・・・。


layouts/_default/baseof.html(抜粋)

<section class="widget widget_categories">

<h2 class="widget-title">カテゴリー</h2>
<ul>
{{ $burl := .Site.BaseURL }}
{{ range $term, $tax := (where .Site.Taxonomies.categories "Term" "!=" "") }}
{{ $count := .Count }}
<li class="cat-item"><a href="/categories/{{ $term }}/">{{ $term }}</a>({{ $count }})</li>
{{ end }}
</ul>
</section>


shortcodeを活用する(組み込み)

コードをいい感じに出したい時は Hugo にデフォルトで組み込まれている Highlight shortcode を使うといい感じになると思う。Wordpressからの移行でこの部分の量が多いと書き換えがしんどい。


contents/posts/111.md(抜粋)

{{< highlight Bash "linenos=table" >}}

systemctl enable bluetooth.service
systemctl start bluetooth.service
{{< /highlight >}}

上のように書くと、下の画像のような感じになる。

Youtubeの場合は以下のようにする。


contents/posts/111.md(抜粋)

{{< youtube _4dDDU_BQNU >}}



AWS Amplify

ここから AWS Amplify について書く。といっても AWS Amplify Console だけ。


設定

Hugo で作ったものを Github に push したら、AWS Amplify の設定をする。AWS Management Consoleに入って、AWS Amplifyを選ぶ。私は東京リージョンを使用した。

[アプリの作成]を選ぶ。

連携するリポジトリを選択する。私の場合は GitHub

連携が初めての場合はここでGithub側から、Amplifyとの連携を認めるかどうか聞かれるのでOKする。連携したらデプロイするリポジトリとブランチを選ぶ。

Amplify側が勝手にHugoのリポジトリであることを認識してくれて、いい感じのビルド設定を提案してくれる。素晴らしいな!!そのまま次へ。

最後に設定の確認をしてデプロイ開始。

デプロイ中は状況を逐次出力してくれる。基本的にはほかっておけばいい。私の場合は初回10分弱、2回目以降は5分程度でデプロイが完了している。最後に各デバイス(iPad, iPhoneなど)の出力サムネイルまで表示してくれる。至れり尽くせりだ。

正直 Amplify の部分はあまり難しいところはない。雰囲気でポチポチやってるだけでなんとなくできてしまう。


コスト的なところ

今回さくらからの移行を見据えてやってみたが、コストはまだ長期間動かしていないのでよくわからない。とはいうものの、Amplifyはビルドの合計分数とストレージ量にしか課金されないので、たぶんそんなにかからないし、さくらとドッコイドッコイなのではないかなとは思っている。

以上です。参考になれば。