Asset Modules is a type of module that allows to use asset files (fonts, icons, etc) without configuring additional loaders.
Prior to webpack 5 it was common to use:
raw-loader to import a file as a stringurl-loader to inline a file into the bundle as a data URIfile-loader to emit a file into the output directoryAsset Modules type replaces all of these loaders by adding 4 new module types:
asset/resource emits a separate file and exports the URL. Previously achievable by using file-loader.asset/inline exports a data URI of the asset. Previously achievable by using url-loader.asset/source exports the source code of the asset. Previously achievable by using raw-loader.asset automatically chooses between exporting a data URI and emitting a separate file. Previously achievable by using url-loader with asset size limit.This is an experimental feature. Enable Asset Modules by setting
experiments.asset: truein experiments option of your webpack configuration.
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
+ experiments: {
+ asset: true
+ },
};
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
experiments: {
asset: true
},
+ module: {
+ rules: [
+ {
+ test: /\.png/,
+ type: 'asset/resource'
+ }
+ ]
+ },
};
src/index.js
import mainImage from './images/main.png';
img.src = mainImage; // '/dist/151cfcfa1bd74779aadb.png'
All .png files will be emitted to the output directory and their paths will be injected into the bundles.
By default, asset/resource modules are emitting with [hash][ext] filename into output directory.
You can modify this template by setting output.assetModuleFilename in your webpack configuration:
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
+ assetModuleFilename: 'images/[hash][ext]'
},
experiments: {
asset: true
},
module: {
rules: [
{
test: /\.png/,
type: 'asset/resource'
}
]
},
};
Another case to customize output filename is to emit some kind of assets to a specified directory:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
+ assetModuleFilename: 'images/[hash][ext]'
},
experiments: {
asset: true
},
module: {
rules: [
{
test: /\.png/,
type: 'asset/resource'
- }
+ },
+ {
+ test: /\.html/,
+ type: 'asset/resource',
+ generator: {
+ filename: 'static/[hash][ext]'
+ }
+ }
]
},
};
With this configuration all the html files will be emitted into a static directory within the output directory.
Rule.generator.filename is the same as output.assetModuleFilename and works only with asset and asset/resource module types.
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
- assetModuleFilename: 'images/[hash][ext]'
},
experiments: {
asset: true
},
module: {
rules: [
{
- test: /\.png/,
- type: 'asset/resource'
+ test: /\.svg/,
+ type: 'asset/inline'
- },
+ }
- {
- test: /\.html/,
- type: 'asset/resource',
- generator: {
- filename: 'static/[hash][ext]'
- }
- }
]
}
};
src/index.js
- import mainImage from './images/main.png';
+ import metroMap from './images/matro.svg';
- img.src = mainImage; // '/dist/151cfcfa1bd74779aadb.png'
+ block.style.background = `url(${metroMap})`; // url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo...vc3ZnPgo=)
All .svg files will be injected into the bundles as data URI.
By default, data URI emitted by webpack represents file contents encoded by using Base64 algorithm.
If you want to use a custom encoding algorithm, you may specify a custom function to encode a file content:
webpack.config.js
const path = require('path');
+ const svgToMiniDataURI = require('mini-svg-data-uri');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
experiments: {
asset: true
},
module: {
rules: [
{
test: /\.svg/,
type: 'asset/inline',
+ generator: {
+ dataUrl: content => {
+ content = content.toString();
+ return svgToMiniDataURI(content);
+ }
+ }
}
]
},
};
Now all .svg files will be encoded by mini-svg-data-uri package.
webpack.config.js
const path = require('path');
- const svgToMiniDataURI = require('mini-svg-data-uri');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
experiments: {
asset: true
},
module: {
rules: [
{
- test: /\.svg/,
- type: 'asset/inline',
- generator: {
- dataUrl: content => {
- content = content.toString();
- return svgToMiniDataURI(content);
- }
- }
+ test: /\.txt/,
+ type: 'asset/source',
}
]
},
};
src/example.txt
Hello world
src/index.js
- import metroMap from './images/matro.svg';
+ import exampleText from './example.txt';
- block.style.background = `url(${metroMap}); // url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo...vc3ZnPgo=)
+ block.textContent = exampleText; // 'Hello world'
All .txt files will be injected into the bundles as is.
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
experiments: {
asset: true
},
module: {
rules: [
{
+ test: /\.txt/,
+ type: 'asset',
}
]
},
};
Now webpack will automatically choose between resource and inline by following a default condition: a file with size less than 8kb will be treated as a inline module type and resource module type otherwise.
You can change this condition by setting a Rule.parser.dataUrlCondition.maxSize option on the module rule level of your webpack configuration:
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
experiments: {
asset: true
},
module: {
rules: [
{
test: /\.txt/,
type: 'asset',
+ parser: {
+ dataUrlCondition: {
+ maxSize: 4 * 1024 // 4kb
+ }
+ }
}
]
},
};
Also you can specify a function to decide to inlining a module or not.