Korte versie
Astro levert van zichzelf al compacte HTML: sinds Astro 7 haalt de standaardinstelling compressHTML witruimte rond elementen weg. Met een klein Node-script na astro build geef je alle h2- tot h4-koppen in je Astro-HTML een vaste anker-id en minificeer je wat overblijft met html-minifier-terser. Verwacht daarbij geen kleinere bestanden: op de 236 pagina's van deze site werd de build er 0,82% groter van.
Dit is een los voorbeeld voor statische Astro-projecten; deze site gebruikt het script niet in productie. Op 10 oktober 2026 heb ik het wel gedraaid op een kopie van de build van deze site, om te meten wat het met je Astro-HTML doet. Hieronder lees je hoe je het opzet, wat die meting liet zien en waar je moet opletten.
Wat heb je nodig om te starten?
Zorg voordat je begint dat je de volgende vereisten op je systeem hebt geïnstalleerd:
Afhankelijkheden installeren
Ons script is afhankelijk van drie pakketten: ‘globby’, ‘html-minifier-terser’ en ‘jsdom’. Installeer ze door het volgende commando uit te voeren:
npm install --save-dev globby html-minifier-terser jsdomHet process-html.mjs-script
Maak een nieuw bestand met de naam process-html.mjs in de hoofdmap van je Astro-project. De onderstaande code gebruikt Astro’s standaard statische uitvoermap dist. Als je een andere uitvoermap gebruikt, pas dan de path-variabele aan.
import fs from 'node:fs/promises'
import { globby } from 'globby'
import { minify } from 'html-minifier-terser'
import { JSDOM } from 'jsdom'
// Find all HTML files in the output folder
const path = './dist'
const files = await globby(`${path}/**/*.html`)
await Promise.all(
files.map(async (file) => {
console.log('Processing file:', file)
let html = await fs.readFile(file, 'utf-8')
// Preserve existing IDs and add unique IDs to other h2, h3 and h4 elements
const dom = new JSDOM(html)
const headings = dom.window.document.querySelectorAll('h2, h3, h4')
const usedIds = new Set(
[...dom.window.document.querySelectorAll('[id]')].map((element) => element.id)
)
for (const heading of headings) {
if (heading.id) continue
const baseId = heading.textContent
.normalize('NFKD')
.replace(/\p{Mark}+/gu, '')
.trim()
.toLowerCase()
.replace(/[^\p{Letter}\p{Number}]+/gu, '-')
.replace(/^-|-$/g, '') || 'section'
let id = baseId
let suffix = 2
while (usedIds.has(id)) id = `${baseId}-${suffix++}`
heading.setAttribute('id', id)
usedIds.add(id)
}
html = dom.serialize()
// Minify the resulting HTML
html = await minify(html, {
removeComments: false,
preserveLineBreaks: true,
collapseWhitespace: true,
})
await fs.writeFile(file, html)
})
)Bijwerken van package.json
Werk je package.json-bestand bij om het script uit te voeren na het bouwproces. Voeg && node process-html.mjs toe na astro build zoals weergegeven in het voorbeeld hieronder.
{
"name": "astro-process-html",
"type": "module",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build && node process-html.mjs",
"preview": "astro preview",
"astro": "astro"
}
}Wat levert het op in de praktijk?
Ik heb het script hierboven letterlijk gedraaid op een kopie van de build van deze site: 236 HTML-pagina’s, gebouwd met Astro 7.2.8 en de standaardinstelling voor compressHTML. De pakketversies waren globby 16.2.4, html-minifier-terser 7.2.0 en jsdom 30.1.2. Het resultaat is het omgekeerde van wat je verwacht: de Astro-HTML werd niet kleiner, maar groter.
| Meting | Vóór het script | Na het script | Verschil |
|---|---|---|---|
| Alle 236 HTML-bestanden | 31.807.539 bytes | 32.067.896 bytes | +0,82% |
| Zelfde bestanden met gzip | 6.573.834 bytes | 6.637.927 bytes | +0,97% |
| Zelfde bestanden met Brotli | 5.506.134 bytes | 5.562.603 bytes | +1,03% |
| Deze blogpagina | 153.257 bytes | 154.532 bytes | +0,83% |
| Toegevoegde heading-id's | – | 6.552 op 236 pagina's | op elke pagina |
De oorzaak zit in twee stappen. Alleen de minify-stap, met dezelfde opties, haalde over de hele build 408 bytes weg: Astro had de witruimte al opgeruimd. Alleen het parsen en opnieuw wegschrijven met jsdom maakte de bestanden samen 38.059 bytes groter, onder meer omdat jsdom elk leeg attribuut voluit schrijft (data-site-header wordt data-site-header=""). De rest komt van de nieuwe id’s. Het verwerken duurde 25,7 seconden.
Dat compressHTML al zoveel doet, staat ook in de Astro-documentatie:
Since v7.0, Astro applies by default the JSX whitespace rules used by frameworks like React.
De meerwaarde van het script zit dus niet in bytes, maar in de transformatie. Elke h2, h3 en h4 krijgt een vaste, unieke anker-id, zodat je overal naar een sectie kunt linken. Bestaande id’s blijven staan. Het voorbeeld verwijdert geen lege paragrafen of CMS-attributen; daarvoor is aanvullende, geteste logica nodig. Meet op je eigen build of de extra bytes de ankers waard zijn.
Welke valkuilen moet je kennen?
Bewaar HTML-comments wanneer je Svelte 5 of andere comment-gebaseerde hydratatie gebruikt. Daarom staat removeComments: false in dit voorbeeld. Zie de Svelte 5-migratiegids.
- Zet het script in je buildpipeline, niet in je dagelijkse werk. Elke build overschrijft de outputmap volledig, dus een handmatig gedraaide run verdwijnt bij de volgende deploy. Vandaar de aanpassing in package.json hierboven.
- Houd preserveLineBreaks: true aan. Zonder die optie klapt je hele HTML op één regel en wordt een diff of debugsessie op gebouwde bestanden bijna onmogelijk.
- jsdom parseert en serialiseert elke pagina opnieuw. Dat is veilig voor gewone HTML, maar test je hydratatie (Svelte- of framework-islands) na elke uitbreiding van het script. Controleer interactieve componenten en hun ankers na elke wijziging.
- collapseWhitespace kan in randgevallen een zichtbare spatie rond inline elementen weghalen. Controleer je design na de eerste run, zeker rond buttons en iconen die naast tekst staan.
- Verwacht geen kleinere bestanden. jsdom schrijft lege attributen voluit en elke nieuwe id kost bytes, dus op een Astro 7-build groeit je HTML eerder. Zet het script in voor de ankers, niet voor de bestandsgrootte.
Is er een alternatief voor het losse script?
Wil je alleen kleinere bestanden en geen heading-ankers, dan hoef je zelf niets te schrijven. Een bestaande integratie zoals @playform/compress zet html-minifier-terser samen met minifiers voor CSS, JavaScript, SVG en afbeeldingen in je Astro-build. Meet ook dan het verschil, want Astro heeft de HTML al grotendeels gecomprimeerd.
Wie dit netter vindt dan een los npm-script, pakt dezelfde logica in een Astro-integratie. Die draait op de astro:build:done-hook en krijgt de uitvoermap mee, zodat je geen paden hoeft te hardcoden. Je wint herbruikbaarheid (een integratie stop je in een package) en verliest een beetje eenvoud: voor één site is een los script prima, voor meerdere projecten loont de integratie.
Dit is alleen het integratieskelet, geen tweede volledig werkend script. Voeg de bestandsverwerking hierboven toe en zet de URL dir om met fileURLToPath uit node:url voordat je hem als globby-pad gebruikt. Gebruik dit alternatief niet tegelijk met het npm-postbuildscript.
// astro.config.mjs
import { defineConfig } from 'astro/config'
function processHtml() {
return {
name: 'process-html',
hooks: {
'astro:build:done': async ({ dir }) => {
// hier dezelfde globby- en minify-logica als in process-html.mjs,
// maar dan over alle .html-bestanden in de uitvoermap dir
},
},
}
}
export default defineConfig({
integrations: [processHtml()],
})Beide routes komen op hetzelfde neer: na de build over alle HTML-bestanden heen en elke pagina verwerken. Kies wat past bij hoe je projecten beheert.
Conclusie
Met een handjevol regels na de build krijg je vaste heading-ankers in al je Astro-HTML, elke deploy opnieuw. Kleinere bestanden krijg je er niet mee: Astro comprimeert de HTML zelf al, en op deze site groeide de build met 0,82%. Gebruik het script voor een concrete transformatie en meet het effect op je eigen build.
Wil je verder met snelheid, lees dan meer over de laadtijd van je website. En wil je dat dit soort pipelines iemand anders dagelijks onderhoudt, kijk dan bij websiteonderhoud of neem contact op voor vragen. Meer configuratieopties vind je in de referentiegids van html-minifier-terser.
Liever een volledig begeleid traject voor je Astro-project? Bekijk dan Astro website laten maken.

