Favicon Gremlins in Static Web Apps + Webpack

Favicons, or as I like to call them, image gremlins from hell, can be mildly frustrating to add to your application. I successfully conquered the little beasts, so I figured I owed it to the community to share how I vanquished them.

The rare cute gremlin in the wild. Photo by Mukesh Jain on Unsplash

The back story

I normally build front end applications using React, but lately I’ve been working on a static website using plain HTML, CSS, and JavaScript. I played with Gulp, but found myself missing the extensibility of Webpack. So I switched to Webpack, thereby signing myself up for an Odyssean adventure.

You see, most people don’t use Webpack as a build tool for static web apps. I’ll save that how-to post for another day. In the meantime, I hope this niche post helps those of you in the same predicament or even others that use Webpack in a more traditional JavaScript setting.

Step 1: Cheat

Don’t attempt to generate your own favicons. This is not the 1990’s when you could get away with just one favicon.ico file. You need like 4236* now.

Gremlins can be many sizes. Just don’t add water. Photo by Jakob Owens on Unsplash

*I’m lying (it’s more like 27 at the time of writing), but they do seem to grow at an exponential rate. Just like gremlins. So don’t add water.

Create the image you want to use as the basis for all your favicons. For the best results, it should be at least 260x260.

Next, sail over to RealFaviconGenerator and select your base favicon image.

RealFaviconGenerator https://realfavicongenerator.net/

This is the best part… they generate all 4236* files that you need to serve up favicons for all browsers and platforms! Plus they give you the 324** lines of code you need to add to the head of your HTML!

** Again, I might be exaggerating (it’s more like 16 at the time of writing).

Download the zip file containing all your images.

Copy those lines of code into the head of every html file in your project (the joys of using no front-end framework never cease).

A note on my current Webpack set up

Before we dig into how to handle the favicons, let me give you a flavor of my current Webpack set up so that you can determine which of my steps are relevant to your application.

This is a static website hosted on S3. So I have HTML files for every page. All of the markup is in HTML — not JavaScript or JSX. JavaScript is only used in the old school way for adding behavior like mobile nav, carousels, async requests, and animations. Thus, I use file-loader + extract-loader + html-loader for loading, extracting, resolving URLs (e.g., for <img> sources), and building my HTML files:

Since I’m using Webpack, I need a JavaScript way to trigger Webpack that my HTML files should be used. Thus, I require them in my entry point files, like the following index.js file which will contain or load all the JavaScript required for my index.html page.:

// index.js
require('../index.html');

Finally, I have entry points set up for each code split. What do I mean? Well, my index page has a lot more JavaScript than many of the basic pages need. So it has a separate index.js entry point. Most of the basic pages just need the same basic stuff, so they share the base.js file in which I have a require statement for every page’s HTML file. Sometimes, I need a special feature for just one page, so I create a separate entry point just for that page, like specialPage below:

Step 2: Add the favicons

Unzip the file you downloaded from RealFaviconGenerator, and copy or move the contents to a separate folder in your app or src directory. In my app, it is called app/favicons/. We create a separate directory because we want a super easy way to pass all these files to the root of our build folder for optimal treatment by all browsers.

Put all your gremlins in one basket. Photo by Paul on Unsplash

Now is when you’re probably wondering, “Do I need to write a require statement for all 4236* files?!?!?!”. No. Please use the powers of software engineering to help you. Create a helper file that programmatically loads all files in the app/favicons/ directory for you (of course, change the path according to your application set up):

Finally, add it to your each of your entry point files, like so:

// index.js
require('../index.html');
require('./helpers/favicons')

Step 3: Adjust Webpack config

Finally, we need to tell Webpack what to do and what not to do with these files:

  1. Simply copy all the files to the root of the build folder using file-loader
  2. Don’t do any extra image processing that we may do on other images, or exclude them from other rules

Here is my sample set up:

But why… ?

Why didn’t I use a static site generator or template engine? The client dictated no special tools, just plain HTML, CSS, and JavaScript.

Why didn’t I use my image loader for my favicons with hashes to make cache invalidation easier? Because unfortunately, I haven’t figured out a way for Webpack to resolve the href attribute for a <link> yet. If you know how, please let me know!

Why didn’t I use favicons-webpack-plugin? It wouldn’t automatically update my HTML in this setup. I also didn’t want to add a bunch of extra dependencies slowing down my dev builds when this method was just as easy.

Beware of friendly-looking gremlins. Photo by Wang Xi on Unsplash.

I’d love to hear how you vanquish your own gremlins or if you find an improvement on this method for static apps — please share in the comments!

If you liked this story, give it a 👏 to share the love.