81 lines
2.6 KiB
Bash
Executable File
81 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# compress-assets.sh — Generate .gz (and .br, if brotli is installed) sidecars
|
|
# for compressible text assets in _site/.
|
|
#
|
|
# Pairs with nginx `gzip_static on` / `brotli_static on`: nginx serves the
|
|
# pre-compressed file when the client advertises a matching Accept-Encoding,
|
|
# so each build pays the compression cost once (at brotli -q 11) instead of
|
|
# the server paying it on every request.
|
|
#
|
|
# Only files >= MIN_SIZE bytes are compressed — below that, the compression
|
|
# framing overhead can exceed the savings. Sidecars are regenerated only
|
|
# when the source is newer than the existing sidecar, so re-runs are cheap.
|
|
#
|
|
# Usage:
|
|
# ./tools/compress-assets.sh # compress _site/
|
|
# ./tools/compress-assets.sh path/to/dir # compress a specific directory
|
|
|
|
set -euo pipefail
|
|
|
|
SITE_DIR="${1:-_site}"
|
|
MIN_SIZE="${MIN_SIZE:-1024}" # bytes
|
|
|
|
if [ ! -d "$SITE_DIR" ]; then
|
|
echo "compress-assets: directory '$SITE_DIR' not found" >&2
|
|
exit 1
|
|
fi
|
|
|
|
have_brotli=0
|
|
if command -v brotli >/dev/null 2>&1; then
|
|
have_brotli=1
|
|
else
|
|
echo "compress-assets: brotli not found — generating gzip only" >&2
|
|
echo " (install: pacman -S brotli / apt install brotli)" >&2
|
|
fi
|
|
|
|
# Export for subshells invoked by xargs.
|
|
export MIN_SIZE
|
|
export have_brotli
|
|
|
|
compress_one() {
|
|
local src="$1"
|
|
local size
|
|
size=$(stat -c '%s' "$src" 2>/dev/null || stat -f '%z' "$src")
|
|
if [ "$size" -lt "$MIN_SIZE" ]; then
|
|
return
|
|
fi
|
|
|
|
# gzip sidecar — -9 max ratio, -n strips filename/mtime for reproducible output.
|
|
if [ ! -f "$src.gz" ] || [ "$src" -nt "$src.gz" ]; then
|
|
gzip -9 -n -c "$src" > "$src.gz.tmp" && mv "$src.gz.tmp" "$src.gz"
|
|
fi
|
|
|
|
# brotli sidecar — -Z is the max quality (level 11); slow but cached.
|
|
if [ "$have_brotli" = "1" ]; then
|
|
if [ ! -f "$src.br" ] || [ "$src" -nt "$src.br" ]; then
|
|
brotli -Z -f -o "$src.br.tmp" "$src" && mv "$src.br.tmp" "$src.br"
|
|
fi
|
|
fi
|
|
}
|
|
export -f compress_one
|
|
|
|
# Extensions worth compressing. Images (png/jpg/webp) and PDFs are already
|
|
# compressed; fonts (woff2) are zstd/brotli internally — don't re-wrap.
|
|
find "$SITE_DIR" -type f \( \
|
|
-name '*.html' -o \
|
|
-name '*.css' -o \
|
|
-name '*.js' -o \
|
|
-name '*.mjs' -o \
|
|
-name '*.json' -o \
|
|
-name '*.svg' -o \
|
|
-name '*.xml' -o \
|
|
-name '*.txt' -o \
|
|
-name '*.wasm' \
|
|
\) \
|
|
-not -name '*.gz' \
|
|
-not -name '*.br' \
|
|
-print0 \
|
|
| xargs -0 -P "$(nproc 2>/dev/null || echo 4)" -I {} bash -c 'compress_one "$@"' _ {}
|
|
|
|
echo "compress-assets: sidecars written under $SITE_DIR/"
|