iconfont-webpack-plugin
iconfont-webpack-plugin copied to clipboard
Prints unicode character instead of icon
Using the default config suggested in the README
:
const IconFontPlugin = require('iconfont-webpack-plugin')
...
loader: 'postcss-loader',
options: {
plugins: loader => [new IconFontPlugin(loader)],
},
font-icon: url('../../static/images/icons/search.svg');
I am seeing the unicode character instead of the referenced svg as the content. Please advise on how I can fix to see the icon or what steps I can take to debug.
Hey @labbydev
it looks like you did everything correct 🤔
Can you try if it works for you with the scss-config-webpack-plugin
?
It is using this configuration in the background:
https://github.com/namics/webpack-config-plugins/blob/master/packages/scss-config-webpack-plugin/config/development.config.js
Adding in scss-config-webpack-plugin
just creates an error for all of my scss
files:
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: expected "{".
var api = require("!../../../../node_modules/scss-config-webpack-plugin/node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js");
It looks like perhaps the font file isn't correct. In the compiled result:
@font-face {
font-family: pin-Hb46a9;
src:url(\'!!/Users/[name]/Sites/[project]/node_modules/iconfont-webpack-plugin/lib/loader.js?{"svgs":["source/default/static/images/icons/search.svg","source/default/static/images/icons/close.svg"],"name":"pin-Hb46a9","enforcedSvgHeight":3000}!~/Users/[name]/Sites/[project]/node_modules/iconfont-webpack-plugin/placeholder.svg\') format(\'woff\');
font-weight: normal;
font-style: normal;
}
looks like the loader doesn't work - which webpack version do you use?
I'm using version 4 (specifically 4.44.2) of Webpack
In the example it works:
https://github.com/jantimon/iconfont-webpack-plugin/blob/master/example/default/webpack.config.js
I also created this codesandbox for you - maybe you can try to break it similar like on your project so we can find out what kind of configuration is causing it:
https://codesandbox.io/s/icon-font-webpack-plugin-ku3qz?file=/webpack.config.js
I have tried adding a copy of my webpack file in the sandbox here however, based on an inspect of the icon it doesn't appear to be using that configuration since it doesn't have the appropriate font name prefix appearing.
I've tried a number of configurations and this is the only one that builds without errors (generally a large number of 'unknown word' errors about //
if I try moving the iconfont plugin to the sass-loader or other earlier loaders. In my site I am referencing font-icon
in a sass file. This only shows the icon as ""
as opposed to the sandbox which appears to compile to an understandable '\e000'
for the content of the pseudo element
I experience the same issue, however with webpack 5. I'm running webpack-dev server as well.
My SASS file looks similar to this:
.ss-value-delete
span
&:after
font-icon: url('./assets/close.svg')
.ss-arrow
&:after
font-icon: url('./assets/arrow-down.svg')
Both files are in the "assets" folder and can be resolved by webpack.
However both icons look like this:
And everything seems to be in order here:
The issue I think leads to the problem is, that the generated font file is invalid.
Because when I take a look in the style tag where the generated woff gets included:
The content is prefixed with module.exports="... which is probably not correct and leads to the issue, that the browser can't interpret the woff file and will therefore fail to render the correct icon.
I'm not 100% sure if this is related, or it has to do with the webpack asset module syntax that was introduced in v5.
As an appendix to my previous post: I can confirm, my issue comes from using the asset module logic, instead of the url-loader/file-loader in webpack 5.
I fixed the issue by using the "generator" and "parser" options for the asset module:
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
type: 'asset',
generator: {
filename: 'assets/[name]-[hash][ext][query]',
dataUrl(source)
{
source = typeof source === 'string' ? source : source.toString();
// This is a fix for the iconfont-webpack-plugin so we don't add module.exports to the data url
if (source.startsWith('module.exports="\\"data:')) {
return source.substr(18, source.length - 4 - 18);
}
return require('mini-svg-data-uri')(source);
}
},
parser: {
dataUrlCondition: (source) => {
source = typeof source === 'string' ? source : source.toString();
// This is a fix for the iconfont-webpack-plugin,
// so everything that starts with module.exports is automatically written as data url
if (source.startsWith('module.exports=') || source.startsWith('data:')) {
return true;
}
return (new Blob([source]).size) < 10000;
}
}
}
]
}
};
This will ensure the icon font gets written as data-url and remove the module.exports from it. I hope this helps someone in the future :)
@Neunerlei is there anything we could do in the iconfont-webpack-plugin to prevent that?
maybe we could use the inline-matchresource
feature !=!
to tell webpack that this file is not an svg?
https://webpack.js.org/api/loaders/#inline-matchresource
or maybe even turn it into a binary so it can be statically extracted?
@jantimon Hey there.
What you are supposing could work, but I never tested that option myself, yet.
One thing that would make it a lot easier would be to introduce a new option like: "esModule": false which disables the Module generation here and on line 35
What would really solve the problem is, to get rid of the dataUrl entirely in your loader. Your loader is in a twilight-zone, where webpack seems to run into its limits. I spent a lot of time, searching the internet on how to create a dynamic module, that handles like a real one.
You would have multiple routes to go with, tho.
- Do what they do and create a virtual module, which seems quite finnicky...
- Return a request that is handled by your own loader, and points to a dummy.woff inside your loader directory. The content of dummy.woff gets replaced by the loader with the actual woff you store somewhere globally in your postcss plugin. For example: icon-woff-content-loader?iconFont={{fontId}}!./path/to/your/dummy.woff Here, your loader could simply return the stored content of the woff which webpack will handle as any other "real" woff.
- Go the brute-force option and write a woff file in a temporary directory and include that in the generated webpack bundle. Yes, this has some drawbacks, like not using the memory-fs, but it would work. And I have seen other loaders do the same thing.
I personally would try option 2 first, because you don't need a plugin, have the benefit of keeping your woff source "virtual" and can handle the file as a real woff without any issues. Additionally, it should work without any updates in the webpack.config (Theoretically cough)
I hope this helps :)
Not sure if this is to overcomplicated..
./file.woff!=!icon-woff-content-loader/getStyles!./file.svg
will create a dependency to ./file.svg
and create a virtual file ./file.woff
the virual file will be picked up by all loaders defined for .woff
If that works 👍