Hugoでの記事ファイルの配置と画像管理
Hugoでの記事ファイルの配置と記事に貼り付ける画像の管理方法について書きます。 この記事を含めて、やってみて分かった的な Hugo 関連の内容をしばらく続けます。
公式サイトではおそらく推奨されないようなやり方も含んでいますので、あくまで参考程度で。
Hugo での content 配下のファイル配置
Hugo の記事ファイルは(設定で変更できますが)デフォルトでは/content
以下に置きます。ちなみにこうしたファイルパスの説明で/
はプロジェクト(サイト)のルートを表します。
content 配下には普通、記事全体をあらわす一つの_index.md
を置き、これがレイアウトファイル側の/layouts/index.html
と結びつき、URL的にはサイトルートを表すトップページです。
content 配下に何らかのフォルダを作ると自動的にセクションとして扱われ、そこにまた_index.md
を置けば、レイアウト側の/layouts/_default/list.html
などと結びついて、それがそのセクションのリストページになります。例えば/content/post/_index.md
を置けば、post
セクションの最上位ページになります。セクションの名前は自動的にフォルダ名、つまりこの場合だと「post」になりますが、/content/post/_index.md
のフロントマターで
title: "記事"
などとすれば、セクションの表示名を「記事」にできます。つまり_index.md
にtitle
プロパティを設定することでトップページやセクションリストページのタイトルを好きなように変更できるわけです。もちろんレイアウトファイル側で.Page.Title
といったページ変数を上手く使う必要はありますが、テンプレートの話は他サイトを見て下さい。
このcontent 配下の_index.md
や記事ファイルと layouts 配下のレイアウトファイルを、Hugoがどういう順序で探してどう結びつけるかは公式サイトに優先順位の説明があります。
このレイアウトファイル検索順序をふまえた上で、最低限こんなレイアウトファイルを用意すればサイトが表示されるという話は、ここで以前に書きました。
詳しい話は省略しますが、公式サイトや日本語の解説サイトを見て下さい。ちなみに私が Hugo でサイト構築する上で、公式サイト以外で一番参考にさせていただいているのはこのサイトです。たぶん一番わかりやすい。
Page Bundle
Hugoには、content DIR配下に記事ファイルを作っていく上での一定のルールというか指針のようなものがあって、これをページバンドル (Page Bundle) と呼んでいます。
Page Bundle には ブランチ(Branch Bundle) と リーフ(Leaf Bundle) の 2種類あって、Branch は「枝」、Leaf は「葉」と言う意味ですよね。アンダーバーがファイル名の先頭に付く_index.md
を置いたDIRは Branch Bundle 、アンダーバーが付かないindex.md
を置いたDIRは Leaf Bundle となります。
セクションページの配置方法はすでに説明したとおりですが、個別の記事ファイルはこのセクションフォルダ配下に何らかの記事専用フォルダを作って、そこにindex.md
を置いて記事とします。いきなり適当な名前のマークダウン、例えば/content/post/post01.md
とかを置いても、Page Bundleルール上では、あくまで所属セクションの_index.md
の付加ファイル(リソース)であって、厳密な意味では個別記事ファイルでは無いことになります。
この場合post01
をフォルダ名とし、/content/post/post01/index.md
を作る必要があります。また記事の作成日時などを正しく記して Hugo が認識できるファイルにするためには、手動で作らず、コマンドラインからhugo new ファイルパス
とするほうがベストなようです。
hugo new post/post01/index.md
これ馴れてこないと面倒ですが、このやり方が確実です。で結局 Page Bundle のルールについてあまり詳しく知らなくても、
- ブランチは、content 配下の
_index.md
が置かれたセクションを表すフォルダ(とその同階層ファイル、配下の個別記事フォルダやサブセクションを含む) - リーフは、個別記事を表すセクションフォルダ配下の
index.md
が置かれた記事フォルダ(とその同階層ファイル)
という理解でとりあえず使えます。逆に言えば content 配下にフォルダを作っても、その直下に_index.md
を置くかindex.md
を置くかで役割りが違ってくるということです。
ちなみに今使ってるHugoのバージョン(hugo v0.81.0-59D15C97+extended linux/amd64)では、content 配下にフォルダを作っても、そこに_index.md
もindex.md
も置かなければ、セクションとしても記事としても認識されずただのフォルダです(内部的にはセクションなのかもしれませんが)。
例えばサイドバーでセクション階層のリストアップをしていても出てこない。
だから私の場合/content/documents
とか/content/documents/videos
とか作って、他の記事から参照する資料フォルダにするような使い方をしています。これは/documents/videos/xxxx.mp4
といったURLで個別記事やリストからアクセスできます。
セクションや個別記事のそばに置いたファイル
では_index.md
やindex.md
以外の、それらのファイルと同階層に置いたファイルはどう扱われるのでしょうか?
- まずブランチから見ると、その内部のフォルダは個別記事やサブセクションのために作るものなので、リソースファイル用のサブディレクトリを持つことができません。だからセクションの
_index.md
から参照するリソースファイルは同じ階層に置く必要がある。 - またリーフはシングルページ用の
index.md
を置く場所なので、「葉=末端」という解釈であり、その中にサブセクションやサブ記事フォルダを置くとかはできません。ただ逆に、ブランチと違ってリソースファイル用のサブディレクトリを持つことができます。リーフのリソースはその配下の全てのファイルです。
例えば/content/post/post01/index.md
と同じ階層にimg
というフォルダを作り画像を置けば、そのindex.md
からimg/xxxx.jpg
などといった相対パスでアクセスできます。あまり深い階層はおすすめできませんが、ルール上どこまで深くてもindex.md
と同階層直下なら一応リソースファイルとして扱われるそうなので、やったことは無いですが、/content/post/post01/img/001/001-01.png
とかでもいけるんだと思います。
このリソースファイルというのはブランチでもリーフでも同様に、画像以外 Hugo が読み込み可能な全てのファイルで、PDFや動画などもその階層のindex.md
からなら参照できます。
ただ、いろんな解説記事には別のマークダウンファイルですらリソースになると書いてあったりしますが、実際やってみるとあまり上手くいきません(HTMLとして書き出されない、何かやり方あるのかな〜? テストはしていませんが、たぶん対応するレイアウトファイルが必要なのでしょう)。
記事ファイル配置のサンプル(やや変則技)
以下は実際使っている Hugo で作ったサイトの/content
配下のDIR構成の一部です。
ターミナルのtree
コマンドで 7階層下まで表示させた例です。
$ tree -L 7 content content ├── _index.md (1) ├── post-01.md (2) ├── trv │ ├── _index.md (3) │ └── ovs │ ├── _index.md (4) │ ├── fr │ │ ├── 01 (5) │ │ │ ├── img (6) │ │ │ │ └── duck.jpg │ │ │ └── ref-01 (7) │ │ │ ├── img │ │ │ │ ├── ref-01-IMG.png │ │ │ ├── index.md │ │ │ ├── ref-02.md (8) │ │ └── _index.md (9)
コンテンツルート
(1)の_index.md
がトップページにアクセスする場合のindex.html
になります。ローカルサーバだとhttp://localhost:1313/
で表示されるページ。
コンテンツルート直下のマークダウンファイル
(2)はコンテンツDIR直下のマークダウンファイルですが、これはトップページのリソースになります。実際はレイアウトファイルを適切に処理すれば、/post-01/index.html
が書き出されhttp://localhost:1313/post-01/
でアクセスできます。フロントマターのurl
属性で例えばurl: /post-01.html
などとすれば、hugo
コマンドでビルドした場合でも、フォルダを作らずに(/post-01/index.html
を書き出さずに)ルート直下に/post-01.html
で書き出され、http://localhost:1313/post-01.html
でアクセスできます。
実はこのフロントマターのurl
属性を使って個別のファイルの書き出しをコントロールする知識が役立ちます。またこのようにhugo
コマンドでビルドしてみるのが、Hugo のサイト構築の仕方を理解する早道で、いろんな事が分かりました。このことは後でも述べます。
セクションDIR
この例では、コンテンツDIR直下にはtrv
(「旅行」のつもり)というセクションがあり、その中にovs
(「overseas」=「海外旅行」のつもり)というサブセクション、さらにその下にfr
(「フランス」のつもり)というサブセクションがあり、それぞれに_index.md
を持っています。(3)(4)(9)
個別ファイル
(7)のref-01
は個別記事のフォルダです。だからindex.md
を持っています。
やや変則技な配置
ここまでは一見 Page Bundles のルールどおりなのですが、あれ?っと思った方は鋭い。上記のDIR構成を見て変だと思ったでしょう。
(7)のref-01
フォルダは、ルールどおりだと本来/content/trv/ovs/fr/
の直下にあるべきですが、ここではさらにfr
の下に01
フォルダを作ってその中にあります。
01
フォルダには_index.md
は存在せず、従ってこれはセクションフォルダでは無いのでこの配置は Page Bundles のルールからは違反です。- またこの
01
フォルダのなかに直にref-02.md
という記事ファイルがあります。これはfr
の直下に置くかref-02/index.md
として置くべきなので、これも変則です。
実際はhugo
コマンドでビルドしてみると分かるのですが、これでもやり方しだいで成り立ちます。(英文を全部読んだわけでは無いので自身はありませんが)公式サイトには書いていないと思われるので、変則技と思っています。良い子はマネしないで下さいw
フロントマターのurl
属性を活用する
この変則技を成り立たせるコツが、フロントマターのurl
属性を使いこなすことです。とにかくhugo
コマンドでビルドしてみてわかってきます。これは個別ファイルとその個別ファイルに貼る画像ファイルの管理にも関わることです。
画像ファイルの管理
最初 Hugo では画像ファイルはプロジェクトルートの/static
以下に置くルールが推奨だったそうです。/static/img/
などといったDIRを作り、そこに画像ファイルを置くと、個別記事などから/img/xxxx.png
などとサイトルートから始まる短いURLでアクセスできる。これはこれで楽ですし、サイト全体で使う画像などはこのやり方が理にかなっています。
しかし個々の記事にしか使わない画像までこの配置にしていると、場合によっては膨大な画像ファイルの数を/static/img/
などにぶっこんでしまうので管理が大変です。そういう問題もあって Page Bundles のルールができて、セクション階層/個別記事フォルダ/index.md
の直下にリソースを置くことが推奨され管理しやすくなったわけです。
ただそれ以外の方法だとなぜダメなのでしょうか?
リソースの書き出され方を見てみる
そもそも Page Bundles のルールではどうして個別記事名.md
というファイルを作って、同階層にimg/xxxx.png
といった配置で画像を置くのではなく、個別記事フォルダ/index.md
として、その配下にリソースを置くのでしょうか?
個別記事フォルダ/index.md
の形にこだわって開発されているのはURLを綺麗にしたい(/aaa/bbb/xxxx.html
というHTMLファイル名むき出しのパスがイヤ)というのは当然あるでしょう。実際 Hugo じゃなくても JavaScript系のフレームワークでも、今は何らかのフォルダを作って中にindex.html
を置くやり方が主流ですね。
ただ、ユーザから見ると、個人が作るブログのようなサイトで、何がなんでも拡張子.html
を見せたくないってほどのこだわりは無いとおもいます。このへんは個人の好みの問題にもなってきますが。
そんな REST命的な理想は置いておいてテクニカル的な面だけみると、hugo
コマンドでビルドしてみることで実際の理由が分かります。例えば/post/ref-01.md
というファイルを作って、同階層にimg/xxxx.png
といった配置で画像を置くと、書き出されるのは(意地でも!)/post/ref-01/index.html
になり、同階層に置いたimg/xxxx.png
は/post/img/xxxx.png
に書き出される。
つまり/post/ref-01/index.html
から見ると、一つ上のDIRに画像フォルダが動いてしまう。
これだと個別記事内で相対リンクでimg/xxxx.png
としてもリンクが外れてしまいます。だからPage Bundles のルールを守ってねということになります。
uglyurls
config.toml
でuglyurls=true
にすることで、強制的に/post/ref-01.md
を/post/ref-01/index.html
にしないという方法もあり、そちらがいいという方もいるようですが、記事の書き出し方法全てに影響するので、私は使っていません。これも若干好みの問題です。
ただuglyurls=true
は非推奨な扱いなので、なにか理由があるのかもしれません。知らんけどw
フロントマターのurl
属性でビルドをコントロール
実は上記(7)ref-01/
配下のindex.md
には、フロントマターのurl
属性でパーマリンクが指定してあります。
--- url: trv/ovs/fr/01/ref-01/ ---
これはあってもなくても良いような気がするんですが、パスに01
という、セクションでも無いただの分類用フォルダがあっても問題なく出力できています(この点はたぶんurl
属性が無くてもそうなる)。セクションではない01
の配下ではありますが、形はリーフのルールなので記事内でimg/ref-01-IMG.png
に普通にアクセスできています。
また(8)のref-02.md
のurl
属性はこうなっています。
--- url: trv/ovs/fr/01/ref-02.html ---
こうしておくことで/trv/ovs/fr/01/ref-02/index.html
として書き出されず指定したURLどおりになるので、/trv/ovs/fr/01/img/duck.jpg
といった同階層の画像フォルダにもアクセスできています。
ここで表面上 Page Bundles のルールに従ったref-01/index.md
と、ルールからはみ出したref-02.html
を、セクションでもない共通フォルダ01
配下に置いたことが特徴です。
本来/content/trv/ovs/fr/
の直下に置くべきですし、直下に置いた別のファイルも使えるのですが、あえて分類用の01
フォルダにそれらをまとめても、個別記事のフロントマターでurl
属性の値(パス)さえ適切に設定しておけば問題ないことがわかりました。
例えばあるセクションの配下の記事数が50とか100とかに増えても管理しやすく、また作りたくない深い階層のセクションフォルダを作って管理する必要もない。
これはどういう目的のサイトにするかにもよるので、ある種のムダ知識ですが、例えば大量のブックマークを記事化したサイトなどだと使える発見と思います。