inotifywaitを使用して静的サイトSSGのLumeCMSで変更があった時だけ再ビルドを行う
3 min read
こんにちは、無能です。今日完全にLumeCMSに移行しました。 そこで今回どのように行ったか記録。
管理用ページの分離
LumeCMSの場合、adminページと通常ページは異なります。 そうして、例えば標準設定でdeno task lume cmsとdeno task serveを行ってしまうとどちらもデフォルトの_siteフォルダにビルドされてしまいます。この場合何が起こるかというと、adminページを編集した際にはリアルタイムに_siteへのビルドが行われ非公開ページの"Draft"をYesとした場合のページも一緒にビルドされてしまうので_siteをルートディレクトリとした場合にHTTPサーバが起動したら非公開記事まで見えてしまうことになります。これを回避せねばいけません。ということで、私の場合は
/home/haturatu/.deno/bin/deno task lume cms --location=http://localhost:3001
としてlocalhostの3001番でまずはCMS用としました。 そして外で編集もできるように捨てドメインでnginx側でhttp://localhost:3001
に対してリバースプロキシを行いました。これでadminページが出来上がります。
さて、次に公開用ページですがビルドされるディレクトリを別にするとリアルタイムに変更した場合にすぐにビルドされる訳でもありません。 かと言って、ビルドをcronジョブとするのはリソース的にもディスクの消耗を無駄に行うだけなので避けたいところ。 ということでinotify-tools(inotifywait)
というファイルシステムの監視を行って変更があった場合に指定のコマンドを実行してくれるようなスクリプトを作成します。
#!/bin/bash
WATCHED_DIR="/var/www/html/soulmining/src/" # 監視を行うディレクトリ
COMMAND="/home/haturatu/.deno/bin/deno task lume --dest=site" # 実行コマンド--destでビルド出力先指定
COOLDOWN_TIME=60 # クールダウン(sec)
# 最後にコマンドを実行した時間を記録
LAST_RUN_FILE="/tmp/last_run.time"
# 現在の時間を取得
current_time() {
date +%s
}
# 最後にコマンドを実行した時間を取得する(存在しない場合は0を返す)
get_last_run_time() {
if [ -f "$LAST_RUN_FILE" ]; then
cat "$LAST_RUN_FILE"
else
echo 0
fi
}
# 最後にコマンドを実行した時間を記録
set_last_run_time() {
current_time > "$LAST_RUN_FILE"
}
inotifywait -m -r -e modify,create,delete "$WATCHED_DIR" | while read -r directory events filename; do
echo "変更が検出されました"
last_run_time=$(get_last_run_time)
now=$(current_time)
# 最後にコマンドを実行した時間からコマンドを再度実行するか判定
if [ $((now - last_run_time)) -ge $COOLDOWN_TIME ]; then
echo "コマンドを実行"
cd /var/www/html/soulmining || exit
$COMMAND
cd ~ || exit
set_last_run_time
else
echo "コマンドは実行されません"
fi
done
実際に稼働確認ができるのであればバックグランドで実行している間、echoは無駄なのでコメントアウトしても良いかもしれません。また、クールダウンを行わないと変更したファイルだけコマンドを実行してしまうため(vimのswapファイルとかも)追加しました。実際に除外するファイルも選択出来ますがこの方が自分的には手軽で間違いなく変更を拾ってくれると判断したのでこのような仕様に。 これをchreload.sh
なりでファイルを作りnohup sudo -u root chreload.sh &
で実行。 rc.local上には/my/dir/chreload.sh &
として追加。srcディレクトリが主に投稿記事やcssファイルを変更するディレクトリなのでここが変更されたことを検知すればいいかと。また、追加で変更しなければいけないのがHugoで言うところのbathUrlが標準だとlocalhostのままなので適切に設定しなければなりません。
$ cat _config.ts
import lume from "lume/mod.ts";
import blog from "blog/mod.ts";
import plugins from "./plugins.ts";
import nunjucks from "lume/plugins/nunjucks.ts";
import basePath from "lume/plugins/base_path.ts";
const site = lume({
src: "./src",
location: new URL("https://soulminingrig.com"),
});
site.use(basePath());
site.use(plugins());
site.use(nunjucks());
export default site;
と、いうわけでこれで公開しても問題ないようにしました。また、denoでhttpサーバを起動することに抵抗あったのでadminページであるCMS以外の部分のsite
ディレクトリをApache側でListenして公開用サーバーであるNginxでApacheにリバースプロキシして公開しています。それではまた。 よろしくお願いします。