react-fontawesome
react-fontawesome copied to clipboard
Lighter version for reduced bundle size
Hi guys,
I noticed that fontawesome-svg-core
takes up 38kB of space in our bundle, compared to react-fontawesome
which only takes 6.6kB.
We're really only displaying icons without doing anything fancy, yet we have to serve 2500 loc of fontawesome-svg-core
to all our customers. Is all of it necessary? Could there be a "lighter" version of that package that doesn't include the massive amount of code if you don't need it?
I'm not sure what's going on in there, I see an entire mock of Promises as well, what is it doing?
I have the same thoughts when exploring react + FA.
According to the docs, in order to utilize 15-20 icons, (each 500-800 bytes), I have to include ~30kb libs. Seems to be insane.
In my case it is easier to import icons individually from node_modules/@fortawesome/fontawesome-free/svgs
@Floriferous we don't have a lighter version right now but we might one day. The size of the package is to support all of the features that are listed on https://fontawesome.com/how-to-use/on-the-web
In theory, using only explicit imports would make the icon
(lookup) import obsolete, and then all that's left is the parse
import from fontawesome-svg-core
. If those two dependencies could be refactored (or a lighter sub-component extracted out of this one), then the fontawesome-svg-core
dependency could be optional rather than required.
Look up tree-shaking
, and ensure that your bundling is doing this properly (FontAwesome does have some issues with it, but it does work given understanding of the subject) :-)
Same here - just adding one icon via fontawesome-react will add 30 KB to our bundle (11 KB gzipped). The icon itself is about 260 B (gezipped) when added via SVGR + CRA 😭
I added an example based on CRA here: https://github.com/pstrh/fontawesome-bundle-size-issue
Screenshot from source-map-explorer:
Has anyone made progress on finding a solution for this? @fortawesome/fontawesome-svg-core
is taking up a lot of space in our bundle when we don't use any of the extra features.
If you don't need any of the extra features an alternative approach is to convert the svgs into react components yourself - via https://react-svgr.com/.
It's almost 2022 now. In case anyone still needs a solution except svgr I've pushed a separate package react-fontawesome-svg-icon. It does not support power transforms or masking, but should be fine for basic usage.
Anyone wants to remove @fortawesome/fontawesome-svg-core
and reduce bundle size could use the following snippet:
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
import type { SVGProps } from 'react'
export type FaIconProps = SVGProps<SVGSVGElement> & { icon: IconDefinition }
const xmlns = 'http://www.w3.org/2000/svg'
export function FaIcon(props: FaIconProps) {
const { icon: iconProps, children, ...rest } = props
const { prefix, iconName, icon } = iconProps
const [width, height, ligatures, unicode, svgPathData] = icon
const dataFa = `${prefix}-${iconName}`
return (
<svg
viewBox={`0 0 ${width} ${height}`}
xmlns={xmlns}
role={'img'}
aria-hidden="true"
data-fa={dataFa}
{...rest}
>
{children}
{Array.isArray(svgPathData) ? (
<g>
<path d={svgPathData[0]} />
<path d={svgPathData[1]} />
</g>
) : (
<path d={svgPathData} />
)}
</svg>
)
}
Usage:
import { faClose } from '@fortawesome/pro-solid-svg-icons'
<FaIcon icon={faClose} style={{width: 16, height: 16}} fill={'grey'} />
Another way without react:
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
function faIconToString(def: IconDefinition) {
const { icon } = def
const [width, height, ligatures, unicode, svgPathData] = icon
let content = ''
if (Array.isArray(svgPathData)) {
content = `<g>${svgPathData.map((x) => `<path d="${x}" />`)}</g>`
} else {
content = `<path d="${svgPathData}" />`
}
return `<svg viewBox="0 0 ${width} ${height}" role="img" xmlns="http://www.w3.org/2000/svg">${content}</svg>`
}
export default faIconToString
Usage:
import { faClose } from '@fortawesome/pro-solid-svg-icons'
// when component mount
element.current.append(faIconToString(faClose))
Adapt as you need.
@eugenezinovyev wow, this actually does everything I need it to. Thank you!
It's almost 2022 now. In case anyone still needs a solution except svgr I've pushed a separate package react-fontawesome-svg-icon. It does not support power transforms or masking, but should be fine for basic usage.
Oh my gosh this is amazing, works perfectly and saves me 20kb in my bundle, thank you!
Copied from sept2
's solution for an angular app (ng 15 with standalone components)
import { NgIf } from '@angular/common';
import { Component, Input } from '@angular/core';
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
@Pipe({
standalone: true,
name: 'faIcon',
})
export class FaIconPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(def: IconDefinition) {
const { icon } = def;
const [width, height, ligatures, unicode, svgPathData] = icon;
let content = '';
if (Array.isArray(svgPathData)) {
content = `<g>${svgPathData.map((x) => `<path d="${x}" />`)}</g>`;
} else {
content = `<path fill="currentColor" d="${svgPathData}" />`;
}
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}
@Component({
standalone: true,
selector: 'standard-icon',
template: `
<svg
*ngIf="icon"
class="svg-inline--fa fa-fw"
[attr.viewBox]="'0 0 ' + icon.icon[0] + ' ' + icon.icon[1]"
role="img"
xmlns="http://www.w3.org/2000/svg"
[innerHTML]="icon | faIcon"
></svg>
`,
styles: [
`
svg:not(:root).svg-inline--fa,
svg:not(:host).svg-inline--fa {
overflow: visible;
box-sizing: content-box;
}
.svg-inline--fa.fa-fw {
width: var(--fa-fw-width, 1.25em);
}
.fa-fw {
text-align: center;
width: 1.25em;
}
.svg-inline--fa {
display: var(--fa-display, inline-block);
height: 1em;
overflow: visible;
vertical-align: -0.125em;
}
`,
],
imports: [NgIf, FaIconPipe],
})
export class StandardIconComponent {
@Input() icon: IconDefinition | undefined;
}
bump,
there is no reason why me using few emoticons on react pulls in 70KB+ worth of stuff
Can remove prop-types
as a dependency. No reason this should be listed as a dependency
If you're only using free, then just grab the svg source directly from their site: https://fontawesome.com/v5/search?o=r&m=free. Wrap it how you want and call it a day.