FortAwesome / vue-fontawesome

Font Awesome Vue component
https://fontawesome.com
MIT License
2.38k stars 134 forks source link

make an icon component specifically for tree shaking #475

Open jpengelbrecht opened 10 months ago

jpengelbrecht commented 10 months ago

fontawesome-svg-core/index.mjs comes in at a whooping 60.187 KiB . so if i am using the treeshaking method by importing the icons i need and using the "@fortawesome/vue-fontawesome" component the display component makes up about 3% of my entire bundle size. i would imagine if you make a sleeker version that is only made for explicitly passing through the imported icon as a prop we can do away with a lot of the logic bulking up this component

jasonlundien commented 10 months ago

@jpengelbrecht ---

make a sleeker version that is only made for explicitly passing through the imported icon as a prop

Do you have a repo where you have done this, a PR, or some code perhaps that I could see/review on this ?

jpengelbrecht commented 10 months ago

I don't have a repo for this no. but using this method, https://fontawesome.com/docs/apis/javascript/tree-shaking essentially you already have the icon. I am just saying that import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; is huge for something you only need to pass a prefetched icon

jasonlundien commented 10 months ago

@jpengelbrecht ---

I think I get what you are saying then...

So currently to use the Font Awesome icons in vue we do have to import FontAwesomeIcon: import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";

This allows us to use icons in our vue components: <font-awesome-icon icon="fa-solid fa-user-secret" />

But we also need to import icons or at least 1 icon (via tree shaking): import { faUserSecret } from '@fortawesome/free-solid-svg-icons'

So how do we still use Font Awesome icons without importing the FontAwesomeIcon component: import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";

I think that is what you are questioning/asking?

jpengelbrecht commented 10 months ago

@jasonlundien exactly. you can still use <font-awesome-icon class="push-icon-2" :icon="faUserSecret" /> however it I think some of the components bulk comes from having to support this as well <font-awesome-icon icon="fa-solid fa-user-secret" /> so maybe a specific component for tree shaking might be a lot skinner if that makes sense?

WhyNotHugo commented 9 months ago

I've measured the size of my bundle.

Without any font-awesome:

assets/product-variant-selector-9e4e1ee7.js            1.97 kB │ gzip:  0.94 kB

Merely registering the component like this

import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
Vue.component('font-awesome-icon', FontAwesomeIcon)

Increases the bundle size:

assets/product-variant-selector-392a0bd2.js           70.75 kB │ gzip: 19.95 kB

Adding the library itself

import { library } from '@fortawesome/fontawesome-svg-core'
library.add()

This has almost no impact in bundle size:

assets/product-variant-selector-30f78efb.js           70.77 kB │ gzip: 19.97 kB

Importing a single icon

And finally, importing a single icon seems to only increase the bundle every so slightly:

import { faShoppingBasket } from '@fortawesome/free-solid-svg-icons'
library.add(faShoppingBasket)
assets/product-variant-selector-4e0332cb.js           71.43 kB │ gzip: 20.28 kB

I'm really not sure what's happening when importing the FontAwesomeIcon type. I suspect that some unnecessary files are getting pulled in too. But the component with a single icon end up representing 97% of my bundle size.

robmadole commented 9 months ago

Hello @WhyNotHugo we have some docs on using the plugin system to pick-n-choose features:

https://fontawesome.com/docs/apis/javascript/plugins

This helps to reduce size but it may not get the bundle size down as small as you would like. It's worth a look though!

WhyNotHugo commented 9 months ago

My main issue is that each script ends up bundling the same component, so each output script jumps in size by 60kB just by using a single icon.

I've managed to somewhat improve the situation by making sure that Vite puts the icon component into its own file, and different pages will just load the same one (this will often be a cache hit, so it'll only be loaded once).

I just added this into rollupOptions.output invite.config.js:

output: {
  manualChunks: {"fa": ["@fortawesome/vue-fontawesome"]},
}

Bundle sizes:

product-variant-selector-b281f8f7.js              2.72 kB │ gzip:   1.30 kB
fa-e8ca04d2.js                                   68.76 kB │ gzip:  19.11 kB
WhyNotHugo commented 9 months ago

Thanks, @robmadole, but that seems to only reduce the size of the core svg bundle. What's really bumping my modules size is this specific bit:

import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'

In order to reduce the size of that one, I think I'd need my own build of the Vue component, which depends on my own build of svg-core as described in https://fontawesome.com/docs/apis/javascript/plugins.