Hugoは静的サイトジェネレータの中でもだいぶ柔軟性のあるツールだと思います。
ただ、その分気をつけなければいけないことがあったり、実現する方法が分かりづらかったりすることが多いので、 そういった点をまとめてみます。
まずはテーマを作ります。 この章では、テーマを作るための環境の作り方を解説します。
HugoにはHugoBasicExampleという、サンプルの記事や基本的な機能を使ったテスト用レポジトリが用意されています。
spf13/HugoBasicExample: Example site to use with Hugo & Hugo Themes
Hugoのテーマづくりは、このレポジトリのcloneから始まります。
次にテーマの雛形を作ります。 Hugoにはテーマの雛形を作り上げるコマンドがあります。
1hugo new theme [name]
hugo newコマンドは、新しくサイトを作るときやページを作るときにも使われます。
とにかく、何か新しいものを作るときに使われるコマンドで、テーマを作るときもこれを使います。
cloneしたHugoBasicExampleのルートディレクトリでコマンドを実行すれば、./themes/XXXXに雛形が作られます。
後述するthemes.gohugo.ioに載せてもらうために必要なファイルも揃っているので、0からファイルを作るよりこのコマンドを使うのが賢明だと思います。
Hugoのページ構造はだいたい次の通りです。
で、hugo newで作られるテーマファイルの構成は次の通りです。
1. 2├── LICENSE.md 3├── archetypes 4│ └── default.md 5├── layouts 6│ ├── 404.html 7│ ├── _default 8│ │ ├── list.html 9│ │ └── single.html 10│ ├── index.html 11│ └── partials 12│ ├── footer.html 13│ └── header.html 14├── static 15│ ├── css 16│ └── js 17└── theme.toml
実は、この雛形には足りないものや要らないものもあります。 それはおいおい自分の好きなように足したり消したりすれば大丈夫です。
テンプレートファイルと対象ページの紐付けは、実は少しややこしいです。
なぜかというと、Hugoは対象のテンプレートを特定の順番で走査する仕組みになっていて、 ページごとに細かくデザインを変えたり、全体で1つのテンプレートに統一したりと、融通が効くようになっています。
listページを例に具体的な構造を示すとこうなります。
1/layouts/section/SECTION.html 2/layouts/_default/section.html 3/layouts/_default/list.html 4/themes/THEME/layouts/section/SECTION.html 5/themes/THEME/layouts/_default/section.html 6/themes/THEME/layouts/_default/list.html
上から順に、最初に見つかったテンプレートを採用します。
つまり、最終的に/themes/THEME/layouts/_default/list.htmlまですべて見つからなければ、何も描画されません。
Hugoの最も便利な仕組みの1つとして、テンプレートファイルは./themesとルート直下のものでそれぞれ用意できるような仕様があります。
つまり、themesにおいたテーマファイルをユーザが独自にオーバーライドできるようになっています。
先の例にあげたlistで言えば、/layoutsと/themesで同じファイルを走査しているのがわかります。
1/layouts/section/SECTION.html 2/layouts/_default/section.html 3/layouts/_default/list.html 4/themes/THEME/layouts/section/SECTION.html 5/themes/THEME/layouts/_default/section.html 6/themes/THEME/layouts/_default/list.html
例えば、ユーザがあなたのテーマを使ってくれたとします。
そのまま使えばあなたがデザインしたとおりに描画されますが、対象のテンプレートファイルと同じ名前をルートディレクトリに配置することで、 そのファイルだけを独自に変更することができます。
ここで大事なのは、これはテンプレートファイルに限った話ではなく、CSSや画像などの静的ファイルにも同じことが言えるということです。
これをうまく利用することで、ユーザが豊富なバリエーションで使うことができるテーマを作ることができます。
ここまでで、Hugoのテーマづくりにおける基礎的な解説はできたと思います。
しかし、実際に手をつけるとなるとどこから着手していいかわからなくなると思います。 というわけで、自分がテーマを作るときの作業順序をまとめてみます。
Hugoは./layouts/index.htmlがなければ、./layouts/_default/list.htmlが採用されます。
自分は複雑な構造にするのが嫌なので、まず./layouts/index.htmlを消してしまいます。
トップとそれ以外の記事一覧で表示を変えたい場合は、if文と.IsHomeでなんとかします。
トップと一覧が大幅に乖離する場合は、ちゃんと分けたほうが良いです。
後述するblock templatesを使うため、baseof.htmlを作ります。
ここでHTMLに必要な<!DOCTYPE html>やmetaタグの配置、ヘッダとフッタのマークアップとデザインをします。
次にlist.htmlを作ります。
前述したとおり、Hugoは./layouts/index.htmlがなければ、./layouts/_default/list.htmlが採用されます。
このタイミングで、トップページのマークアップとデザインを終わらせます。
Hugoは断片的なパーツ、例えば一覧表示用の記事など、使い回しをする素材を切り出すことを推奨しています。
これはPageが持つ.Renderを使って実現します。
Hugo - Hugo Template Functions
./layouts/_default/list.htmlには最新記事の一覧を表示する場合がほとんどであるため、
./layouts/_default/list.htmlで作った記事1つ1つをli.htmlに切り出します。
次に記事詳細を作ってしまいます。 これはここまでで説明したものとなんら変わりないので、特筆なしです。
次にtermsのページを作ります。 このページは質素になりがちなので、デザインが難しいです。
忘れがちなのが404.htmlです。
ちゃんと作っておかないと空白のページが作られます。
ここまでで基本的なテーマを作れるまでの説明をしました。 しかし、これだけだときっとハマるであろう落とし穴がいくつかあります。
画像や静的資材の参照には相対パスを使ってはいけません。これはHTML上にあらわれるあらゆるファイルすべてに言えます。
ユーザはドメインのルートであなたのテーマを使うとは限りません。 例えばthemes.gohugo.ioがいい例です。
各テーマのデモはサブディレクトリで構成されます。 つまり、相対パスを使ってしまうと参照が壊れてデザインが崩れます。
{{ .Site.BaseURL}}を使って絶対参照で構築するべきです。
よくあるのが、Taxonomyに使われる値をべた書きしてしまうものです。
categoriesやtagsなど。
これをマジックナンバーで書いてしまうと、ユーザが独自にTaxonomyを定義できません。
Hugoは.Site.Taxonomiesで定義されたTaxonomyをすべて取得できるので、できるだけ柔軟に使えるようにしましょう。
Hugo側でcategoriesとtagsはデファクトのようなスタンスを取っているので、それを理解した上でべた書きするのはありだと思います。
サイトを作る上で、誰もが使いたいであろう機能があります。 そういった機能はできるだけつけたほうが良いです。
代表的なものがGoogleAnalyticsです。
Hugoはconfig.tomlにGoogleAnalyticsのUserAgentを記述できるようになっています。
1googleAnalytics = "UA-123-45"
この値が設定されていればGoogleAnalyticsのタグを配置するべきですし、 設定されていないなら出すべきではありません。
そういったときにはwithが便利に働きます。
Conditionals | Hugo - Go Template Primer
GoogleAnalyticsのタグは_internal/google_analytics.htmlという内部テンプレートが用意されています。
自分で書くよりもこれを呼び出してしまえば、値の設定、未設定の判定もやってくれます。
静的サイトのコメント機能でもっとも有名なDisqusです。 これもGoogleAnalyticsと同様、変数名が決まっています。
1disqusShortname = "XYW"
DisqusもGoogleAnalytics同様、内部テンプレートが用意されているので、それを呼び出すのが良いです。
HugoはHugoのコミュニティを成長させるために、metaタグにgeneratorを明記することを推奨しています。
1<meta name="generator" content="Hugo 0.17-DEV" />
generatorは{{ .Hugo.Generator }}でタグとともに出力されます。
ユーザに影響をあたえるものではありませんが、Hugoの発展のためにできるかぎり入れてあげたいところです。
generator-meta-tag | Hugo - Creating a Theme
シェアボタンも、基本的にはどのサイトにも必要になります。 これは国によって使われるサービスやSNSが異なるため、可変にできるとなお良いです。
また、シェア自体いらないという場合もあるため、config.tomlで表示、非表示が切り替えられたり、
記事単位に.Paramsで切り替えられたりすると良いと思います。
ここまでで、必要最低限なものが揃ったテーマを作るための説明はできたと思います。 次は少し発展させて、ユーザが柔軟にテーマを使うための機能を作ります。
だいたいのWebサイトには、メニューが配置されます。 HugoにはMenusという機能があり、これを使うこともできます。
ただ、実際にこれを使ってMenuを形成している人は少なそうな印象です。 そのため、config.tomlなどで設定できるようにしているテーマが多く見られます。
自分がもっとも適切と思える形で実装し、READMEで設定の仕方を説明すると良いです。
Wordpressやその他のブログシステムにはShortcodesというとても便利な機能があります。
もちろんHugoにもありますので、基本的なものはテーマ側で用意しておくと良いです。
これはマークダウン内で定型的なHTMLを差し込むことができるものです。 例えば、画像やiframe、Twitterの埋め込みなどは、毎回HTMLを書くよりも手軽に呼び出せるようにしたかったりします。
テーマが用意するShortcodesとしては、画像の埋め込みと右寄せ、左寄せくらいを提供できると良いです。 機能を作ったら、README.mdに使い方を書いておきます。
ユーザが独自に、デザイン的なオーバーライドをしたい場合があります。
styles.css1つ用意しておけば、ユーザがまるまるHugoのルートディレクトリにコピーしてオーバーライドすることもできますが、
全体をコピーしないといけなくなります。
そういったときのため、custom.cssという空っぽのスタイルシートを用意して読み込ませておくと良いです。 ユーザは必要な場合のみcustom.cssを作ればいいですし、そうでないなら空っぽのまま使われるだけです。
テーマのバージョンアップをしたときも、影響を少なくすることができます。
Hugoは全世界のあらゆる国で使われています。 テーマもできるだけ、特定の国に依存しないようにします。
まず言えるのが、日付の形式です。
日本は2016/01/01といった形式ですが、世界では違います。
これはできるだけ、柔軟に変えられると良いです。
例えば、config.tomlに次のように設定できるようにします。
1[params] 2 dateformat = "Jan 2, 2006" # Optional
テンプレートファイルでは次のように描画します。
1{{ .Lastmod.Format ( .Site.Params.dateformat | default "Jan 2, 2006") }}
英語圏ではHelveticaやArialなどでいいフォントも、国によってはそうとも言えません。
これもDateFormatと同じように、config.tomlなどで設定できると良いです。 custom.cssを用意する方法でも良いですが、フォントだけのためにファイルを作らせるよりは、設定で変えられると親切だと思います。
ここでは、テーマを作る上でのさらに発展的なノウハウについてまとめます。
すでに登場しましたが、Hugoはblock templatesという機能が使えます。
これはベースとなるテンプレートと子となるテンプレートを用意できる機能で、 HTMLの共通的な部分をベーステンプレートに切り出すことができます。
しかし、このHugoの機能には現在バグがあり、時折Golangのエラーメッセージを吐いてクラッシュします。
1fatal error: concurrent map read and map write
この記事を書いている今も、かなりの回数クラッシュしています。
おそらく記事生成をgoroutineで回していて、その中でmapへの不適切なアクセスが走っているのだと思います。 そのうち直ると思いますが、気になる方はblock templates自体を使わないほうが良いです。
Concurrent map read and write error in template handling · Issue #2224 · spf13/hugo
Issueもあがっていますが、再現できていないようです。
AMP対応は制約がいくつか付くだけなので、そこまで難しい実装ではありません。
おそらく一番困るのがスタイルシートの導入だと思います。
自分は./layouts/partials/styles.cssにスタイルを配置して、次のようにしてインラインCSSとして描画しています。
1<style amp-custom> 2 {{ replaceRE " +" " " (replaceRE "\n" "" (partial "styles.css" .)) | safeCSS }} 3</style>
テーマを作ったら、Hugoのテーマポータルであるthemes.gohugo.ioに載せてもらうための手順を進めます。
まず、theme.tomlを書く必要があります。
これはhugo newで雛形が作られているので、それにそって書けば大丈夫です。
基本的な説明は、Hugoのテーマ用レポジトリのREADMEにあります。
spf13/hugoThemes: All Themes Hugo
themes.gohugo.ioに表示されるサムネイルが2つの異なるサイズで必要になります。
Thumbnail should be 900×600 in pixels
Screenshot should be 1500×1000 in pixels
Media must be located in:
[ThemeDir]/images/screenshot.png
[ThemeDir]/images/tn.png
一番映えるページでスクリーンショットを撮り、配置します。
README.mdはユーザにもっとも近いドキュメントになります。 ここにはできるかぎり親切な情報を載せたほうが良いです。
例えば次のようなものです。
必要であれば、画像も使って説明をします。
ここまでできたら、自分のテーマレポジトリをHugoのテーマ用レポジトリにIssueとして連絡すれば大丈夫です。
spf13/hugoThemes: All Themes Hugo
コントリビューターの方が確認して、修正すべきポイントがあればIssueをあげてくれますし、 問題なければ取り込んでCloseしてくれます。