在LumeCMS中進行WebP轉換
您好,我是無能。
由於我之前一直使用WordPress,WebP轉換只需安裝插件並在內部執行ImageMagick即可輕鬆完成,但LumeCMS中不存在這樣的功能。
或許Lume的插件可以實現,但從圖像處理的效率來看,執行用C語言編寫的程序會更快、更高效。
雖然Nginx端的腳本並非不可能,但由於我正在進行反向代理,還需要引入其他功能,而且反向代理伺服器的資源相當有限,為1vCPU Mem 1GB Disk 25GB,因此我認為沒有必要在如此有限的資源內強行執行。
此外,似乎也有人透過在內部執行Lua腳本來實現。 透過Nginx+Lua+libwebp實現伺服器圖片自動WebP轉換
缺點是這個腳本會在請求時執行,我感覺這可能會導致資源集中。
作為npm的包裝器,似乎有cwebp-bin,但實際上需要的是圖片轉換和已建置的靜態網站HTML檔案中圖片路徑的重寫。
因此,我決定在自己編寫的init守護進程腳本中執行一個將圖片轉換為WebP的shell腳本,該腳本作為後端處理,監控Lume的變更並自動建置。
此外,我沒有使用libvips。因為libvips的WebP轉換內部只是使用了libwebp,這與可以透過apt等輕鬆安裝的cwebp是相同的,所以我將使用cwebp進行轉換。
轉換用的Shell腳本
如下所示,排除重複模式後,將圖片檔案群轉換為WebP。
#!/bin/bash
# 監視するディレクトリ
SOURCE_DIR="/var/www/html/soulmining/src/uploads"
# WebP出力先ディレクトリ
DEST_DIR="/var/www/html/soulmining/src/uploads"
# 変換対象の拡張子
EXTENSIONS=("png" "jpg" "jpeg")
# WebPの品質設定 (0-100)
QUALITY=80
# 必要なコマンドの確認
command -v cwebp >/dev/null 2>&1 || { echo >&2 "cwebpコマンドが見つかりません。インストールしてください。"; exit 1; }
# 出力先ディレクトリが存在しない場合は作成
mkdir -p "$DEST_DIR"
# ファイルを処理する関数
process_file() {
local file="$1"
local filename=$(basename "$file")
local name="${filename%.*}"
local dest_file="$DEST_DIR/${name}.webp"
# 既に変換済みのファイルはスキップ
if [ -f "$dest_file" ]; then
echo "スキップ: $filename (既に変換済み)"
return
fi
# WebPに変換
cwebp -q $QUALITY "$file" -o "$dest_file"
if [ $? -eq 0 ]; then
echo "変換成功: $filename -> ${name}.webp"
else
echo "変換失敗: $filename"
fi
}
# メイン処理
for ext in "${EXTENSIONS[@]}"; do
find "$SOURCE_DIR" -type f -name "*.$ext" | while read file; do
process_file "$file"
done
done
echo "処理完了"
將此內容追加到init守護進程的c/initme-watcher`](httpithub.cturame-watcher)中。
#!/bin/bash
### BEGIN INIT INFO
# Provides: lume-watcher
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Watches directory and triggers Lume task
# Description: Watches the specified directory and triggers the Deno Lume task when changes are detected.
### END INIT INFO
WATCHED_DIR="/var/www/html/soulmining/src/"
COMMAND="/home/haturatu/.deno/bin/deno task lume --dest=site"
CONV_WEBP="/opt/sh/webp.sh"
~~~
省略
~~~
# 監視開始を行う
monitor_directory() {
inotifywait -m -r -e modify,create,delete "$WATCHED_DIR" | while read -r directory events filename; do
echo "$(date): Change detected" >> "$LOG_FILE"
last_run_time=$(get_last_run_time)
now=$(current_time)
if [ $((now - last_run_time)) -ge $COOLDOWN_TIME ]; then
check_and_rotate_log
echo "$(date): Executing command" >> "$LOG_FILE"
sleep 0
cd $OUTPUT_ROOT_DIR || exit
$CONV_WEBP >> "$LOG_FILE" 2>&1
$COMMAND >> "$LOG_FILE" 2>&1
cd ~ || exit
set_last_run_time
else
echo "$(date): Command not executed due to cooldown" >> "$LOG_FILE"
fi
done
}
~~~
以下略
嚴格來說,這個init守護進程會檢測目標目錄內的所有變更,所以即使只上傳圖片也會觸發重新建置,但這也沒辦法。
如果要做的話,可以在執行inotifywait時指定選項為 --exclude "dth"。
追加到_config.ts
好的,還有工作要做。
如果保持原樣,Lume建置後的HTML檔案中的圖片路徑會指向原始圖片的路徑。
所以我們讓它在建置時進行重寫。
import { walk } from "httpeno.lad/d.ts";
~~~
略
~~~
site.addEventListener("afterBuild", async () => {
const buildDir = site.dest()ビルド出力ディレクトリ
for await (const entry of walk(buildDir, { exts: [".html"] })) {
if (entry.isFile) {
let content = await Deno.readTextFile(entry.path);
URLを.webpに変換する正規表現
const regex rcload"'\s]+\.(png|jpe?g|gif;
content = content.replace(regex, (match) => {
return match.replac(png|jpe?g|gif '.webp');
});
await Deno.writeTextFile(entry.path, content);
console.log(`Processed: ${entry.path}`);
}
}
});
說實話,我偷偷想過,在lume-watcher中用sed來重寫會更短、更快、更方便。
順帶一提,lume的-w選項不穩定
雖然我有在執行的守護進程,但Lume官方也提供了一個watch功能,如果加上-w選項以deno task lume -w啟動,可以不使用簡易伺服器,每次檔案變更時都生成HTML,但它不穩定。
在我的環境下經常崩潰。
LumeCMS本身在cms儲存庫中的apteme.ts`內
Start the watcher
const watcher = site.getWatcher();
deno-lint-ignore no-explicit-any
watcher.addEventListener("change", async (event: any) => {
const files = event.files!;
await site.update(files);
dispatch("previewUpdated");
});
watcher.start();
似乎是這樣調用的。
await site.update(files);
看起來是在那裡。
既然它是在LumeCMS的程式碼中被調用的,那麼Lume本身應該也是一樣的才對,為什麼會這樣呢?
那麼,下次再見了。