This is my vite-config.js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, splitVendorChunkPlugin } from 'vite'
import vue from '@vitejs/plugin-vue'
import usePHP from 'vite-plugin-php'
export default defineConfig({
plugins: [
usePHP({
binary: 'C:/tools/php83/php.exe',
}),
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => ['v-list-item-content', 'v-list-item-group'].includes(tag),
}
}
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
rollupOptions: {
external: ['/config/settings.json'],
output: {
manualChunks(id) {
return 'App';
}
}
}
}
})
Which results on npm run build
to this:
vite v5.4.14 building for production...
✓ 875 modules transformed.
dist/index.php 0.99 kB
dist/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 403.22 kB
dist/assets/materialdesignicons-webfont-PXm3-2wK.woff 587.98 kB
dist/assets/materialdesignicons-webfont-B7mPwVP_.ttf 1,307.66 kB
dist/assets/materialdesignicons-webfont-CSr8KVlo.eot 1,307.88 kB
dist/assets/index-B9hCvS5B.css 774.23 kB │ gzip: 110.89 kB
dist/assets/index.php-Cxh_CgE8.js 576.45 kB │ gzip: 184.18 kB
The size of the materialdesignicons are enormous compared to the small app size. How can I reduce the size of the fonts? Is this a vuetify issue?
EDIT My main.js
//Vuetify
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
const vuetify = createVuetify({
components,
directives,
locale: {
messages: { de, en }
}
})
app
.use(createPinia())
.use(vuetify)
.use(router)
This is my vite-config.js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, splitVendorChunkPlugin } from 'vite'
import vue from '@vitejs/plugin-vue'
import usePHP from 'vite-plugin-php'
export default defineConfig({
plugins: [
usePHP({
binary: 'C:/tools/php83/php.exe',
}),
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => ['v-list-item-content', 'v-list-item-group'].includes(tag),
}
}
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
rollupOptions: {
external: ['/config/settings.json'],
output: {
manualChunks(id) {
return 'App';
}
}
}
}
})
Which results on npm run build
to this:
vite v5.4.14 building for production...
✓ 875 modules transformed.
dist/index.php 0.99 kB
dist/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 403.22 kB
dist/assets/materialdesignicons-webfont-PXm3-2wK.woff 587.98 kB
dist/assets/materialdesignicons-webfont-B7mPwVP_.ttf 1,307.66 kB
dist/assets/materialdesignicons-webfont-CSr8KVlo.eot 1,307.88 kB
dist/assets/index-B9hCvS5B.css 774.23 kB │ gzip: 110.89 kB
dist/assets/index.php-Cxh_CgE8.js 576.45 kB │ gzip: 184.18 kB
The size of the materialdesignicons are enormous compared to the small app size. How can I reduce the size of the fonts? Is this a vuetify issue?
EDIT My main.js
//Vuetify
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
const vuetify = createVuetify({
components,
directives,
locale: {
messages: { de, en }
}
})
app
.use(createPinia())
.use(vuetify)
.use(router)
Share
Improve this question
edited Feb 6 at 11:56
Moritz Ringler
16.1k10 gold badges27 silver badges45 bronze badges
asked Feb 1 at 12:27
theking2theking2
2,8702 gold badges34 silver badges48 bronze badges
5
- The recommended way is to use svg icons, as you don't have to include the full icon set. Instead, only the icons you actually use will be bundled (see docs) – Moritz Ringler Commented Feb 2 at 16:58
- Yeah I agree but it seems vuetify uses these (?) – theking2 Commented Feb 3 at 8:27
- I found this in the vuetify docs. – theking2 Commented Feb 3 at 10:24
- Using the font file is the easiest way, but SVG is recommended to reduce built size in production. Since font files are cached, clients typically only download them once, so for projects with a limited set of users (most business projects probably), this is often acceptable (no first time visitors wondering what weird page they landed at). – Moritz Ringler Commented Feb 3 at 10:48
- @MoritzRingler thanks! I've provided an example in my answer. – theking2 Commented Feb 3 at 12:09
2 Answers
Reset to default 0In order to prevent inclusion of all icons consider including only those you need and not use <v-icon></v-icon>
but instead use @mdi/js
pnpm install @mdi/js
To make this easy create component Icon.vue
<script setup>
defineProps({
path: String,
fill: String,
size: {
type: [String, Number],
default: 24
}
});
</script>
<template>
<svg :width="size" :height="size" viewBox="0 0 24 24">
<path :d="path" :fill="fill" />
</svg>
</template>
and use it in your template:
<template>
<Icon :path="mdiAccount" fill="red" size="60"/>
</template>
<script>
import { mdiAccount } from "@mdi/js";
import Icon from '@/components/Icon.vue';
</script>
Of course you can fill from properties or computed value
After that make sure to remove the fonts with pnpm uninstall @mdi/font
In Vuetify, an icon setup consists of three parts:
- an icon source (e.g. an icon font used through css classes)
- a component that knows how to display the icons from the source (i.e. to render an
<i>
tag with the css class of the icon) - a record binding icons to named aliases
The component and the aliases depend on the source, Vuetify provides implementations for Material Design Icons (MDI) and Font Awesome (FA), both css and svg. For other icons, you have to provide your own icon component and alias mapping (see docs for creating a custom icon set).
The default is MDI css font, Vuetify expects the css files being available. Usually, that means you have import '@mdi/font/css/materialdesignicons.css'
somewhere in your project, the actual font files (woff, ttf, etc.) are then added to your bundle along the CSS file. Clients will load the fonts file they work best with (usually woff2 I think, but it might be declaration order in CSS, not sure).
So to switch from MDI css, follow these steps:
- remove the import of
materialdesignicons.css
- install the icon library you want to use
- register component and alias declaration in the
icons
part of the Vuetify configuration passed tocreateVuetify()
. For MDI SVG, this looks as in the documentation:
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg'
export default createVuetify({
icons: {
defaultSet: 'mdi', // refers to a value in "sets" below
aliases, // <--- the aliases, should match the defaultSet
sets: {
mdi, // <--- the icon component
},
},
})
Look at vuetify/iconsets/mdi-svg
to see the aliases, it is a simple object, binding names to SVG pathes. The component exported as mdi
puts those SVG pathes into a SVG element (same as the Icon.vue
component in your answer):
const aliases: IconAliases = {
collapse: 'svg:M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z',
complete: 'svg:M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z',
...
}
const mdi: IconSet = {
component: VSvgIcon,
}
Implementation of VSvgIcon can be found here.
- Make sure icons you use in your project are available.
For example, <v-icon icon="mdi-home" />
will not work anymore when you removed the CSS file and changed the component (you'll get a SVG with a path d="mdi-home"
). Import the declaration (the SVG path) into the context where you use VIcon.
To import into context:
<template>
<v-icon :icon="mdiAccount" />
</template>
<script setup>
import { mdiAccount } from '@mdi/js'
</script>
It is also possible to extend aliases and work with placeholders, which is the key from aliases prefixed with a $
(see documentation for an example).
Registering multiple icon sets basically means to register multiple of those icon components, you can tell VIcon which component to use through prefixes (see docs).
Hope this clears things up.