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ページが出来上がります。 Image
さて、次に公開用ページですがビルドされるディレクトリを別にするとリアルタイムに変更した場合にすぐにビルドされる訳でもありません。 かと言って、ビルドを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にリバースプロキシして公開しています。それではまた。 よろしくお願いします。