Published on
·
Time to read
5 minute read

Perf Protip: Eliminate Unused Icons with fontmin

Blog post image
Authors

Webfonts are an essential part of modern web design, but every time I use them I find myself with an enormous amount of guilt due to their significant impact on web performance.

So I made a better way! Introducing fontmin-webpack. Fontmin is a package that reexports a TrueType-based font with only the glyphs that you specify (i.e. it minifies it). fontmin-webpack is a plugin for webpack that automatically scans your assets for usages of particular glyphs and passes those to fontmin before exporting your font assets. This can be a godsend for icon fonts, which can often have used only a handful glyphs.

In this blog post, we will go over the steps to install and use fontmin-webpack to optimize your icon fonts and improve the performance of your site.

Step 1: Installation

To use fontmin-webpack, you first need to install it as a development dependency in your project:

npm install fontmin-webpack --save-dev

Step 2: Use an Icon Font

Next, include the font you want to minify from your application's JavaScript. The example below uses glyphs \uf0c7 and \uf0ce from FontAwesome.

Protip: You can avoid manually specifying font glyphs by using an automated unused CSS tool.

entry.js

require('./fonts.css')
require('./app.js')

fonts.css

@font-face {
  font-family: 'FontAwesome';
  src: url('fontawesome-webfont.eot') format('embedded-opentype'), url('fontawesome-webfont.woff2')
      format('woff2'), url('fontawesome-webfont.woff') format('woff'), url('fontawesome-webfont.ttf')
      format('ttf');
}

/**
 * Remove other unused icons from the file.
 */
.fa-save:before,
.fa-floppy-o:before {
  content: '\f0c7';
}
.fa-table:before {
  content: '\f0ce';
}

Step 3: Webpack Configuration

Next, you need to configure fontmin-webpack in your webpack configuration file. In this example, we will be using an icon font called "my-icons.ttf" that is located in the "src/fonts" folder:

const FontminPlugin = require('fontmin-webpack')

module.exports = {
  entry: `${__dirname}/entry.js`,
  output: { filename: 'out.js', path: `${__dirname}/dist` },
  module: {
    rules: [
      {
        test: /\.(woff|woff2)(\?v=.+)?$/,
        use: {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]?[contenthash]',
          },
        },
      },
      { test: /\.(svg|ttf|eot|png)(\?v=.+)?$/, use: ['file-loader'] },
      { test: /\.css$/, use: ['style-loader', 'css-loader'], include: __dirname },
    ],
  },
  plugins: [
    new FontminPlugin({
      autodetect: true, // automatically pull unicode characters from CSS
      glyphs: ['\uf0c8' /* extra glyphs to include */],
      // note: these settings are mutually exclusive and allowedFilesRegex has priority over skippedFilesRegex
      allowedFilesRegex: null, // RegExp to only target specific fonts by their names
      skippedFilesRegex: null, // RegExp to skip specific fonts by their names
      textRegex: /\.(js|css|html)$/, // RegExp for searching text reference
      webpackCompilationHook: 'thisCompilation', // Webpack compilation hook (for PurgeCss webpack plugin use 'compilation' )
    }),
  ],
}

In this configuration, we are using the file-loader to copy the font file to the "dist/" folder and the fontmin-webpack loader to optimize the font. The "text" option is used to specify the prefix of the icon class names, in this case "icon-".

Results

By using fontmin-webpack to eliminate unused glyphs from your icon fonts, you can significantly improve the performance of your website.

Before

674f50d287a8c48dc19ba404d20fe713.eot     166 kB          [emitted]
912ec66d7572ff821749319396470bde.svg     444 kB          [emitted]  [big]
b06871f281fee6b241d60582ae9369b9.ttf     166 kB          [emitted]
af7ae505a9eed503f8b8e6982036873e.woff2  77.2 kB          [emitted]
fee66e712a8a08eef5805a46892932ad.woff     98 kB          [emitted]

After

674f50d287a8c48dc19ba404d20fe713.eot    2.82 kB          [emitted]
912ec66d7572ff821749319396470bde.svg    2.88 kB          [emitted]
b06871f281fee6b241d60582ae9369b9.ttf    2.64 kB          [emitted]
af7ae505a9eed503f8b8e6982036873e.woff2  1.01 kB          [emitted]
fee66e712a8a08eef5805a46892932ad.woff   2.72 kB          [emitted]

Now we just have to figure out how to get it working with URL loader to eliminate that pesky render-blocking request! 🤔