4

I am using materialdesignicons in my vue project.

require ('../node_modules/@mdi/font/css/materialdesignicons.min.css);
Vue.use(Vuetify, {iconfont:'mdi'});

I have a handful of icons which I dynamically create:

 <v-icon>{{ some-mdi-file }}</v-icon>

When I build for production via (npm run build) I get the following error:

asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
  img/materialdesignicons-webfont.someHash.svg (3.77 MiB)

That file size is huge because it includes every icon, regardless of whether it's being used. Is there a way to trim that file size down by only packaging the specific icons used. Is there a different package I should be using? Caveat: The project is hosted offline, so I need to include the fonts directly in my project.

I looked at vue-material-design-icons but it looks like it may not work for dynamic icon names and it says nothing about the overall file size/performance.

I have also looked here but clicking on the 'size warning' link brings me to a page where the Vue portion is not filled out https://dev.materialdesignicons.com/getting-started/webfont

James Coyle
  • 9,922
  • 1
  • 40
  • 48
ekjcfn3902039
  • 1,673
  • 3
  • 29
  • 54

1 Answers1

5

I would recommend using the @mdi/js package for this which provides SVG paths for each icon and supports tree shaking. Currently Vuetify doesn't support SVG icons but it should in the future.

For now, it's easy enough to create a custom icon component:

<template>
    <svg :class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
        <path :d="path" />
    </svg>
</template>

<script>
export default {
    name: 'my-icon',

    data: () => ({
        path: '',
    }),

    methods: {
        updatePath() {
            if (!this.$scopedSlots) return
            if (typeof this.$scopedSlots.default !== 'function') return

            this.path = this.$scopedSlots
                .default()
                .map((n) => n.text)
                .join('')
        },
    },

    mounted() {
        this.updatePath()
    },

    updated() {
        this.updatePath()
    },
}
</script>

<style scoped>
.icon {
    display: block;
    color: inherit;
    fill: currentColor;
    width: 24px;
    height: 24px;
}
<style>

Then to use it you just need to import your component and the icon you want to use:

<template>
    <div class="app">
        <my-icon>{{mdiCheck}}</my-icon>
    </div>
</template>

<script>
import MyIcon from 'path/to/my/icon.vue'
import { mdiCheck } from '@mdi/js'

export default {
    name: 'my-app',

    components: {
        MyIcon,
    }

    data: () => ({
        mdiCheck,
    }),
}
</script>
James Coyle
  • 9,922
  • 1
  • 40
  • 48