UNPKG

astro-minify-html-swc

Version:
92 lines (74 loc) 2.73 kB
import fs from 'node:fs/promises' import path from 'node:path' import { fileURLToPath } from 'node:url' import { formatBytes } from '@ocavue/utils' import type * as SWC from '@swc/html' import type { AstroIntegration, AstroIntegrationLogger } from 'astro' import glob from 'fast-glob' type SizeChange = [sizeBefore: number, sizeAfter: number] function formatSizeChange([sizeBefore, sizeAfter]: SizeChange): string { const diff = sizeAfter - sizeBefore const percent = (100 * diff) / sizeBefore return `${formatBytes(diff)} (${percent.toFixed(1)}%)` } async function compress( logger: AstroIntegrationLogger, minify: typeof SWC.minify, dirPath: string, filePath: string, isDebug: boolean, ): Promise<SizeChange> { try { const fullPath = path.join(dirPath, filePath) const textBefore = await fs.readFile(fullPath, 'utf-8') const sizeBefore = Buffer.byteLength(textBefore, 'utf-8') const result = await minify(textBefore, { collapseWhitespaces: 'conservative', removeComments: true, minifyJson: true, minifyJs: true, minifyCss: true, }) const textAfter = result.code const sizeAfter = Buffer.byteLength(textAfter, 'utf-8') await fs.writeFile(fullPath, textAfter, 'utf-8') if (isDebug) { logger.debug(`${formatSizeChange([sizeBefore, sizeAfter])} ${filePath}`) } return [sizeBefore, sizeAfter] } catch (error) { logger.error(`Failed to minify ${filePath}:`) logger.error(String(error)) return [0, 0] } } export default function integration(): AstroIntegration { return { name: 'astro-minify-html-swc', hooks: { 'astro:build:done': async ({ logger, dir }) => { const timeStart = performance.now() const dirPath = fileURLToPath(dir) logger.debug(`Scanning ${dirPath}`) const filePaths = await glob('**/*.html', { cwd: dirPath }) logger.debug(`Found ${filePaths.length} HTML files in ${dirPath}`) const { minify } = await import('@swc/html') const isDebug = logger.options.level === 'debug' const sizeChanges = await Promise.all( filePaths.map((filePath) => { return compress(logger, minify, dirPath, filePath, isDebug) }), ) const totalSizeChange: SizeChange = [0, 0] for (const sizeChange of sizeChanges) { totalSizeChange[0] += sizeChange[0] totalSizeChange[1] += sizeChange[1] } const timeEnd = performance.now() logger.info( `${formatSizeChange(totalSizeChange)} Compressed ${filePaths.length} HTML files in ${Math.round(timeEnd - timeStart)}ms`, ) }, }, } satisfies AstroIntegration }