Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prints unicode character instead of icon #48

Open
labbydev opened this issue Nov 4, 2020 · 13 comments
Open

Prints unicode character instead of icon #48

labbydev opened this issue Nov 4, 2020 · 13 comments

Comments

@labbydev
Copy link

labbydev commented Nov 4, 2020

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.

@jantimon
Copy link
Owner

jantimon commented Nov 5, 2020

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

@labbydev
Copy link
Author

labbydev commented Nov 5, 2020

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
Copy link
Author

labbydev commented Nov 6, 2020

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

@jantimon
Copy link
Owner

jantimon commented Nov 7, 2020

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

@labbydev
Copy link
Author

labbydev commented Nov 9, 2020

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

@jantimon
Copy link
Owner

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

@labbydev
Copy link
Author

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

@Neunerlei
Copy link

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
Copy link

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

@jantimon
Copy link
Owner

jantimon commented Apr 15, 2021

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

@Neunerlei
Copy link

@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 :)

@jantimon
Copy link
Owner

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

@Neunerlei
Copy link

If that works 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants