#!/bin/bash # release.sh - Build optimized WASM and serve with Caddy + Brotli compression set -e ############################################################################### # Freezone Portal Release Script # - Builds the WASM app with trunk in release mode # - Optionally optimizes .wasm with wasm-opt (-Oz, strip) # - Precompresses assets with gzip and brotli for efficient static serving # - Generates a manifest (manifest.json) with sizes and SHA-256 checksums # # Usage: # ./release.sh [--outdir dist] [--no-opt] [--compress] [--no-manifest] # [--trunk-args "--public-url /portal/"] # # Notes: # - Precompression is OFF by default; enable with --compress # - Only modifies files within the output directory (default: dist) # - Non-destructive to your source tree ############################################################################### set -u SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) PROJECT_DIR=$(cd "$SCRIPT_DIR/.." && pwd) BUILD_SCRIPT="$SCRIPT_DIR/build.sh" # Defaults OUTDIR="dist" DO_OPT=1 DO_COMPRESS=0 DO_MANIFEST=1 TRUNK_ARGS="" usage() { cat < Output directory (default: dist) --no-opt Skip wasm-opt optimization --compress Enable gzip/brotli precompression --no-manifest Skip manifest generation --trunk-args "..." Extra arguments forwarded to trunk build -h, --help Show this help Examples: $(basename "$0") --outdir dist --trunk-args "--public-url /" $(basename "$0") --no-opt --no-compress EOF } # Parse args while [[ $# -gt 0 ]]; do case "$1" in --outdir) OUTDIR="$2"; shift 2;; --no-opt) DO_OPT=0; shift;; --compress) DO_COMPRESS=1; shift;; --no-manifest) DO_MANIFEST=0; shift;; --trunk-args) TRUNK_ARGS="$2"; shift 2;; -h|--help) usage; exit 0;; *) echo "❌ Unknown option: $1"; echo; usage; exit 1;; esac done # Tool checks if [[ ! -x "$BUILD_SCRIPT" ]]; then echo "❌ build.sh not found or not executable at: $BUILD_SCRIPT" echo " Ensure portal/scripts/build.sh exists and is chmod +x." exit 1 fi if ! command -v trunk >/dev/null 2>&1; then echo "❌ trunk not found. Install with: cargo install trunk"; exit 1; fi HAS_WASM_OPT=0 if command -v wasm-opt >/dev/null 2>&1; then HAS_WASM_OPT=1; fi if [[ $DO_OPT -eq 1 && $HAS_WASM_OPT -eq 0 ]]; then echo "⚠️ wasm-opt not found. Skipping WASM optimization." DO_OPT=0 fi if [[ $DO_COMPRESS -eq 1 ]]; then if ! command -v gzip >/dev/null 2>&1; then echo "⚠️ gzip not found. Skipping gzip compression."; GZIP_OK=0; else GZIP_OK=1; fi if ! command -v brotli >/dev/null 2>&1; then echo "⚠️ brotli not found. Skipping brotli compression."; BR_OK=0; else BR_OK=1; fi else GZIP_OK=0; BR_OK=0 fi echo "🔧 Building optimized WASM bundle (via build.sh)..." set -x "$BUILD_SCRIPT" --release --outdir "$OUTDIR" ${TRUNK_ARGS:+--trunk-args "$TRUNK_ARGS"} set +x DIST_DIR="$PROJECT_DIR/$OUTDIR" if [[ ! -d "$DIST_DIR" ]]; then echo "❌ Build failed: output directory not found: $DIST_DIR"; exit 1; fi # Optimize .wasm files if [[ $DO_OPT -eq 1 && $HAS_WASM_OPT -eq 1 ]]; then echo "🛠️ Optimizing WASM with wasm-opt (-Oz, strip)..." while IFS= read -r -d '' wasm; do echo " • $(basename "$wasm")" tmp="$wasm.opt" wasm-opt -Oz --strip-dwarf "$wasm" -o "$tmp" mv "$tmp" "$wasm" done < <(find "$DIST_DIR" -type f -name "*.wasm" -print0) fi # Precompress assets if [[ $DO_COMPRESS -eq 1 ]]; then echo "🗜️ Precompressing assets (gzip/brotli)..." while IFS= read -r -d '' f; do if [[ $GZIP_OK -eq 1 ]]; then gzip -kf9 "$f" fi if [[ $BR_OK -eq 1 ]]; then brotli -f -q 11 "$f" fi done < <(find "$DIST_DIR" -type f \( -name "*.wasm" -o -name "*.js" -o -name "*.css" \) -print0) fi # Manifest with sizes and SHA-256 if [[ $DO_MANIFEST -eq 1 ]]; then echo "🧾 Generating manifest.json (sizes, sha256)..." manifest="$DIST_DIR/manifest.json" echo "{" > "$manifest" first=1 while IFS= read -r -d '' f; do rel="${f#"$DIST_DIR/"}" size=$(stat -f%z "$f" 2>/dev/null || stat -c%s "$f") if command -v shasum >/dev/null 2>&1; then hash=$(shasum -a 256 "$f" | awk '{print $1}') else hash=$(openssl dgst -sha256 -r "$f" | awk '{print $1}') fi [[ $first -eq 1 ]] || echo "," >> "$manifest" first=0 printf " \"%s\": { \"bytes\": %s, \"sha256\": \"%s\" }" "$rel" "$size" "$hash" >> "$manifest" done < <(find "$DIST_DIR" -type f ! -name "manifest.json" -print0 | sort -z) echo "\n}" >> "$manifest" fi echo "📦 Checking bundle sizes ($OUTDIR)..." if [ -d "$OUTDIR" ]; then echo "Bundle sizes:" find "$OUTDIR" -name "*.wasm" -exec ls -lh {} \; | awk '{print " WASM: " $5 " - " $9}' find "$OUTDIR" -name "*.js" -exec ls -lh {} \; | awk '{print " JS: " $5 " - " $9}' find "$OUTDIR" -name "*.css" -exec ls -lh {} \; | awk '{print " CSS: " $5 " - " $9}' echo "" fi