Posted 5 months ago. Visible to the public.

Minify Font Awesome fonts with webpack

Font Awesome 5 is a comprehensive solution for vector icons on your website.

Originally, Font Awesome came as an icon font (plus stylesheets), but recently it can also be used as a pure JavaScript solution (which will render icons as inline <svg> tags), or even as SVG sprites.

All solutions have their pros and cons:

Icon font:

  • little CPU load (no JavaScript)
  • fonts are relatively large
  • 1 extra HTTP request

Javascript + inline SVG:

  • higher CPU load (needs to watch the DOM via mutation observers to add icons)
  • small file size due to in-built ability to only include the icons you use (if you use webpack 2, or another packager with tree-shaking)
  • no extra HTTP requests

SVG sprites:

  • largest file size, hard to subset
  • 1 extra HTTP request

In practice there are probably additional performance tradeoffs.

Luckily, there is a webpack plugin that will subset an icon font "on the fly" to remove all unused glyphs. However, there is (currently) on major caveat: When subsetting the font, the (digest) hash of the compiled font will not change. That means that if you add a new icon, browsers will not automatically reload the expanded font. There is a workaround at the bottom, but it is not very pretty.

In my opinion using this plus the icon font you get the best of all worlds, with low CPU usage, no JavaScript, and file-sizes in the one-digit kB range.

You can set it up like this:

Add npm modules

  • add @fortawesome/fontawesome-free
  • add @fontmin-webpack. For webpack 3, use version ^1.0.2.

Load the fontmin plugin

Add the plugin in your webpacker config (example for webpacker)

Copy
const FontminPlugin = require('fontmin-webpack') environment.plugins.append( 'Fontmin', new FontminPlugin({ autodetect: true, }) )

Only include the icons you need

Fontmin-webpacker works by only keeping glyphs it sees in your CSS content attributes. To make this work, you need to selectively only add the icons you require in your CSS.

Create and require a file font-awesome.scss with the following content:

Copy
$fa-font-path: '~@fortawesome/fontawesome-free/webfonts'; @import '~@fortawesome/fontawesome-free/scss/variables'; @import '~@fortawesome/fontawesome-free/scss/mixins'; @import '~@fortawesome/fontawesome-free/scss/core'; // you can pick and choose the features you actually need: @import '~@fortawesome/fontawesome-free/scss/larger'; @import '~@fortawesome/fontawesome-free/scss/fixed-width'; @import '~@fortawesome/fontawesome-free/scss/list'; @import '~@fortawesome/fontawesome-free/scss/bordered-pulled'; @import '~@fortawesome/fontawesome-free/scss/animated'; @import '~@fortawesome/fontawesome-free/scss/rotated-flipped'; @import '~@fortawesome/fontawesome-free/scss/stacked'; @import '~@fortawesome/fontawesome-free/scss/screen-reader'; // the fonts itself, perhaps you only need "solid" @import '~@fortawesome/fontawesome-free/scss/regular'; @import '~@fortawesome/fontawesome-free/scss/solid'; @import '~@fortawesome/fontawesome-free/scss/brands'; // add your icons here $used-icons: ( bars: $fa-var-bars, calendar: $fa-var-calendar, search: $fa-var-search, ); @each $name, $content in $used-icons { .#{$fa-css-prefix}-#{$name}:before { content: fa-content($content); } }

Workaround for digest issue

As mentioned, if you add additional icons, the filename of the generated icon font will not change. This means browser will keep using the cached font and not see new icons. When deploying with capistrano, the following workaround will cause a new font file to be generate on every deploy:

Add the following to your config/webpacker/environment.js (if using webpacker):

Copy
const fs = require('fs') let iconFontVersion = 'dev' try { iconFontVersion = fs.readFileSync('REVISION', 'utf-8').trim() } catch(_error) { // okay, probably in dev mode } environment.loaders.prepend('fa-font', { test: /fa-.*\.(woff2|woff|eot|svg|ttf)$/, use: [{ loader: 'file-loader', options: { name: '[path][name]-[hash]-' + iconFontVersion + '.[ext]', context: join(config.source_path), } }] }) environment.loaders.get('file').exclude = /fa-.*\.(woff2|woff|eot|svg|ttf)$/

makandra has been working exclusively with Ruby on Rails since 2007. Our laser focus on a single technology has made us a leader in this space.

Owner of this card:

Avatar
Tobias Kraze
Last edit:
4 months ago
by Tobias Kraze
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Tobias Kraze to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more