Hugo + ox-hugo を使って最低限の手間でそれなりの見栄えの Web サイトを作成し,org ファイルに書き足すだけで 現実逃避 サイトの更新が捗るようにする.
動機
むかし,はてなダイアリーというサービスでしばらく現実逃避の履歴を書いていたが,だいぶ前にサービスが止まってしまった (サービスが止まる前に更新も止めてしまっていたけれど).当時のコンテンツは後継のはてなブログに移行されたのだが,元の入力ソース (はてな記法) のエクスポートがなぜかできない (Movable Type 形式に強制変換される) という謎仕様.無料ブログサービスなんていつサービス停止してもおかしくない中,ソースの保全がまともにできないサービスを使い続けるのはリスクが高い.
また,最近は GNU Emacs の org-mode が便利すぎて最近はほとんど org-mode
で文書作成をしている1ので,一つの org ファイルにちまちま書き足すだけで 現実逃避 サイトの更新が捗りそうな ox-hugo を使ってみることにした.
ただ,ox-hugo の公式ドキュメントは結構充実していると思うが,Hugo の概念を知らないとなかなか理解にしくい.それなりに試行錯誤をしたので備忘録として手順を残しておく.2
以下,試行錯誤の際に参考にさせていただいた日本語の ox-hugo に関する記事へのリンクを紹介する.
- Org-mode で記事を書いて Hugo 向け markdown を ox-hugo で自動生成する話
- ox-hugo の概要
- ox-Hugo Cheat Sheet
- ox-Hugo を使う
- 1つの org ファイルから Hugo と Qiita の Markdown を生成する
- ox-hugo - A perfect autumn day
- ox-hugo - Get Out of Your Door
- Emacs の ox-hugo で HUGO
- ブログをEmacs org-mode + Hugo + Netlifyに移行した
やりたいこと
- Org ファイルをソースとしてブログが追記/更新できるようにする.
- 見栄えは今風
の意識高い感じがいいよね.- org-mode も標準で HTML エクスポートできるが,サイト全体を作ったり見栄えを良くしたりするためには,いろいろとあれこれが必要.
- というのを最小限の手間で実現したい.
アプローチ
- サイト作成には ox-hugo を使う.
- ox-hugo は “One post per Org subtree” でサイトの内容を管理できる.ひとつのサブツリーにひとつの記事,つまりひとつの org ファイルで複数の記事 (というかサイト全体) の内容を管理することができる.
- Hugo を生で使うのも良いが,いまさら方言だらけの Markdown と格闘したくない.という人のために Hugo は org 形式もサポートしているが, 1 つのファイルで複数のページを作成することはできない.
- 見栄えは Hugo のテーマで良くする.具体的には Jane を使う.
- このあたりのテーマ界隈の事情は良く知らないので,Hugo Star Ranking
で上位のテーマから自分の趣味に合いそうなテーマを片っ端から見てみた.
Jane は 2019/8/10 時点3のランキング 8 位.
- ランキング断トツ 1 位の Academic は…なんかちょっと癖が強すぎそうなのでやめた.
- Jane は中国の人が作ったテーマらしく,CJK は考慮しているが日本語はあまり考慮されていない.特にフォントの選択が中華フォント決め打ちでしょんぼりすぎるのでなんとかする (後述).
- このあたりのテーマ界隈の事情は良く知らないので,Hugo Star Ranking
で上位のテーマから自分の趣味に合いそうなテーマを片っ端から見てみた.
Jane は 2019/8/10 時点3のランキング 8 位.
- GitLab Pages や Netlify などで org-mode から自動デプロイ (CI/CD) できるようにしたいが,それは別の機会に.
やったこと
準備
あらかじめ Hugo のそれなりに新しい版 (あまり古い版だとテーマが対応していないことがある) をインストールしておく.Debian 系だと apt-get install hugo
でも良いが,公式の配布ページに最新版のパッケージが置いてあるので,それを dpkg -i
しても良い (というかたぶんそのほうが良い).
なお,Hugo には標準版と extended 版があるが,後述の通り sass/scss を使っているテーマ (最近のテーマはほとんど使っている?) をカスタマイズしようとすると extended 版が必要になる (標準版だとはまる) ので,特に理由がなければ extended 版 (配布ファイル名に “extended” とついている) をインストールしておくことをおすすめ する.
また,org-mode や ox-hugo も適切にインストール・設定しておく.ox-hugo
は設定に特に気をつけるべきことはない.org-mode については,ox-hugo を使おうとするような マニアックな 人には説明不要と思われるので割愛.:p
Hugo サイトツリーの作成
まずは gitlab/github/bitbucket などに空のリポジトリを作成し,ローカルに clone する4.このリポジトリに空の Hugo のサイトツリーを準備し,その中にテーマを submodule として持たせる.
export MYNAME=<GitLab/GitHub/BitBucket での自分のユーザ名>
export REMOTE=<gitlab.com/github.com/bitbucket.org など>
export REPOSITORY=<作成したリポジトリ名>
export THEME=<利用するテーマの .git URL>
# リモートの空リポジトリをローカルに clone する.
git clone https://$MYNAME@$REMOTE/$MYNAME/$REPOSITORY.git
# clone したリポジトリに Hugo のサイトツリーを作成する.
hugo new site $REPOSITORY
# 作成したサイトツリーにテーマを submodule として追加する.
cd $REPOSITORY/themes; git submodule add $THEME
なお,リポジトリが空でない (何らかのファイルやディレクトリがある) 場合は hugo new site .
でエラーが出て --force
オプションを参照するよう表示される.新しくディレクトリを切って指定するか,そのままで問題なければ --force
つきで実行する.
なお,テーマは git の submodule として取り込んでいる.最新版への追随やリポジトリの肥大化防止などの観点からこの方法が望ましいが,テーマの中身を直接編集したりすると git submodule の闇にハマることになる5.
テーマのカスタマイズはサイトツリーにカスタマイズしたいファイルをコピーしてそれを編集するようにし, themes/
以下のファイルには直接手をつけないように注意. 6
サイト設定 (config.toml
) の編集
作成したサイトツリーのルートディレクトリに,テーマの exampleSite
から config.toml
をコピーして適切に書きかえる.
baseURL
, title
, author
など Hugo の一般的な設定は一般的に書き換えれば良い.ただ,メニュー項目の制御は org ファイル側でできる (後述)
ので,その場合は削除してしまっても良い.メニューを org ファイルで制御しない場合はそのまま残す.
なお defaultContentLanguage
などの言語設定を日本語 (ja
) にする場合は i18n/ja.yaml
が必要になる.後述の通り i18n/en.yaml
を雛形として修正するなりして適切に作成する (面倒なら en.yaml
を複製するだけでも良い).
テーマのカスタマイズ
前述の通り,Jane は日本語のことをあまり考えていないので,国際化まわりやフォント設定などをカスタマイズする.前述した通り,カスタマイズ対象のファイルをサイトツリー本体に複製してから修正し, themes/
以下のファイルには直接手をつけない.
Jane の場合,具体的には,
assets/sass/_variables.scss
を複製してフォント設定を修正する.どこを直すべきかは,だいたい見たらわかる.i18n/en.yaml
を複製してja.yaml
にファイル名を変更し,変更したいところを変更する.- 必要に応じて
static/css/custom.css
などを作成し,そこに追加の CSS 設定をする (ファイル名はconfig.toml
のcustomCSS
で設定する).- たとえば,この機能を使ってロゴで Web フォントを使うように変更する方法が Jane 公式の issue #7 への回答で示されている.
のあたりでフォント/言語まわりのカスタマイズはできる.ただ,前述の通り sass/scss 関係のカスタマイズは Hugo の “extended” 版を使わないと反映されない ことに注意.標準版を使っていると,いくらフォント設定を変えても記事タイトルに中華フォント (Microsoft Yahei) が使われてしまい悩むことになる (しばらく気付かずに悩んだ).
org ファイルの作成
Hugo サイトツリーの最上位ディレクトリ (config.toml
があるディレクトリ) に空の org ファイルを作成する (どこかから複製してきても良い).このファイルに,サイトの全内容を記載していくことになる.
こんな感じ↓になる.
#+hugo_base_dir: .
Hugo サイトツリーの最上位ディレクトリ (config.toml があるところ) への
相対パスを示す.
#+options: author:nil
エクスポート時の ~author~ の出力を抑制する (Author を config.toml で指
定する場合は ~author~ の出力は不要).
なお,ox-hugo は ~:EXPORT_FILE_NAME:~ プロパティに何らかの値が設定され
たノードしかエクスポートの対象としない.つまり,ここに何を書いてもサイ
トには反映されない.
* Post (名前はなんでも良い)
:PROPERTIES:
:EXPORT_HUGO_SECTION: post
:END:
このノードのサブツリーすべてを ~post~ に配置する.ここに書かれている
内容は (~:EXPORT_FILE_NAME:~ が無いため) Markdownにエクスポートされ
ず,したがってサイトにも反映されない.
** Blog Posts
:PROPERTIES:
:EXPORT_FILE_NAME: _index
:EXPORT_HUGO_MENU: :menu "main"
:END:
メニューに ~post~ を追加するためのエントリー.メニューのアイテム名に
はこのノードのタイトル (ここでは "Blog Posts") が使われる.
なぜ ~:EXPORT_HUGO_MENU:~ を親ノードではなくここで設定するべきかは,
https://www.kengrimes.com/ox-hugo-tutorial/ で詳しく説明されている.
ここに書かれている内容は ~post/_index.md~ というファイルにエクスポー
トされる.サイトに反映されるかどうかはテーマによる (Jane は反映しな
いが,セクション ~post~ の扉ページの本文として扱うテーマもある).
** ひとつ目の記事のタイトル
:PROPERTIES:
:EXPORT_FILE_NAME: ひとつ目の記事のファイル名
:EXPORT_DATE: <2020-01-13 Sun>
:END:
ひとつ目の記事の内容.
** ふたつ目の記事のタイトル
:PROPERTIES:
:EXPORT_FILE_NAME: ふたつ目の記事のファイル名
:EXPORT_DATE: <2020-01-14 Mon>
:END:
ふたつ目の記事の内容.
* About (ブログ以外の記事)
:PROPERTIES:
:EXPORT_HUGO_SECTION: /
:EXPORT_FILE_NAME: about
:EXPORT_DATE: <2020-01-15 Tue>
:EXPORT_HUGO_MENU: :menu "main"
:END:
ブログではない記事の内容.ここに書かれたことは ~about.md~ にエクスポー
トされ,メニューから辿ることができる.
なお,ここでは post
というセクションにブログ記事が書かれることを想定しているが,ブログ記事のセクション名はテーマにより異なる (post
でなく posts
など) ので,もし違う場合は修正する必要がある.また,メニューの名称を "main"
としているが,これも同様にテーマにより異なる.必要に応じて修正する.
Hugo は (Hugo だけじゃないかもしれないが),このように「テーマによって微妙に違う」ことが多い.しかも post
と posts
のように,同じものを別の名前で呼ぶことがあったりして結構カオス.このあたり標準化ってされていないのだろうか.
Markdown の export とサイトの構築
org ファイルの編集が終わったら C-c C-e H A
で Markdown にエクスポートする (contents/
以下の適切なディレクトリにファイルが配置される).
その後にサイトのルートディレクトリで hugo
を実行するとサイトが構築でき,さらに hugo server
とするとテスト用サーバーが起動する.このサーバーには http://localhost:3123/
で接続して内容を確認することができる.
.gitignore の設定とリモートへの反映
不要なファイルを push しないように .gitignore
を設定してリモートに
push する.
たとえば,リモート側の CI/CD で Hugo が自動実行される場合7は public
以下は不要だし,もし ox-hugo
も自動実行できる場合8は content
以下も不要になる.
(任意) org-capture と自動エクスポートの設定
ox-hugo の公式サイトに org-capture の設定や,自動エクスポートの設定に関する説明があるので,必要に応じて.
日々のサイト更新
ここまでで準備は完了.あとは,
- 上記で作成した org ファイルをちまちま更新して,
C-c C-e H H
(もしくは必要に応じてC-c C-e H A
) でエクスポートし,- 自動エクスポートの設定をした場合やリモートの CI/CD で ox-hugo を自動実行する場合は不要.
hugo
でサイトを構築し,- リモートの CI/CD で Hugo を自動実行する場合は不要.
git commit
/git push
で更新するだけ.
なお,テーマを Git の submodule として管理しているので,必要に応じてテーマのディレクトリで git pull
しておく9と,テーマが最新版に更新される.
しあわせになれたこと
やりたかったことはほぼできた.
- ひとつの org ファイルに追記更新するだけでサイト全体の内容の管理ができる.
- タグやカテゴリは org-mode のタグで指定できる.親和性が高い.
- メニュー構成も org のプロパティで指定できる (ただしテーマによる).
- 見た目は Hugo の豊富なテーマでいろいろ変えられる.けっこうオサレなものが揃っている.
- Hugo 爆速.インストールも簡単.Go 言語のご利益.
いまいちしあわせになれないこと
テーマ関係の設定で躓くことが多かった.いちど設定ができてしまえば問題ないとも言えるが,今後テーマを変更しようとしたりすると,また苦労しそう.
- サイト全体の設定をする
config.toml
は適宜修正しなくてはならない.しかも何をどう設定すべきかがテーマによって異なる.- しかも
post
とposts
とか,しょうもないところで違ったりする. - メニューの名称も違ったりする (
"main"
ではなく"sidebar"
とか).
- しかも
- 上記の理由から,「テーマだけ切り替えれば見た目を自由に切り替えられる」という状況からは少し遠い.
- 特に Academia などの癖が強いテーマを使ってしまうと,他のテーマへの移行には苦労しそう.
- 「内容とプレゼンテーションの分離」が,こういうしょうもないところで失われてしまっているのはもったいない.
ふしあわせではないけどなんとかしたいこと
- Jane が生成する HTML のソースはあまり綺麗ではない.Jane 以外のテーマがどのくらい綺麗かはわからないし実害があるわけでもないが,できるだけ human readable な HTML を出力してほしいところ.
- ox-hugo も含めてリモートの CI/CD で自動実行…できなくても実際問題としては困ることはないが,理想的にはそうできるようにしたい.
- まあ個人サイトで CI/CD を使うご利益がそもそも微妙という話もあるけど.
-
TeX 入稿の解説記事とか論文も org-mode で書けてしまう,というか書いた. ↩︎
-
試行錯誤をしている時点で,目的である「最小限の手間」ではなくなってしまったが,そこはそれ,現実逃避の履歴 (本サイトのタイトル) ということで. ↩︎
-
半年近く更新されていないが,まああまり新しいテーマを使うといろいろはまりそうなので気にしないことにした. ↩︎
-
なお,ローカルで
git init
してからリモートに紐づける方法もあるが,最初からリモートへの紐づけを考慮するならこちらのほうが簡単. ↩︎ -
個人的には git submodule の考え方は美しいと思う (subtree のほうがいまだによくわからない) のだけど,たぶん
git submodule update
あたりの挙動が直感に合わなかったりするのが闇を作り出しているのだと思う. ↩︎ -
もちろん,そのテーマに contribute したいなどの特別な理由がある場合は除く.そういう人は submodule の闇の中でも生きていけると思うので. ↩︎
-
そういう設定が標準で準備されていることが多く,情報もたくさんある. ↩︎
-
Emacs + ox-hugo を batch mode で実行するような CI/CD 環境を自分で構築する必要があるので,こちらは少しハードルが高い. ↩︎
-
そのほかにも
git submodule update --remote --merge
やgit submodule foreach git pull
などの方法もあるので好みのやり方で. ↩︎