iconfont-webpack-plugin icon indicating copy to clipboard operation
iconfont-webpack-plugin copied to clipboard

Prints unicode character instead of icon

Open labbydev opened this issue 4 years ago • 13 comments

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.

labbydev avatar Nov 04 '20 18:11 labbydev

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

jantimon avatar Nov 05 '20 08:11 jantimon

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");

labbydev avatar Nov 05 '20 15:11 labbydev

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;
}

labbydev avatar Nov 06 '20 16:11 labbydev

looks like the loader doesn't work - which webpack version do you use?

jantimon avatar Nov 07 '20 10:11 jantimon

I'm using version 4 (specifically 4.44.2) of Webpack

labbydev avatar Nov 09 '20 15:11 labbydev

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

jantimon avatar Nov 10 '20 10:11 jantimon

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

labbydev avatar Nov 10 '20 23:11 labbydev

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: image

And everything seems to be in order here: image image

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: image

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. image

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.

Neunerlei avatar Apr 14 '21 11:04 Neunerlei

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 avatar Apr 14 '21 14:04 Neunerlei

@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 avatar Apr 15 '21 06:04 jantimon

@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.

  1. Do what they do and create a virtual module, which seems quite finnicky...
  2. 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.
  3. 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 :)

Neunerlei avatar Apr 15 '21 12:04 Neunerlei

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

jantimon avatar Apr 15 '21 12:04 jantimon

If that works 👍

Neunerlei avatar Apr 15 '21 13:04 Neunerlei