Hugoの設定ファイルを分割しfswatchを使って結合してみる

アイキャッチ画像


記事内に商品のプロモーションを含む場合があります。

Nプログラマ(@Nprog128)です。

今回は、Hugoの設定ファイルconfig.tomlを分割・結合するという内容です。

config.tomlの分割は 公式でサポート (params, languages, menusなど)されていますが、任意のパラメータの場合はこれができないようです。

一つの設定ファイルにモリモリ書いてもいいのですが、1000行を超えてくると編集がツラくなってきます。

そこでfswatchを使ってファイル監視を行い、編集を検知したらconfig.tomlに結合するようにしてみました。

ファイル単位で分割しているため、設定の場所や編集のしやすがラクになるかもしれません。

あまりオススメはできません

この記事の内容を使い続けてみて実感したことですが、この方法ではHugoのライブプレビューのビルドが若干遅くなるような気がします(あくまで体感です)

configにモリモリと書くよりは、data templateを使った方がいいと思います。

環境

  • Mac OS X High Sierra 10.13.6
  • fswatch 1.14.0

準備

まずは検証のため空のプロジェクトを作成します。

1\$ hugo new site sample

sampleディレクトリの階層構造はこうなっています。

1./
2├── archetypes
3│   └── default.md
4├── config.toml
5├── content
6├── data
7├── layouts
8├── static
9└── themes

HugoのConfiguration Directory を参考にconfigディレクトリを作成します。 その下に_defaultディレクトリを作成して、config.tomlをそこに移動させます。

変更した結果、以下のようなディレクトリ階層になりました。

 1./
 2├── archetypes
 3│   └── default.md
 4├── config
 5│   └── _default
 6│       └── config.toml
 7├── content
 8├── data
 9├── layouts
10├── static
11└── themes

これで準備完了です。

設定ファイルを分割していく

分割ファイル用のディレクトリを作成

先に分割したファイルを配置するためのディレクトリを作成します。 ディレクトリ名は任意なのでtmpという名前にしました。 このディレクトリがfswatchの監視対象になります。

またこのディレクトリはhugoのサーバ起動時のビルド対象にならないので、必要以上にビルドがされないのもいいところかなと思っています。
(おそらくConfiguration Directoryのルールから外れているため、ビルドされないのだろうと思っています)

ファイルの分割

ここからは先程移動させたconfig.tomlを分割していきます。
分割前の内容はこんな感じです。

config.toml コードを開く
config.toml
 1baseURL = "サイトのURL"
 2title = "サイトのタイトル"
 3themes = "使っているテーマ"
 4
 5[MyParams.Hoge]
 6  name = "hoge"
 7  age  = "20"
 8  link = "hoge link"
 9
10[MyParams.Fuga]
11  name = "fuga"
12  age  = "30"
13  link = "fuga link"
14
15[MyParams.Piyo]
16  name = "piyo"
17  age  = "40"
18  link = "piyo link"

これらを4つのファイルに分割してみます。

  • 00.base.toml
  • myparams-hoge.toml
  • myparams-fuga.toml
  • myparams-piyo.toml

分割したファイルを先程作成したtmpディレクトリに配置します。

1./
2├── _default
3│   └── config.toml
4└── tmp
5    ├── 00.base.toml
6    ├── myparams-fuga.toml
7    ├── myparams-hoge.toml
8    └── myparams-piyo.toml

baseだけ数字がついているのは、結合時にソートしてconfig.tomlで一番上に記述したいからです。

config.tomlはfswatchの検知により常に自動生成されるため、削除しなくても問題ありません。

config.tomlは常に上書き

この仕組みを導入するとconfig.tomlは常に分割したファイルを結合した結果の上書き更新になります。
導入する前にはバックアップを取るようにお願いします。
またconfig.tomlを編集する場合は、必ず分割ファイルを編集するようにしてください。

分割したファイルのコード

00.base.toml コードを開く
00.base.toml
1baseURL = "サイトのURL"
2title = "サイトのタイトル"
3themes = "使っているテーマ"
myparams-hoge.toml コードを開く
myparams-hoge.toml
1[MyParams.Hoge]
2  name = "hoge"
3  age  = "20"
4  link = "hoge link"
myparams-fuga.toml コードを開く
myparams-fuga.toml
1[MyParams.Fuga]
2  name = "fuga"
3  age  = "30"
4  link = "fuga link"
myparams-piyo.toml コードを開く
myparams-piyo.toml
1[MyParams.Piyo]
2  name = "piyo"
3  age  = "40"
4  link = "piyo link"

ファイルの監視・結合

ファイルの分割ができたので、次はfswatch( 公式サイト )を使った監視をします。
コマンドがない場合はbrewコマンドでインストールします。

1brew install fswatch

ファイル変更を検知したらconfig.tomlに結合する処理が必要なので、そのシェルスクリプトを作成しました。

update-config.sh コードを開く
update-config.sh
 1#!/usr/bin/env bash
 2
 3# (1) 一時ファイル
 4tmpfile=$(mktemp)
 5
 6# (2) 1ファイルに対して1度だけ処理: PHPStorm用
 7echo $1 # ファイル変更の通知内容の確認
 8if [[ $(echo $1 | grep -e 'Removed') ]]; then
 9  echo '分割したファイルの結合処理をする'
