Преобразование в WebP с помощью LumeCMS

9 min

language: ja bn en es hi pt ru zh-cn zh-tw

Привет, я бездарь.

Поскольку я раньше использовал 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 должен быть таким же, но почему?

На этом все. До новых встреч.

Related Posts