Minify Files in Metalsmith

Christian Emmer
Christian Emmer
Mar 26, 2020 · 3 min read

Minified files maintain all the functionality of their original source but optimize for size, which in turns means faster page loads and improved SEO - and it's a snap to do in Metalsmith.

See "Remove Unused Assets in Metalsmith" on removing unused assets entirely.

Remove Unused Assets in Metalsmith
Remove Unused Assets in Metalsmith
May 19, 2020 · 3 min read

Have assets in your source directory that are never used by your output? Save some space, get rid of them!

Project setup

To keep this article short and to the point we're not going to set up a full website, just enough to show sample usage. See "Starting a Metalsmith Project" for a more complete article on how to set up a Metalsmith project.

Starting a Metalsmith Project
Starting a Metalsmith Project
Sep 19, 2019 · 12 min read

Metalsmith is a plugin-based static site generator originally from Segment. It's a current favorite of mine because of how sites are built as a pipeline of plugins where the output of each plugin is the input of the next. This allows for strong control over what happens and when it happens.

Installing packages

Starting with an empty project, install some Metalsmith packages:

npm install --save metalsmith metalsmith-uglify metalsmith-css-unused metalsmith-clean-css metalsmith-renamer metalsmith-html-minifier

Source file structure

Create the following directories and files for use in the build pipeline:

.
├── index.js
└── src
    ├── index.html
    └── static
        ├── css
        │   └── styles.css
        └── js
            └── scripts.js

The names of the files aren't important as all HTML, CSS, and JavaScript files will be minified.

Fill in those files with some dummy content such as:

<!-- src/index.html -->

<!DOCTYPE html>
<html lang="en">
</html>
/* src/static/css/styles.css */

body {
    background: white;
}
// src/static/js/scripts.js

console.log('foo');
console.log('bar');

Writing the source files

Set up your index.js file like this:

const Metalsmith   = require('metalsmith');
const uglify       = require('metalsmith-uglify');
const cssUnused    = require('metalsmith-css-unused');
const cleanCSS     = require('metalsmith-clean-css');
const renamer      = require('metalsmith-renamer');
const htmlMinifier = require('metalsmith-html-minifier');

Metalsmith(__dirname)
    .source('./src')         // source directory for the pipeline
    .use(uglify({            // minify JavaScript files
        removeOriginal: true,
        uglify: {
            sourceMap: false
        }
    }))
    .use(cssUnused())        // remove unused CSS rules and combine files
    .use(cleanCSS({          // minify CSS files
        cleanCSS: {
            rebase: false
        }
    }))
    .use(renamer({           // rename minified CSS files
        css: {
            pattern: '**/*.css',
            rename: file => file.replace(/\.css$/, '.min.css')
        }
    }))
    .use(htmlMinifier({      // minify HTML files
        minifierOptions: {
            // Fix metalsmith-html-minifier defaults
            removeAttributeQuotes: false,
            // Additional minification rules
            minifyCSS: true,
            minifyJS: true,
            quoteCharacter: '"',
            removeScriptTypeAttributes: true,
            removeStyleLinkTypeAttributes: true
        }
    }))
    .destination('./build')  // destination directory of the pipeline
    .clean(true)             // clean the destination directory before build
    .build(function (err) {  // execute the build
        if (err) {
            throw err;
        }
    });

This will (in order):

  • Minify all /.js$/ (and not /.min.js$/) JavaScript files and change their extension to .min.js.
  • Remove unused CSS rules from all **/*.css files, based on the contents of all **/*.html HTML files.
  • Minify static/css/styles.css in-place without rebasing URLs.
  • Change the extension of all **/*.css (just static/css/styles.css) to .min.css.
  • Minify all **/*.html files in-place, including in-line CSS and JavaScript.
  • Copy src/index.html to build/index.html.

Build

Run the build command like normal:

node index

Then the resulting files will all be minified and ready for deployment!