Created
February 20, 2026 12:55
-
-
Save Nooshu/568f44fe571d11660bc3e4e281f6329b to your computer and use it in GitHub Desktop.
The HTML compression postbuild file for compressing the HTML to Brotli 11. (contains logging for Cloudflare pages builds)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import fs from 'fs'; | |
| import path from 'path'; | |
| import { brotliCompress, BROTLI_LEVEL } from './compression.js'; | |
| /** | |
| * Recursively find all .html files in a directory. | |
| * @param {string} dir - Directory to search | |
| * @param {string[]} [acc=[]] - Accumulator for results | |
| * @returns {string[]} Relative paths to .html files | |
| */ | |
| function findHtmlFiles(dir, acc = []) { | |
| const entries = fs.readdirSync(dir, { withFileTypes: true }); | |
| for (const entry of entries) { | |
| const fullPath = path.join(dir, entry.name); | |
| const relPath = path.relative('./_site', fullPath); | |
| if (entry.isDirectory()) { | |
| findHtmlFiles(fullPath, acc); | |
| } else if (entry.isFile() && entry.name.endsWith('.html')) { | |
| acc.push(relPath); | |
| } | |
| } | |
| return acc; | |
| } | |
| /** | |
| * Compress all HTML files in _site with Brotli level 11, writing .br files. | |
| * Call after Eleventy build when HTML has been output. | |
| * | |
| * Serving: functions/[[path]].js performs content negotiation for HTML document requests. | |
| * When client sends Accept-Encoding: br, it serves the .br file with Content-Encoding: br. | |
| * Otherwise it passes through to static assets (uncompressed HTML). | |
| */ | |
| export function compressHtmlFiles() { | |
| const startTime = Date.now(); | |
| console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); | |
| console.log('🚀 PRODUCTION POSTBUILD: Starting HTML Brotli compression'); | |
| console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'); | |
| const siteDir = path.join('./_site'); | |
| if (!fs.existsSync(siteDir)) { | |
| console.log('⚠️ _site directory not found, skipping HTML compression'); | |
| return; | |
| } | |
| const htmlFiles = findHtmlFiles(siteDir); | |
| if (htmlFiles.length === 0) { | |
| console.log('⚠️ No HTML files found, skipping compression'); | |
| return; | |
| } | |
| let compressedCount = 0; | |
| let skippedCount = 0; | |
| let totalOriginal = 0; | |
| let totalCompressed = 0; | |
| const errors = []; | |
| for (const relPath of htmlFiles) { | |
| const inputPath = path.join(siteDir, relPath); | |
| const outputPath = `${inputPath}.br`; | |
| try { | |
| if (fs.existsSync(outputPath)) { | |
| const inputStats = fs.statSync(inputPath); | |
| const outputStats = fs.statSync(outputPath); | |
| if (outputStats.mtime >= inputStats.mtime) { | |
| skippedCount++; | |
| continue; | |
| } | |
| } | |
| const fileContent = fs.readFileSync(inputPath); | |
| const originalSize = fileContent.length; | |
| const brotliBuffer = brotliCompress(fileContent, BROTLI_LEVEL); | |
| const compressedSize = brotliBuffer.length; | |
| fs.writeFileSync(outputPath, brotliBuffer); | |
| compressedCount++; | |
| totalOriginal += originalSize; | |
| totalCompressed += compressedSize; | |
| } catch (error) { | |
| errors.push(`❌ ${relPath}: ${error.message}`); | |
| } | |
| } | |
| const totalTime = Date.now() - startTime; | |
| const savedPercent = totalOriginal > 0 ? ((1 - totalCompressed / totalOriginal) * 100).toFixed(1) : '0'; | |
| console.log(`✅ Compressed ${compressedCount} HTML file(s) (${skippedCount} skipped, up-to-date)`); | |
| if (compressedCount > 0) { | |
| console.log( | |
| ` ${(totalOriginal / 1024).toFixed(1)} KB → ${(totalCompressed / 1024).toFixed(1)} KB (${savedPercent}% smaller)` | |
| ); | |
| } | |
| console.log(` Finished in ${totalTime}ms (${(totalTime / 1000).toFixed(2)}s)`); | |
| if (errors.length > 0) { | |
| console.error('\nErrors:'); | |
| errors.forEach(e => console.error(` ${e}`)); | |
| } | |
| console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment