Hugoの多言語機能で日本語ブログに英語版を別URLで公開した
で英語版を/en/配下に公開したあと、メイン以外のブランチをCloudflare PagesのPreviewに出そうとしたら、立て続けに2件のトラブルに遭遇した。
メイン(本番)は問題なく成功していたので、最初は原因が見当も付かなかった。
- Previewのビルドが
permalink ill-formedで失敗する - デプロイ後、メニューの「English」をクリックすると404になる
どちらもCloudflare PagesがProductionとPreviewで環境変数を別管理していることが根っこにあった。1つずつ潰していく。
1. Previewがデプロイできなかった
症状
メイン以外のブランチをプッシュすると、Cloudflareのビルドが次のエラーで失敗した。
Error: error building site: failed to create resource spec: error expanding "/:contentbasename/": permalink ill-formed
Failed: build command exited with code: 1メイン(本番)は成功する。
原因
hugo.tomlのパーマリンクは/:contentbasename/にしている。このトークンはHugo 0.144.0で追加されたもので、それより古いHugoは未知のトークンとみなし、permalink ill-formedになる。
| デプロイ | 使う環境変数 | Hugo | 結果 |
|---|---|---|---|
| メイン | ProductionのHUGO_VERSION | 0.164.0(0.144以上) | 成功 |
| 他ブランチ | PreviewのHUGO_VERSION | 未設定、または0.130.0など古い値 | permalink ill-formed |
このブログをNetlifyから移行した当初はHUGO_VERSION=0.130.0だった。その後テーマ更新で:filenameを:contentbasenameに置き換え、本番だけ新しいHugoに上げていた。Preview側がそれに追従せず、古いままだった。
対策
Cloudflareダッシュボード→Pagesプロジェクト→Settings → Environment variablesで、PreviewにもProductionと同じHUGO_VERSION(0.144以上。本番と同じ0.164.0が安全)を入れる。
確認は失敗ログ先頭のInstalling Hugo 0.xx.xを見ればよい。0.144未満ならこの原因で確定してよい。
この対策でPreviewビルドは成功した。
2. デプロイ後に英語版が切り替わらなかった
症状
Previewサイトのメニューに「English」は出る。クリックすると404になる。ローカルのhugo serverでは問題が再現しなかった。
原因
英語ページ自体はPreview上に存在していた。リンク先が違っていた。
言語スイッチャーは.Permalink(絶対URL)を使う。
<a class="nav-link" href="https://scribble.washo3.com/en/" lang="en" hreflang="en">English</a>日本語メニューはrelLangURLなので/aboutのような相対パスになり、Preview域内に留まる。Englishだけhugo.tomlのbaseurl(https://scribble.washo3.com/)向きの絶対URLになっていた。
実際の遷移先はhttps://scribble.washo3.com/en/。本番mainにはまだ/en/が無かったため404になる。
https://<hash>.<project>.pages.dev/en/ -> 200
https://scribble.washo3.com/en/ -> 404原因の一歩手前は、環境変数CF_PAGES_URLを本番ドメインに手動で上書きしていたことだった。Cloudflareはデプロイごとに正しいPreview URLを自動注入するが、ダッシュボードの値が優先される。ビルドコマンドでhugo -b $CF_PAGES_URLとしていても、その上書きがそのままbaseURLになってしまう。
ローカルで問題が再現しなかったのは、hugo serverがbaseURLをlocalhostにするためだった。
対処
- Previewの環境変数からCF_PAGES_URLの手動設定を外す
- ビルドでは
$CF_PAGES_URLを素直に使う(Cloudflare注入値をそのまま使う)
この対処でEnglishがPreview内の/en/に向くようになり、404は解消した。
今すぐ見るだけなら、Preview URLの後ろに/en/を直接付けても確認できる。
3. 最終的なビルド構成
環境変数
| 変数 | Production | Preview | 備考 |
|---|---|---|---|
| HUGO_VERSION | 0.164.0(本番と同じ) | 0.164.0(本番と同じ) | 両方必須。0.144未満だと:contentbasenameが死ぬ |
| CF_PAGES_URL | 手動設定しない | 手動設定しない | Cloudflareがデプロイ URLを自動注入する |
Build command
これまでのgit fetch --unshallow && hugo --gc --minify -b $CF_PAGES_URLでも、lastmodとPreviewの英語切替は動く。ただし次の2点が残っていた。
git fetch --unshallowは、既にfull cloneだと失敗し&&でHugoまで届かない- 本番の
$CF_PAGES_URLはカスタムドメインではなく*.pages.devなので、sitemapやhreflangがpages.dev指しになる
そこで、ダッシュボードのBuild command欄には次の1行を入れることにした。
if [ "$(git rev-parse --is-shallow-repository)" = "true" ]; then git fetch --unshallow; fi && if [ "$CF_PAGES_BRANCH" = "main" ]; then hugo --gc --minify; else hugo --gc --minify -b "$CF_PAGES_URL"; fi- 浅いcloneのときだけunshallowする(
enableGitInfoのlastmod用) - mainは
hugo.tomlのbaseurl = https://scribble.washo3.com/をそのまま使う - その他のブランチはCloudflare注入の
$CF_PAGES_URLを使う
Build command欄は1本のシェルコマンドとして実行されるので、複数行のままは貼れない。;でつなぐか、リポジトリにbuild.shを置いて欄にはbash build.shと書く方法もある。
#!/bin/bash
if [ "$(git rev-parse --is-shallow-repository)" = "true" ]; then
git fetch --unshallow
fi
if [ "$CF_PAGES_BRANCH" = "main" ]; then
hugo --gc --minify
else
hugo --gc --minify -b "$CF_PAGES_URL"
fi./build.shだと実行ビット不足で失敗することがあるので、bash build.shと書く方が無難らしい。
フラグの意味
| 要素 | 役割 |
|---|---|
git fetch --unshallow | CloudflareはShallow cloneでチェックアウトする。enableGitInfoのlastmodを正しくするには完全な履歴が必要 |
hugo --gc --minify | CIの定番。--enableGitInfoはtoml側にあるので付けなくてよい |
-b $CF_PAGES_URL | PreviewでのEnglishメニュー・hreflang用の絶対URL。本番では使わない |
まとめ
| 項目 | 内容 |
|---|---|
| 症状1 | Previewビルドがpermalink ill-formedで失敗 |
| 原因1 | PreviewのHUGO_VERSIONがProductionより古く、:contentbasenameトークン(Hugo 0.144〜)を解釈できない |
| 対策1 | PreviewのHUGO_VERSIONをProductionと同じ値に揃える |
| 症状2 | Preview上のEnglishリンクが本番ドメインへ飛び404 |
| 原因2 | CF_PAGES_URLを本番ドメインに手動上書きしていた |
| 対策2 | CF_PAGES_URLの手動設定を外し、Cloudflare注入値をそのまま使う |
どちらもProductionとPreviewの環境変数が別管理であることを忘れていたのが原因だった。
Cloudflare Pagesを多言語Hugoサイトで使う場合は、環境変数は両方の環境で揃っているか、逆に手を加えすぎていないかを最初に疑うとよさそうだ。
参考
- Use a specific Hugo version
- Build configuration / CF_PAGES_URL
- Set build commands per branch
- Hugo GitInfoとshallow clone
- Hugo permalinks / :contentbasename