Asset modules: images, fonts and files

webpack · Essentials · 10 min

Every app ships images and fonts, and webpack 5 handles them without extra loaders.

webpack 5 replaced file-loader, url-loader and raw-loader with built-in asset modules, selected with a rule's type:

  • asset/resource: emits the file to the output directory and exports its URL (formerly file-loader).
  • asset/inline: exports a data URI (formerly url-loader).
  • asset/source: exports the file's contents as a string (formerly raw-loader).
  • asset: chooses automatically: files under parser.dataUrlCondition.maxSize (8 KB by default) are inlined, larger ones emitted.

Output names come from output.assetModuleFilename (default [hash][ext][query]) or a rule's generator.filename, e.g. images/[name].[contenthash][ext].

You can then import logoUrl from "./logo.png" in JavaScript, and url(./bg.png) in CSS is handled by css-loader through the same rules. new URL("./file.png", import.meta.url) also works and is the bundler-agnostic way.

Choosing between inline and resource is a trade-off: inlining saves a request but increases bundle size and bypasses separate caching; keep it for tiny icons. For SVGs used as React components, add @svgr/webpack. Remove old file-loader rules when migrating, or assets get processed twice.

Example

// webpack.config.js
module.exports = {
  mode: "production",
  output: { assetModuleFilename: "assets/[name].[contenthash][ext]" },
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|webp|svg)$/i,
        type: "asset",                          // inline if small, else a file
        parser: { dataUrlCondition: { maxSize: 4 * 1024 } },
      },
      { test: /\.(woff2?|ttf)$/i, type: "asset/resource" },
      { test: /\.txt$/i, type: "asset/source" },
    ],
  },
};
// src/index.js
// import logoUrl from "./logo.png";   // "/assets/logo.8f3a1c2b.png" or "data:image/png;base64,..."
// import licence from "./LICENSE.txt"; // file contents as a string

Remember

  • asset/resource = file + URL, asset/inline = data URI
  • asset/source = contents as string, asset = automatic by size
  • Name files via assetModuleFilename or generator.filename
  • Drop file-loader/url-loader when on webpack 5

Watch out for

  • Keeping legacy file-loader rules alongside asset modules, so files are emitted twice.

Check yourself

  1. Which asset type inlines small files and emits larger ones?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: webpack.js.org/guides/asset-modules/