- Published on ·
- Time to read
- 5 minute read
Perf Protip: Eliminate Unused Icons with fontmin
- Authors
- Name
- Patrick Hulce
- @patrickhulce
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! 🤔