Realizar la conversión a WebP en LumeCMS

10 min

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

Hola, soy Munou.

Hasta ahora, como usaba WordPress, la conversión a WebP se realizaba fácilmente instalando un plugin y ejecutando ImageMagick internamente, pero esa funcionalidad no existe en LumeCMS.

Quizás sea posible con un plugin de Lume, pero en última instancia, por la eficiencia en el procesamiento de imágenes, es más rápido y eficiente ejecutar algo escrito en C.

No es imposible con un script del lado de Nginx, pero como también estoy usando un proxy inverso, habría tenido que introducir otras cosas, y no sentí la necesidad de forzarlo dentro de los recursos muy limitados del servidor de proxy inverso (1vCPU Mem 1GB Disk 25GB).

Además, parece que algunas personas lo hacen posible ejecutando scripts Lua internamente. Lograr la conversión automática de imágenes del servidor a WebP con Nginx+Lua+libwebp

El inconveniente es que este script se ejecuta en el momento de la solicitud, por lo que siento que tiene el potencial de concentrar recursos.

Parece que hay un wrapper para npm llamado cwebp-bin, pero lo que realmente se necesita es la conversión de imágenes y la reescritura de las rutas de las imágenes en los archivos HTML del sitio estático construido.

Por lo tanto, como proceso de backend, ejecutaré un script de shell que convierte a WebP dentro de mi propio script de daemon init, que monitorea los cambios de Lume y construye automáticamente.

Además, no estoy usando libvips. Dado que la conversión a WebP de libvips solo usa libwebp internamente, es lo mismo que cwebp, que se puede instalar fácilmente a través de apt, etc., así que realizaré la conversión con cwebp.

Script de shell para la conversión

Como se muestra a continuación, los archivos de imagen se convertirán a WebP, excluyendo patrones duplicados.

#!/bin/bash

# Directorio a monitorear
SOURCE_DIR="/var/www/html/soulmining/src/uploads"

# Directorio de salida de WebP
DEST_DIR="/var/www/html/soulmining/src/uploads"

# Extensiones a convertir
EXTENSIONS=("png" "jpg" "jpeg")

# Configuración de calidad de WebP (0-100)
QUALITY=80

# Verificar comandos necesarios
command -v cwebp >/dev/null 2>&1 || { echo >&2 "cwebp comando no encontrado. Por favor, instálelo."; exit 1; }

# Crear directorio de destino si no existe
mkdir -p "$DEST_DIR"

# Función para procesar archivos
process_file() {
    local file="$1"
    local filename=$(basename "$file")
    local name="${filename%.*}"
    local dest_file="$DEST_DIR/${name}.webp"

    # Saltar archivos ya convertidos
    if [ -f "$dest_file" ]; then
        echo "Saltar: $filename (ya convertido)"
        return
    fi

    # Convertir a WebP
    cwebp -q $QUALITY "$file" -o "$dest_file"
    
    if [ $? -eq 0 ]; then
        echo "Conversión exitosa: $filename -> ${name}.webp"
    else
        echo "Conversión fallida: $filename"
    fi
}

# Proceso principal
for ext in "${EXTENSIONS[@]}"; do
    find "$SOURCE_DIR" -type f -name "*.$ext" | while read file; do
        process_file "$file"
    done
done

echo "Proceso completado"

Esto se añadirá al c/initme-watcher`](httpithub.cturame-watcher) del daemon 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"
~~~
省略
~~~
# Iniciar monitoreo
monitor_directory() {
    inotifywait -m -r -e modify,create,delete "$WATCHED_DIR" | while read -r directory events filename; do

        echo "$(date): Cambio detectado" >> "$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): Ejecutando comando" >> "$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): Comando no ejecutado debido al tiempo de espera" >> "$LOG_FILE"
        fi
    done
}
~~~
以下略

Estrictamente hablando, en el caso de este daemon init, se detectan todos los cambios dentro del directorio objetivo, por lo que se ejecutará una reconstrucción solo con subir una imagen, pero supongo que es inevitable.
Si lo hicieras, deberías especificar la opción de ejecución de inotifywait como --exclude "dth".

Añadir a _config.ts

Bueno, todavía queda trabajo por hacer.
Tal como está, las rutas de los archivos HTML cuando se construyen con Lume especifican las rutas de las imágenes originales.
Así que, hagamos que las reescriba durante la construcción.

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}`);  
    }  
  }  
});  

Honestamente, es un secreto que pensé que sería más corto, más rápido y más fácil reescribir esto con sed dentro de lume-watcher.

Por cierto, la opción -w de Lume es inestable

Aunque tengo un daemon en ejecución, Lume también tiene una función de vigilancia oficial, por lo que si lo inicias con la opción -w como deno task lume -w, puedes generar HTML cada vez que un archivo cambia sin usar un servidor simple, pero es inestable.
En mi entorno, a menudo se bloqueaba.

En LumeCMS mismo, dentro de `apteme.ts` que se encuentra en el repositorio de 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();  

Parece que se llama así.

await site.update(files);  

Parece que es en ese punto.
Dado que es algo que se llama dentro del código de LumeCMS, siento que Lume mismo debería ser lo mismo, pero me pregunto por qué.

Eso es todo. Hasta la próxima.

Related Posts