diff --git a/bin/hugo-build b/bin/hugo-build index c7ba1387c..4fe1dbad1 100755 --- a/bin/hugo-build +++ b/bin/hugo-build @@ -28,4 +28,9 @@ HUGO_ARGS=(hugo build --noBuildLock --environment "$ENVIRONMENT" --destination " "${HUGO_ARGS[@]}" +# Inline critical CSS in production builds +if [ "$ENVIRONMENT" = "production" ]; then + "$SCRIPT_DIR/inline-critical" "$OUTPUT_DIR" +fi + echo "✓ Build complete" diff --git a/bin/inline-critical b/bin/inline-critical new file mode 100755 index 000000000..6cbe57148 --- /dev/null +++ b/bin/inline-critical @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Inline critical CSS using Beasties + +set -euo pipefail + +PUBLIC_DIR="${1:-_dest/public-dev}" + +if [ ! -d "$PUBLIC_DIR" ]; then + echo "Error: $PUBLIC_DIR does not exist" >&2 + exit 1 +fi + +echo "Inlining critical CSS in $PUBLIC_DIR..." +bun run "$(dirname "$0")/inline-critical.mjs" "$PUBLIC_DIR" +echo "✓ Critical CSS inlining complete" diff --git a/bin/inline-critical.mjs b/bin/inline-critical.mjs new file mode 100644 index 000000000..11a7a861a --- /dev/null +++ b/bin/inline-critical.mjs @@ -0,0 +1,106 @@ +#!/usr/bin/env node +/** + * Critical CSS inlining via Beasties + * Process Hugo's public/ output to extract and inline above-the-fold critical CSS + */ + +import Beasties from 'beasties'; +import fs from 'node:fs'; +import path from 'node:path'; + +const target = process.argv[2]; + +if (!target) { + console.error('usage: inline-critical.mjs '); + process.exit(1); +} + +if (!fs.existsSync(target)) { + console.error(`Error: directory not found: ${target}`); + process.exit(1); +} + +const beasties = new Beasties({ + path: target, + publicPath: '/', + external: true, // process external stylesheets + remote: false, // don't download remote; we convert URLs to relative + pruneSource: false, // DO NOT modify source CSS files + reduceInlineStyles: true, + mergeStylesheets: false, // keep the deferred bundle separate + preload: 'swap', // + noscriptFallback: true, // add