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 underparser.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 stringRemember
- 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.