AlekseyHoffman
AlekseyHoffman

Reputation: 2694

Vue: icons are not displayed when css.extract: false

When building a Vue library (component), according to Vue docs, you can set css.extract: false in vue.config.js to avoid the users having to import the CSS manually when they import the library into an app:

vue.config.js

module.exports = {
  css: { 
    extract: false 
  }
}

However, when you do that, the icons are not displayed in the production build.

In this case I'm using @mdi/font and weather-icons. Neither of them load:

enter image description here

To reproduce

You can reproduce this with this Vue library (component):

import 'vue-open-weather-widget/dist/vue-open-weather-widget.css'

Upvotes: 1

Views: 822

Answers (1)

Serg
Serg

Reputation: 845

I have looked at your lib (nice component BTW). I created a build with css: { extract: false } and first looked at the behavior when importing vue-open-weather-widget.umd.js directly into an HTML file. And that worked without any problems.

The thing is that the fonts remain external in the dist after the build. And it seems that there is a problem to find the fonts when your component is loaded in a Webpack project (in our case Vue CLI project). I don't know why the fonts are not referenced correctly. But I have found another, and possibly a better solution.

As it is stated in the MDI docs, the use of the web fonts can negatively affect the page performance. When importing only one icon, all of them are imported, which in turn increases the bundle size. In such a small component this is more than suboptimal, especially for the component users. Therefore here is the alternative solution, also suggested by MDI:

Use @mdi/js instead of @mdi/font

Remove all @mdi/font references in your code and install deps:

npm install @mdi/js @jamescoyle/vue-icon

Replace all icons with SVG(e.g. in MainView.vue). Note that on this way only icons are included in the bundle that are used in your components:

...
<span @click="state.settings.view = 'settings'">
  <svg-icon type="mdi" :path="mdiCogOutline"></svg-icon>
</span>
...

import SvgIcon from '@jamescoyle/vue-icon'
import { mdiCogOutline } from '@mdi/js'

...
components: {
  SvgIcon
},
data () {
    return {
      mdiCogOutline: mdiCogOutline
    }
  },

Adjust vue.config.js:

module.exports = {
  css: {
    extract: false
  }
}

Build component:

# i would also include --formats umd-min
vue-cli-service build --target lib --formats umd-min --name vue-open-weather-widget src/main.js

Now your dist contains only 192.68 KiB vue-open-weather-widget.umd.min.js and the component is ready to use over CDN or in a Vue CLI Project, without importing any CSS or fonts. I have tested both cases. Here is how it looks like:

enter image description here

Hope it helps you! Feel free to ask if you have further questions.

Upvotes: 1

Related Questions