FortAwesome / react-fontawesome

Font Awesome React component
https://fontawesome.com
MIT License
3.66k stars 261 forks source link

Lighter version for reduced bundle size #232

Open Floriferous opened 5 years ago

Floriferous commented 5 years ago

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?

Deliaz commented 5 years ago

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

robmadole commented 5 years ago

@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

vdh commented 5 years ago

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.

Rycochet commented 5 years ago

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) :-)

pstrh commented 4 years ago

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: source-map-explorer

joshverd commented 3 years ago

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.

pstrh commented 3 years ago

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/.

eugenezinovyev commented 2 years ago

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.

sep2 commented 2 years ago

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.

rscotten commented 1 year ago

@eugenezinovyev wow, this actually does everything I need it to. Thank you!

maxratajczak commented 1 year ago

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!

NateRadebaugh commented 1 year ago

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;
}
chr4ss12 commented 1 year ago

bump,

there is no reason why me using few emoticons on react pulls in 70KB+ worth of stuff

jlurena commented 1 year ago

Can remove prop-types as a dependency. No reason this should be listed as a dependency

morganney commented 8 months ago

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.

jbjhjm commented 1 week ago

Here's a solution for modern angular (standalone component + signals) which allows to get rid of angular-fontawesome and svg-core entirely: https://gist.github.com/jbjhjm/5e9c522c98314ec2c9abf6cf420c5776

vorant94 commented 1 week ago

i'm up for removing runtime checks of prop-types and I am ready to create a PR if repo maintainers consider dropping runtime checks and relying on build-time checks only is a good tradeoff for performance improvement