Преобразование в WebP с помощью LumeCMS
Привет, я бездарь.
Поскольку я раньше использовал WordPress, преобразование в WebP было простым: я устанавливал плагин, который внутренне запускал ImageMagick, но такой функциональности в LumeCMS нет.
Возможно, это можно сделать с помощью плагина Lume, но в конечном итоге, с точки зрения эффективности обработки изображений, быстрее и эффективнее запускать программы, написанные на C.
Это не невозможно с помощью скрипта на стороне Nginx, но поскольку я использую обратный прокси, мне пришлось бы внедрять и другие вещи, и я не видел необходимости форсировать это в условиях довольно ограниченных ресурсов сервера обратного прокси: 1vCPU Mem 1GB Disk 25GB.
Кроме того, похоже, некоторые люди делают это возможным, выполняя внутренне скрипты Lua. Реализация автоматического преобразования серверных изображений в WebP с помощью Nginx+Lua+libwebp
Недостатком является то, что этот скрипт выполняется при каждом запросе, и я чувствую, что это может привести к концентрации ресурсов.
Похоже, существует обертка для npm под названием cwebp-bin, но на самом деле нам нужно преобразование изображений и перезапись путей к изображениям в HTML-файлах сгенерированного статического сайта.
Поэтому я решил запускать скрипт оболочки для преобразования в WebP внутри своего собственного скрипта init-демона, который отслеживает изменения в Lume и автоматически выполняет сборку в фоновом режиме.
Кроме того, я не использую libvips. Поскольку libvips для преобразования в WebP внутренне использует только libwebp, и это то же самое, что cwebp, который легко установить через apt и т.д., я буду выполнять преобразование с помощью cwebp.
Скрипт оболочки для преобразования
Как показано ниже, исключая дублирующиеся шаблоны, я преобразую группу файлов изображений в 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 "処理完了"
Это будет добавлено в c/initme-watcher init-демона.
#!/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-демона он обнаруживает все изменения в целевом каталоге, поэтому пересборка будет запускаться даже при простой загрузке изображения, но что поделать.
Если вы хотите это сделать, укажите опцию --exclude "dth" при выполнении inotifywait.
Добавление в _config.ts
Итак, работа еще не закончена.
В текущем виде пути к HTML-файлам, сгенерированным Lume, указывают на пути к исходным изображениям.
Поэтому давайте сделаем так, чтобы они перезаписывались во время сборки.
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}`);
}
}
});
Честно говоря, я подумал, что было бы короче, быстрее и проще перезаписать это с помощью sed внутри lume-watcher... но это секрет.
Кстати, опция -w в Lume нестабильна
У меня запущен демон, но даже в официальной документации Lume говорится о возможности использования опции -w для запуска deno task lume -w, что позволяет генерировать HTML при каждом изменении файла без использования простого сервера, но это нестабильно.
В моей среде это часто приводило к сбоям.
В самом LumeCMS, в файле `apteme.ts`, который находится в репозитории CMS,
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 должен быть таким же, но почему?
На этом все. До новых встреч.