Optimize Astro HTML post build

Enhance your Astro builds: modify HTML files post-build

Seppe Gadeyne

Freelance web developer

As Astro developers, we're always looking for ways to optimize our websites and improve performance. In this blog post, I'll walk you through a script that can modify your Astro-generated HTML files after the build process. This script adds IDs to heading tags and minifies the HTML, making your website faster and more accessible. Let's dive in!

Optimize Astro HTML post build
Optimize Astro HTML post-build for an even faster website

Contents

  1. Getting started

  2. Installing dependencies

  3. The process-html.mjs script

  4. Updating package.json

  5. Conclusion

Getting started

Before you can begin, ensure that you have the following prerequisites installed on your system:

Installing dependencies

Our script relies on three dependencies: 'globby', 'html-minifier', and 'jsdom'. Install them by running the following command:

npm install globby html-minifier jsdom

The process-html.mjs script

Create a new file named process-html.mjs in your Astro project's root directory. The code below is tailored for static deployments on Vercel. If you're using a different output folder, modify the path variable accordingly.

import fs from 'node:fs/promises'
import { globby } from 'globby'
import { minify } from 'html-minifier'
import { JSDOM } from 'jsdom'

// Get all HTML files from the output directory
const path = './.vercel/output/static'
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')

   	 // Add IDs to h2, h3, and h4 tags
   	 const dom = new JSDOM(html)
   	 const headings = dom.window.document.querySelectorAll('h2, h3, h4')
   	 for (let i = 0; i < headings.length; i++) {
   		 const heading = headings[i]
   		 const text = heading.textContent
   		 const id = text
   			 .trim()
   			 .replace(/[\s.,?:]+/g, '-')
   			 .replace(/-+$/, '')
   			 .toLowerCase()
   		 heading.setAttribute('id', id)
   	 }
   	 html = dom.serialize()

   	 // Minify the HTML
   	 html = minify(html, {
   		 removeComments: true,
   		 preserveLineBreaks: true,
   		 collapseWhitespace: true
   	 })
   	 await fs.writeFile(file, html)
    })
)

Updating package.json

Update your package.json file to execute the script after the build process. Add && node process-html.mjs after, astro build as shown in the example below.

{
	"name": "astro-process-html",
	"type": "module",
	"version": "0.0.1",
	"scripts": {
		"dev": "astro dev",
		"start": "astro dev",
		"build": "astro build && node process-html.mjs",
		"preview": "astro preview",
		"astro": "astro"
	},
	"dependencies": {
		"astro": "~2.1.3",
		"@astrojs/vercel": "~3.2.1",
		"globby": "~13.1.3",
		"html-minifier": "~4.0.0", 
        "jsdom": "~21.0.0" 
    } 
}

Conclusion

Following these steps, you've successfully created a script that modifies your Astro-generated HTML files after the build process. This enhancement will add IDs to heading tags and minify your HTML, improving the performance and accessibility of your website. Don't hesitate to customize the script further to meet your specific needs, and check out the html-minifier reference guide for additional configuration options. Feel free to reach out if you have any questions or need further assistance! Happy coding! 😉

Frequently asked questions

FAQ

Let's dive deeper into some frequently asked questions.

Can I use this script with other static site generators?

While this script is tailored for Astro, you can adapt it to work with other static site generators by modifying the path variable to match the output directory of your preferred SSG.

Can I add more tasks to this script?

Absolutely! You can expand the script's functionality to include tasks such as adding critical CSS or optimizing images. Just install any necessary dependencies and integrate them into the script.

What if I want to add IDs to different HTML elements?

You can modify the querySelectorAll method within the script to target different elements. For example, change 'h2, h3, h4' to 'h1, h2, h3' and target <h1>, <h2>, and <h3> elements instead.

Can I exclude certain files or directories from processing?

Yes, you can do this by adjusting the globby pattern. Refer to the globby documentation for more information on creating custom patterns.