Learn Eleventy

Lesson 21: Adding minification

For a little extra performance, we'll be adding minification for our CSS and HTML. Minification removes extra spaces, newlines, and comments to make the files as small as possible.

Adding a HTML minification transform

We’re going to use a handy Eleventy feature called Transforms. Transforms are a bit like filters where we take the input, pass it though the Transform and then get the transformed output back in return. The Eleventy Image plugin from the last lesson itself uses Transforms under the hood, so we already know how powerful they can be.

We’re going to grab each page as it’s built and minify the HTML, only if we are in production mode. The reason why we only minify HTML in production mode is because this upcoming function is pretty heavy-duty, for understandable reasons, so it makes sense to only run it once per page.

Now, in our eleventy.config.js configuration file, start by importing the following import at the top:

import htmlmin from 'html-minifier-next';

Above the start of the configuration function, add this variable declaration:

const isProduction = process.env.NODE_ENV === 'production';

This is a flag we can use to tell if our build is running in production mode. To make this work, we'll need to add a new production script to run our build in production mode.

Open up eleventy-from-scratch/package.json and add the following line at the end of the "scripts": { block, on a new line between lines 4 and 5:

"production": "NODE_ENV=production npm run build"

You'll need to add a comma at the end of the previous line, after "build": "eleventy", for the JSON to be valid.

It should now look like this:

"scripts": {
	"start": "eleventy --serve",
	"build": "eleventy",
	"production": "NODE_ENV=production npm run build"
},

Back in the configuration function, add the transform itself:

if (isProduction) {
	eleventyConfig.addTransform('htmlmin', function (content) {
		if ((this.page.outputPath || '').endsWith('.html')) {
			return htmlmin.minify(content, {
				useShortDoctype: true,
				removeComments: true,
				collapseWhitespace: true,
			});
		}
		return content;
	});
}

We’re determining whether or not we’re in production mode, and adding our Transform if we are.

What the function does is first check each page to see if it’s an HTML file. If not, it returns it out, untouched. If it is a HTML file, it runs it through a package called html-minifier-next, which gives us back some nice compressed HTML in return.

We’ve got a new package here, so let’s install it. In your terminal, run the following:

npm install html-minifier-next@v4

That's it!

Adding a CSS minification step

We're also going to want to minify our CSS files and the CSS bundled within our HTML. Instead of adding a transform, we will update our compile function for Sass templates.

In our eleventy.config.js file, replace our existing eleventyConfig.addExtension for scss on lines 31 to 53 with the following:

eleventyConfig.addExtension('scss', {
	outputFileExtension: 'css',
	useLayouts: false,
	compile: async function (inputContent, inputPath) {
		let parsed = path.parse(inputPath);
		// Don’t compile file names that start with an underscore
		if (parsed.name.startsWith('_')) {
			return;
		}

		const compiled = sass.compileString(inputContent, {
			loadPaths: [parsed.dir || '.', this.config.dir.includes],
			silenceDeprecations: ['import', 'global-builtin', 'slash-div']
		});

		let result = compiled.css;
		if (isProduction) {
			const minified = await postcss([cssnano]).process(compiled.css, {
				from: undefined,
			});
			result = minified.content;
		}

		// Map dependencies for incremental builds
		this.addDependencies(inputPath, compiled.loadedUrls);

		return async (data) => {
			return result;
		};
	},
});

Our new compile function adds an extra step to run the Sass compiled result through PostCSS and cssnano, if the build is in production mode. cssnano is a plugin for PostCSS, an extensible CSS transformation tool, that adds minification.

For this compile function to work, add the following alongside the other imports at the top of the file:

import postcss from 'postcss';
import cssnano from 'cssnano';

We'll need to install these two new dependencies:

npm install postcss@v8 cssnano@v7

Wrapping up

With those two minification steps wired up, it's time to see what they do!

In your terminal, stop Eleventy by pressing Ctrl + C. Then, run npm run build. Take a peek at what our output files in the dist folder look like.

Now, run npm run production. This is the new script we added just a moment ago, which sets the NODE_ENV environment variable to production and enables our new minification steps. If you inspect our output files this time, you should see some very packed CSS and HTML on a single very looong line — sweet!

A block of compressed, minified HTML