'Webpack 5: file-loader generates a copy of fonts with hash-name
I cant figure out whats going on here. I use the file-loader to load the fonts of my application:
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/fonts/',
publicPath: '../fonts/'
}
}]
},
The fonts are also generated in the structure I specified: dist/assets/fonts.
outputPath: 'assets/fonts/'
... it seems to work correctly.
But: Webpack also packs the fonts with a hash as a name under /dist and sets the path in the CSS file to these files.
@font-face{font-family:"PaulGrotesk";font-style:normal;font-weight:400;src:url(../../d9bc4e30281429c0cddd.eot);
What is happening here? How can I prevent the additional files from being generated and used as a path?
I am using
- webpack: ^5.47.1
- webpack-cli: ^4.7.2
My webpack.config:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'assets/js/bundle_v1.0.0.js'
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
include: path.join(__dirname, 'index'),
options: {
presets: ['@babel/preset-env']
}
},
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/fonts/',
publicPath: '../fonts/'
}
}]
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
}
}
]
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
]
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'node_modules'),
/* https://webpack.js.org/configuration/resolve/ */
},
},
plugins: [
new MiniCssExtractPlugin({
filename: 'assets/css/bundle_v1.0.0.css'
}),
new HtmlWebpackPlugin({
inject: 'body',
template: './src/index.html',
filename: 'index.html',
})
]
};
Solution 1:[1]
I had the exact same issue as the OP (@toge) having migrated from Webpack 4 to 5. Whilst I was looking to implement the solution posted by @seanbun, I came across the following setup for the new Webpack 5 asset modules config that allowed me to get both my previous file-loader
svgs and font files to generate correctly without duplication in the root output folder:
{
test: /\.(woff(2)?|ttf|eot)$/,
type: 'asset/resource',
generator: {
filename: './fonts/[name][ext]',
},
},
This tells webpack to handle it via the asset modules config but output to a custom filepath, similar to how the file-loader
config used to work.
This setup also removed my need to downgrade css-loader
too which was an added benefit
Solution 2:[2]
Apparently, Webpack 5 has a Asset Modules
function which allows one to use asset files (fonts, icons, etc) without configuring additional loaders i.e. file-loader
, url-loader
and etc. The Asset Modules
provides four types to handle different type of asset. You can find more details at https://webpack.js.org/guides/asset-modules/.
So, when you add below rule for font files, the files are acutally handled by the Asset Modules
as well as the file-loader
.
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/fonts/',
publicPath: '../fonts/'
}
}]
}
In this case, we want to use our own file-loader
and disable the Asset Module
. We can set the type to 'javascript/auto'. This would follow your path setting and keep the font files in the assets/fonts
folder.
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
**type: "javascript/auto",**
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/fonts/',
publicPath: '../fonts/'
}
}]
}
P.S I was using css-loader 6.2.0
and had an error - url.replace is not a function
. I downgraded to css-loader 5.2.7
to resolve the issue.
Solution 3:[3]
Loaders are applied from last to first. So my guess is that placing the file loader below the css/sass loaders could fix the issue.
The fonts may not be registered this way when needed by the css loader and therefore loaded twice.
Solution 4:[4]
I already had my font files in a serveable location so I didn't need to copy the assets. (I'm confused why webpack did this by default). My solution was to ignore those files by:
new webpack.IgnorePlugin({
resourceRegExp: /\.(woff(2)?|ttf|eot|svg)$/
}),
Solution 5:[5]
I had similar problem but in my case problem was solved by "type:'asset/inline'"
{
test: /\.(woff|woff2|ttf|otf|eot)$/,
type:'asset/inline',
exclude: /node_modules/,
loader: 'file-loader',
options: {
esModule: false,
name: '[name].[ext]',
outputPath: '../assets/fonts/',
publicPath: '../assets/fonts/'
}
},
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | matthiasgiger |
Solution 4 | Joey Carlisle |
Solution 5 | Votech |