blog.jakoblind.no

Load images and fonts with Webpack file loader like a pro

webpack file loader is a loader used mainly for supporting images such as SVG and PNG, and fonts in your webpack project.

There are different configurations for webpack 4 and webpack 5. We start with webpack 4, if you are using webpack 5 then scroll down to webpack 5 section

How to configure support for SVG using webpack 4 file loader

The first thing we are going to do is to install the webpack file loader dependency:

npm install --save-dev file-loader

Next, we are going to add the file loader to our webpack config:

module: {
    rules: [
      {
        test: /\.svg$/,
        use: 'file-loader'
      }
    ]
  }

(See the complete webpack.config.js for SVG on createapp.dev)

This config has a test section that tells which files should be processed by the webpack file loader. In this case, it’s all files ending with .svg. Webpack goes through all the imported and required files in your project, and for all those files which have a .svg extension, it uses as an input to the webpack file loader. For each of these files, the file loader emits the file in the output directory and resolves the correct URL to be referenced.

With this webpack config in place, we now can access SVG files in the app. Let’s look into how we can do that.

First, we’ll add some SVG image files to our project. If you want an example you can use this:

Put this file in the src folder of your project.

Now first import this image at the top of your javascript file where you want to use this image.

import winampImg from "./winamp.svg"

If you have a React app, you can now view this file from your JSX:

<img src={winampImg} />

If you use other frameworks, the same principle applies. Use winampImg to get the path of the image.

PNG support for webpack 4 file loader

The configuration for PNG support is very similar to SVG support. You just need to change the webpack.config.js to run the webpack file loader for all files ending with .png. Like this:

module: {
    rules: [
      {
        test: /\.png$/,
        use: 'file-loader'
      }
    ]
  }

The rest of the setup is identical to SVG. Here is a sample PNG image if you need it for testing:

Use this image just like in the example with PNG above.

webpack file loader for fonts

You can also use webpack file loader to get support for fonts such as woff, woff2, tff, eot. It’s very similar to how we configure file loader for loading images.

module: {
    rules: [
      {
        test: /\.(woff|woff2|ttf|eot)$/,
        use: 'file-loader'
      }
    ]
  }

The principle for how webpack file loader works for fonts is very similar to how it works for images. This configuration looks for any font file ending in .woff, .woff2, ttf or eot and copies it to the output directory. It also makes sure the correct URL path is referenced.

So let’s look at how we can use the fonts.

The most common way to access the fonts is from your CSS file. You can check out my article on how to configure webpack CSS , or see a complete webpack app with CSS and React on createapp.dev

First, download a font. I used Gemunu Libre for testing because I thought it looked pretty cool. Download it, unzip it, and put the ttf file in your src folder.

Now you can reference your font from the CSS, like this:

@font-face {
  font-family: "MyWebFont";
  src: url("GemunuLibre-VariableFont_wght.ttf") format("woff2");
}

body {
  font-family: "MyWebFont", Fallback, sans-serif;
}

To learn more about how to configure fonts with CSS, check out this article about font-face.

Note that this config only works for webpack 4, if you are using webpack 5, then continue reading.

Configuration for webpack 5 file loader

Webpack 5 has deprecated the file-loader. If you are using webpack 5 you should do some adjustments to your configuration. You should change use: 'file-loader', to type: 'asset/resource'. That means your webpack config for PNG would look like this:

module: {
    rules: [
      {
        test: /\.png$/,
        type: 'asset/resource'
      }
    ]
  }

Also, you no longer need to add the file-loader dependency in package.json.

When you have made the config to your webpack config, you can access PNG files (or whatever files extensions you have configured) just as described earlier.

Configure file name and output path of webpack file-loader

So far we have used the most basic configuration of file-loader you can possibly make. This is fine for most cases. However, there are some configurations you can make. I’ll show you the most interesting ones here.

By default, file-loader renames each file it process to a filename with random characters. Then it puts the file in the root of the output folder. For example, in the example with the PNG file above, it creates a file dist/9df27b25b845b6677bf4cf3f78b88578.png even though the input filename was winamp.png.

We can change both the file name of the processed files and the output folder. We do that in an options section. Here is an example:

module: {
    rules: [
      {
        test: /\.png$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images'
        }
      }
    ]
  }

I have extended our example with the PNG file. There are two important things to note here. First I added the options section that I will come back to, and I’ve renamed use to loader. Webpack doesn’t accept having an options and a use at the same time. If you do, you get an error. I’m not completely sure why. I’ve digged into the docs but have not yet found a good reason. use and loader is more or less the same, so let’s just accept we have to do it this way when we use options.

Ok, back to the configuration. This new extended config now outputs all processed files in a subfolder called images. Also, it keeps the original file names. So in the case of the Winamp image, it’ll keep the file name winamp.png.

In this example, we used the two placeholders [name] and [ext]. There are more to choose from. Another useful placeholder is [contenthash] which gives you a hash of the file, for example 9df27b25b845b6677bf4cf3f78b88578. You can even get an emoji representation of the content by using the [emoji] placeholder which gives you something like 🇦🇩. I don’t think that one is very commonly used but funny that it exists.

There is a complete list of file-loader placeholders webpack in the webpack 4 docs

Are you using webpack 5? Then the configure is a little bit different, read more in asset-modules section of webpack 5 docs

webpack file-loader vs url-loader

Webpack 4 also has the concept url-loader. What is the difference between file-loader ? url-loader first base64 encodes the file and then inlines it. It will become part of the bundle. That means it will not output a separate file like file-loader does. To use url-loader you first have to install the dependency:

npm install --save-dev url-loader

Then you change your webpack.config.js to use the url-loader:

module: {
    rules: [
      {
        test: /\.png$/,
        use: 'url-loader'
      }
    ]
  }

Now if you run your app and inspect the elemnt of the img tag it will look something like this:

<img
  src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABGdBTUEAALGPC..."
/>

(I’ve shortened the string a bit, it’s longer in the browser)

It’s now inlined in the outputted HTML!

If you are using webpack 5, then url-loader is deprecated and instead, you should use asset/inline, like this:

module: {
    rules: [
      {
        test: /\.png$/,
        type: 'asset/resource'
      }
    ]
  }

Thank you for reading. Hope this helped some of your webpack file loader needs! Do you want to learn more about webpack? Join the webpack email course.


tags: