Files
armandine/scripts/critical-css.js
mifi 7870d3b3bd
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/deploy Pipeline was successful
Prettier
2026-02-16 10:01:29 -03:00

74 lines
2.3 KiB
JavaScript

/**
* Inline critical CSS into built HTML using Beasties.
* Run after vite build; reads/writes build/.
*/
import { readFileSync, writeFileSync, readdirSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { log, error } from 'node:console';
import process from 'node:process';
import Beasties from 'beasties';
const __dirname = dirname(fileURLToPath(import.meta.url));
const buildDir = join(__dirname, '..', 'build');
function getFiles(dir, ext, files = []) {
for (const name of readdirSync(dir, { withFileTypes: true })) {
const full = join(dir, name.name);
if (name.isDirectory()) getFiles(full, ext, files);
else if (name.name.endsWith(ext)) files.push(full);
}
return files;
}
const beasties = new Beasties({
path: buildDir,
preload: 'default',
logLevel: 'warn',
inlineThreshold: 50 * 1024,
minimumExternalSize: 50 * 1024
});
/**
* Remove SvelteKit wrapper div and Svelte SSR fragment comments from HTML.
* With csr = false these add noise and the inline style is unnecessary.
*/
function cleanHtml(html) {
// Remove extra SvelteKit body attribute: data-sveltekit-preload-data="hover"
html = html.replace(/<body\s+data-sveltekit-preload-data\s*=\s*["']hover["']\s*>/i, '<body>');
// Remove SvelteKit's root wrapper: <div style="display: contents"> ... </div>
html = html.replace(/<div\s+style\s*=\s*["']display:\s*contents["']\s*>/i, '');
const bodyEnd = html.indexOf('</body>');
if (bodyEnd !== -1) {
const beforeBody = html.slice(0, bodyEnd);
const lastDiv = beforeBody.lastIndexOf('</div>');
if (lastDiv !== -1) {
html = beforeBody.slice(0, lastDiv) + beforeBody.slice(lastDiv + 6) + html.slice(bodyEnd);
}
}
// Remove Svelte fragment/hydration comments (unused when csr = false)
html = html
.replace(/<!--\[-->/g, '')
.replace(/<!--\]-->/g, '')
.replace(/<!--\[!-->/g, '')
.replace(/<!--\]!-->/g, '')
.replace(/<!---->/g, '');
return html;
}
async function main() {
const htmlFiles = getFiles(buildDir, '.html');
for (const htmlFile of htmlFiles) {
let html = readFileSync(htmlFile, 'utf8');
html = await beasties.process(html);
html = cleanHtml(html);
writeFileSync(htmlFile, html);
}
log('Critical CSS inlined:', htmlFiles.length, 'file(s)');
}
main().catch((err) => {
error(err);
process.exit(1);
});