10else
11  echo '何もせず終了する'
12  exit
13fi
14
15# (3) 分割ファイルの結合処理
16find ./sample/config/tmp -type f | sort | xargs -I{} cat {} >> $tmpfile
17
18# (4) 一時ファイルからconfig.tomlへ書き出し
19cat $tmpfile > ./sample/config/_default/config.toml
20
21# (5) 一時ファイルの削除
22function rm_tmpfile {
23  rm -f "$tmpfile"
24  echo 'tmpfile remove!'
25}
26trap rm_tmpfile EXIT
参考サイト

スクリプト内で一時ファイルの作成と削除について、こちらのサイト様の記事を参考にしました。
ありがとうございます。

使い方

作成したスクリプトをhugoで作ったディレクトリと同じ階層に配置します。

1./
2├── sample
3└── update-config.sh

この状態でfswatchコマンドを実行します。

1fswatch -xr ./sample/config/tmp | xargs -I{} ./update-config.sh {}

オプションの-rをつけることで、分割した設定ファイルが入ったtmpを再帰的に監視します。
また-xをつけることでどのようなイベントなのかが表示されるようになります。(これを使ってスクリプト内で条件判定をしています)

ファイルの変更を検知したら、その情報をupdate-config.shに渡します。
渡された内容はupdate-config.shの$1に入ってきます。

後述しますが、1ファイルの変更で複数の通知がくるのでスクリプト側で1回だけの処理になるようにしています。

スクリプトの配置場所について

スクリプト内でファイルパスを指定している部分があるので、そこを書き換えれば任意の場所に配置することができます。

コードの説明

(1) 一時ファイルについて

mktempを使うと一時ファイルの生成し、削除し忘れても一定期間立つと自動的に削除もされるみたいです。
これは便利で勉強になりました。

(2) 1ファイルに対して1度だけ処理について

fswatchでファイル更新をするとその通知内容が飛んでくるのですが、編集に使用したツールによって通知内容が異なるみたいです。

ツール名通知の内容
PHPStorm1ファイルにつき3つの通知
Vim v8.11ファイルにつき2つの通知

自分はPHPStormを使っていたので、fswatchからの通知内容はこんな感じでした。

1変更したファイルパス___jb_tmp___ Created Renamed Updated IsFile}
2変更したファイルパス Renamed OwnerModified IsFile}
3変更したファイルパス___jb_old___ Removed Renamed IsFile}

一番最後の通知に対して一度だけ分割ファイルの結合処理をするようにしました。

他のツールの場合はfswatchの実行画面で通知内容を確認して、条件分岐内のRemovedのところを変更すればうまく動作すると思います。

(3) 分割ファイルの結合処理

ここがメインの処理です。

findコマンドでtmpディレクトリ内のファイル一覧を取得します。

1find ./sample/config/tmp -type f

設定ファイルの中身は、昇順ソートのファイル単位で記述したいのでソートします。
findで出力したファイル一覧はソートされていないので、パイプで出力をsortに渡してソートします。

1sort

xargsコマンドを使い、ソートされたファイル一覧を一つずつcatで出力したものを一時ファイルの変数へ書き込んでいきます。
出力結果を追記していきたいので>>を使っています。

1xargs -I{} cat {} >> $tmpfile

これが終わるとtmpディレクトリ内のファイルの内容全てが、一時ファイルの変数へ書き込まれます。

(4) 一時ファイルからconfig.tomlへ書き出し

先程の一時ファイルの内容をconfig.tomlへ上書きします。

hugo serveで起動している場合は、ここでconfig.tomlが更新されたのでページのリロード処理が走ります。

使ってみる

先程作ったスクリプトを使ってみます。

sampleとupdate-config.shを配置してあるディレクトリに移動後、使い方で書いたコマンドを実行します。

1fswatch -xr ./sample/config/tmp | xargs -I{} ./update-config.sh {}

これで実行中になるので別のterminalを起動させて、myparams-hoge.tomlを編集します。

次のように変更して保存します。

変更前 コードを開く
変更前
1[MyParams.Hoge]
2  name = "hoge"
3  age  = "20"
4  link = "hoge link"
変更後 コードを開く
変更後
1[MyParams.Hoge]
2  name = "hogehoge"
3  age  = "2020"
4  link = "hoge link"

保存した後、結合されて作成された./sample/config/_default/config.tomlの中身を確認すると、myparams-hoge.tomlの変更が反映されていることが確認できました。

config.toml コードを開く
config.toml
 1baseURL = "サイトのURL"
 2title = "サイトのタイトル"
 3themes = "使っているテーマ"
 4
 5[MyParams.Fuga]
 6  name = "fuga"
 7  age  = "30"
 8  link = "fuga link"
 9
10[MyParams.Hoge]
11  name = "hogehoge"
12  age  = "2020"
13  link = "hoge link"
14
15[MyParams.Piyo]
16  name = "piyo"
17  age  = "40"
18  link = "piyo link"

00.base.tomlなど他のファイルを変更しても同じように変更内容が反映されます。

おわりに

今回は、Hugoの設定ファイル(config.toml)を分割・結合するという内容でした。

ちょっと準備が大変でしたがこれを導入してみたら、かなり設定ファイルがスッキリとしました。
設定ファイルが肥大化してきたらお試しください。

それでは、このへんで。
バイナリー!

\ ちょっとお買い物 /


関連した記事