Realizar conversão WebP com LumeCMS
Olá, sou incompetente.
Como eu usava o WordPress, a conversão para WebP era fácil, bastava instalar um plugin que executava o ImageMagick internamente, mas essa funcionalidade não existe no LumeCMS.
Pode ser possível com um plugin do Lume, mas, no final das contas, para a eficiência no processamento de imagens, é mais rápido e eficiente executar algo escrito em C.
Não é impossível com um script do lado do Nginx, mas como também estou usando um proxy reverso e precisei introduzir outras coisas, e os recursos do servidor que faz o proxy reverso são 1vCPU Mem 1GB Disk 25GB, não senti a necessidade de forçar isso dentro de recursos tão limitados.
Além disso, parece que algumas pessoas tornam isso possível executando scripts Lua internamente. Realizando a conversão automática de imagens do servidor para WebP com Nginx+Lua+libwebp
A desvantagem é que este script é executado no momento da requisição, o que me faz sentir que ele tem o potencial de concentrar recursos.
Parece haver um wrapper para npm chamado cwebp-bin, mas o que é realmente necessário é a conversão de imagens e a reescrita dos caminhos das imagens nos arquivos HTML do site estático construído.
Portanto, como um processo de backend, decidi executar um script shell que converte para webp dentro do meu próprio script de init daemon, que monitora as alterações do Lume e constrói automaticamente.
Além disso, não estou usando libvips. A conversão WebP do libvips usa internamente libwebp, que é o mesmo que cwebp, que pode ser facilmente instalado via apt, então farei a conversão com cwebp.
Script shell para conversão
Conforme mostrado abaixo, os arquivos de imagem são convertidos para WebP, excluindo padrões duplicados.
#!/bin/bash
# Diretório a ser monitorado
SOURCE_DIR="/var/www/html/soulmining/src/uploads"
# Diretório de saída WebP
DEST_DIR="/var/www/html/soulmining/src/uploads"
# Extensões a serem convertidas
EXTENSIONS=("png" "jpg" "jpeg")
# Configuração de qualidade WebP (0-100)
QUALITY=80
# Verificar comandos necessários
command -v cwebp >/dev/null 2>&1 || { echo >&2 "cwebp comando não encontrado. Por favor, instale-o."; exit 1; }
# Criar diretório de destino se não existir
mkdir -p "$DEST_DIR"
# Função para processar arquivos
process_file() {
local file="$1"
local filename=$(basename "$file")
local name="${filename%.*}"
local dest_file="$DEST_DIR/${name}.webp"
# Pular arquivos já convertidos
if [ -f "$dest_file" ]; then
echo "Pular: $filename (já convertido)"
return
fi
# Converter para WebP
cwebp -q $QUALITY "$file" -o "$dest_file"
if [ $? -eq 0 ]; then
echo "Conversão bem-sucedida: $filename -> ${name}.webp"
else
echo "Falha na conversão: $filename"
fi
}
# Processamento principal
for ext in "${EXTENSIONS[@]}"; do
find "$SOURCE_DIR" -type f -name "*.$ext" | while read file; do
process_file "$file"
done
done
echo "Processamento concluído"
Adicione isso ao c/initme-watcher do init daemon.
#!/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"
~~~
Omitido
~~~
# Iniciar monitoramento
monitor_directory() {
inotifywait -m -r -e modify,create,delete "$WATCHED_DIR" | while read -r directory events filename; do
echo "$(date): Alteração detectada" >> "$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): Executando 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 não executado devido ao tempo de espera" >> "$LOG_FILE"
fi
done
}
~~~
Fim
Estritamente falando, no caso deste init daemon, ele detecta todas as alterações dentro do diretório de destino, então uma reconstrução será executada apenas ao fazer o upload de uma imagem, mas, bem, é o que é.
Se for fazer isso, especifique a opção de execução do inotifywait como --exclude "dth".
Adicionar a _config.ts
Bem, ainda há trabalho a ser feito.
Do jeito que está, os caminhos nos arquivos HTML construídos com Lume especificam os caminhos das imagens originais.
Então, vamos fazer com que ele reescreva durante a construção.
import { walk } from "httpeno.lad/d.ts";
~~~
Omitido
~~~
site.addEventListener("afterBuild", async () => {
const buildDir = site.dest() // Diretório de saída da construção
for await (const entry of walk(buildDir, { exts: [".html"] })) {
if (entry.isFile) {
let content = await Deno.readTextFile(entry.path);
// Expressão regular para converter URLs para .webp
const regex = /url\([\s'"]*([^)'"]+)\.(png|jpe?g|gif)([\s'"]*\))/gi;
content = content.replace(regex, (match, p1, p2, p3) => {
return `url(${p1}.webp${p3})`;
});
// Também para tags img src e srcset
const imgRegex = /(src|srcset)=([\s'"]*)([^\s'"]+)\.(png|jpe?g|gif)([\s'"]*)/gi;
content = content.replace(imgRegex, (match, p1, p2, p3, p4, p5) => {
return `${p1}=${p2}${p3}.webp${p5}`;
});
await Deno.writeTextFile(entry.path, content);
console.log(`Processado: ${entry.path}`);
}
}
});
Sinceramente, é segredo que pensei que seria mais curto, mais rápido e mais fácil reescrever isso com sed dentro do lume-watcher.
A propósito, a opção -w do Lume é instável
Tenho um daemon em execução, mas o Lume oficial também tem um recurso de observação, então, se você o iniciar com a opção -w como deno task lume -w, você pode gerar HTML toda vez que um arquivo muda sem usar um servidor simples, mas é instável.
Frequentemente travava no meu ambiente.
No próprio LumeCMS, dentro de apteme.ts que existe no repositório do 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 ser chamado por isso.
await site.update(files);
Parece ser nesse ponto.
Como é algo chamado dentro do código do LumeCMS, sinto que o próprio Lume deveria ser o mesmo, mas me pergunto por que não é.
É tudo por agora. Por favor, cuide-se novamente.