React-fontawesome: Bundle size

Created on 9 Feb 2018  路  33Comments  路  Source: FortAwesome/react-fontawesome

According to readme using explicit import like
import faCoffee from '@fortawesome/fontawesome-free-solid/faCoffee'
should allow to minimalize bundle size. What sizes should I expect?
I am using around 15 icons from fontawesome-free-solid. All of them were imported using explicit import. According to source-map-explorer, fontawesome-free-solid occupy 610 KB in my case. Is it normal?

firefox_2018-02-09_07-49-17

Most helpful comment

We weren't able to get tree shaking to work out of the box with Webpack 4. Thankfully, we were able to workaround the issue using babel-plugin-transform-imports with a configuration like this:

// .babelrc
{
  "plugins": [
    ["transform-imports", {
      "@fortawesome/free-solid-svg-icons": {
        "transform": "@fortawesome/free-solid-svg-icons/${member}",
        "skipDefaultConversion": true
      }
    }]
  ]
}

With that, we're still able to import members directly from the package.

import { faTimes, faEnvelope } from '@fortawesome/free-solid-svg-icons';

This works for Pro versions as well.

All 33 comments

The docs for @fortawesome/react-fontawesome says

Explicit Import

Allows icons to be subsetted, optimizing your final bundle. Only the icons you import are included in the bundle. However, explicitly importing icons into each of many components in your app might become tedious, so you may want to build a library.

I'm using this notation

import {faTrashAlt} from '@fortawesome/fontawesome-free-regular';

but the result is the whole index.es.js file in my bundle.

Things I tried:

  1. Removing the default export of the index.es.js but the result is the whole file.
  2. Individualizing the naming export. From this:
export {prefix, faAddressBook, faAddressCard, faAdjust, faAlignCenter, ...};

to this:

export {prefix};
export {faAddressBook};
export {faAddressCard};
export {faAdjust};
export {faAlignCenter};
...

I can't find a workaround to make webpack reduce the the @fortawesome/fontawesome-free-regular size, the same with @fortawesome/fontawesome-free-solid.

@navarroaxel try to use:

import faTrashAlt from '@fortawesome/fontawesome-free-regular/faTrashAlt';

Webpack will only import the icon you are actually referencing.

It's true @iagomelanias but the _explicit import_ example published to NPM (https://www.npmjs.com/package/@fortawesome/react-fontawesome) is out of date. Please update that.

There is a way to avoid import one icon per line in my project? I like the destructuring import syntax and I don't want to build a library like example two says.

We'll be addressing some tree-shaking issues in the 0.1.0 release of this library. Hang tight and we'll get this solved.

but the result is the whole index.es.js file in my bundle.

As far as I can tell that is the core fontawesome lib, so that'll always be there.

I love the approach v5 is taking but I'm a little bit worried that so much runtime code is needed for rendering an icon, I feel a little bit uneasy replacing 80kb of material icon woffs with 40kb of icon-rendering logic. Are there plans to slim this down or possibly provide separate entry-points for simpler use-cases? I'm imagining that an SVG-only React bundle would be a lot smaller for example.

Yep, @pleunv, we have an entire track that is focused on optimization. We intend on moving the rendering logic into a set of modules that can be elective. That plugin kind of architecture is probably a long way off though.

Sounds great, looking forward to it :)

I'm presuming the reason the shorter explicit import version (eg import {faTrashAlt} from '@fortawesome/fontawesome-free-regular') doesn't work is similar to that affecting lodash/others in webpack/webpack#2867?

ie: Defining "side-effects": false in react-fontawesome's package.json (presuming there are no side-effects) will allow for full tree-shaking with webpack 4, or else use the longer import form in the meantime.

I have added "sideEffects" false using Webpack@4 and the bundle size is not smaller.

@kzc give me the solution here: https://github.com/webpack/webpack/issues/6724#issuecomment-372192614
This line of code prevents unused definitions from being dropped:

define('fas', icons$1);

@robmadole, How we can fix this?

This will be addressed in 5.1.0 of Font Awesome. We are working on this now and it鈥檚 the highest priority item we have for the dev team.

For those who are eager about the upcoming changes for tree shaking, but maybe haven't yet experimented with it on the development branch, here's an appetizer: a working demo of easy tree shaking.
https://github.com/mlwilkerson/react-fontawesome-tree-shaking-demo

You can also shave off a 15kb gzipped by just using the svg-icon directly and use your own css-in-js solution, this is an example with styled-components:

import React from 'react'
import PropTypes from 'prop-types'
import styled, { css } from 'styled-components'

import basket from '@fortawesome/fontawesome-free-solid/faShoppingCart'
import bar from '@fortawesome/fontawesome-free-solid/faBars'
import left from '@fortawesome/fontawesome-free-solid/faChevronCircleLeft'
import right from '@fortawesome/fontawesome-free-solid/faChevronCircleRight'
import down from '@fortawesome/fontawesome-free-solid/faChevronCircleDown'
import up from '@fortawesome/fontawesome-free-solid/faChevronCircleUp'
import email from '@fortawesome/fontawesome-free-solid/faEnvelope'
import check from '@fortawesome/fontawesome-free-solid/faCheck'

import facebook from '@fortawesome/fontawesome-free-brands/faFacebook'
import instagram from '@fortawesome/fontawesome-free-brands/faInstagram'
import pinterest from '@fortawesome/fontawesome-free-brands/faPinterest'
import youtube from '@fortawesome/fontawesome-free-brands/faYoutube'

import Element from '../Element/Element'

const icons = {
  email,
  check,
  facebook,
  instagram,
  youtube,
  pinterest,
  basket,
  bar,
  'arrow-left': left,
  'arrow-right': right,
  'arrow-down': down,
  'arrow-up': up
}

const IconBase = styled.svg`
  height: 1em;
  width: 1em;
  margin: 0 !important;
`

const Container = Element.withComponent('i').extend`
  display: inline-flex;
  align-self: center;
  position: relative;
  height: 1em;
  width: 1em;
  vertical-align: baseline;
  ${props =>
    props.baseline
      ? css`
          ${IconBase} {
            bottom: -0.125em;
            position: absolute;
          }
        `
      : ''}
`

const Icon = ({ icon, ...rest }) => {
  if (!icons[icon]) {
    return null
  }
  const rawIcon = icons[icon]
  return (
    <Container {...rest}>
      <IconBase
        aria-hidden='true'
        role='img'
        xmlns='http://www.w3.org/2000/svg'
        viewBox='0 0 512 512'
      >
        <path fill='currentColor' d={rawIcon.icon[4]}></path>
      </IconBase>
    </Container>
  )
}

Icon.propTypes = {
  icon: PropTypes.oneOf(Object.keys(icons)).isRequired,
  baseline: PropTypes.bool
}

export default Icon

Is the issue definitively solved? As for me, the current version is OK. The size of the @fortawesome module after build (in my case) is limited to 46 KB, which is a great improvement.

@robmadole That link brings me to trello but it doesn't show any boards :)

@kbzowski the current version latest or the prerelease channel explained here: https://github.com/FortAwesome/react-fontawesome/tree/development ?

@pleunv that Trello link is just for our internal tracking, ignore please.

@navarroaxel Current from npm registry

Hi, now that 0.1.0 / 5.1.0 is released, is webpack treeshaking working properly?

Yes, the upgrade is working properly.

Hi, I must dropped from something, I used library.add to add the icon I used, but in my bundling analyzer still shows the whole index.ee.js being added... However, if I explicitly add icon into library e.g. import faAngleDoubleRight from '@fortawesome/free-solid-svg-icons/faAngleDoubleRight'; the size of bundle indeed being reduced greatly but it gives me error like 'prefix' is undefined... Any solution?

p.s. I'm using the latest version.

Try import { faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons/faAngleDoubleRight'.

Also check out the docs here regarding the issue with slow tree shaking. https://fontawesome.com/how-to-use/with-the-api/other/tree-shaking

Going to close this as we've got this implemented in 5.1.0.

Is tree shaking supported for the FA pro libraries as well? I'm using @fortawesome/pro-light-svg-icons 5.2.0 and named imports still results in the entire FA library included in my bundle. Thanks!

@mhriess yes, it's supported in Pro. If you are having issues with your build tool we suggest going to sub-module imports like import { faAngleDoubleRight } from '@fortawesome/free-solid-svg-icons/faAngleDoubleRight'

Thanks @robmadole - we fell back to the submodule import, just wanted to double check we weren't doing anything wrong.

We weren't able to get tree shaking to work out of the box with Webpack 4. Thankfully, we were able to workaround the issue using babel-plugin-transform-imports with a configuration like this:

// .babelrc
{
  "plugins": [
    ["transform-imports", {
      "@fortawesome/free-solid-svg-icons": {
        "transform": "@fortawesome/free-solid-svg-icons/${member}",
        "skipDefaultConversion": true
      }
    }]
  ]
}

With that, we're still able to import members directly from the package.

import { faTimes, faEnvelope } from '@fortawesome/free-solid-svg-icons';

This works for Pro versions as well.

I'm having an issue getting my bundle size down with webpack 4 as well. The output ends up being > 1MB in size with the default webpack production build, while doing destructured imports like above. Is anyone else having this issue/resolved?

@ryanwalters This works for Pro versions as well.

Thank you for that. Using your approach I was able to reduce the parsed size of Fontawesome from over 9MB to around 300kb.

Before

Screenshot 2019-04-25 at 17 59 36

After

Screenshot 2019-04-25 at 17 59 53

.babelrc

{
  "presets": ["@babel/env", "@babel/react", "babel-preset-expo"],
  "plugins": [
    "@babel/proposal-class-properties",
    "@babel/plugin-syntax-export-namespace-from",
    [
      "transform-imports",
      {
        "@fortawesome/pro-regular-svg-icons": {
          "transform": "@fortawesome/pro-regular-svg-icons/${member}",
          "skipDefaultConversion": true
        },
        "@fortawesome/pro-solid-svg-icons": {
          "transform": "@fortawesome/pro-solid-svg-icons/${member}",
          "skipDefaultConversion": true
        },
        "@fortawesome/pro-light-svg-icons": {
          "transform": "@fortawesome/pro-light-svg-icons/${member}",
          "skipDefaultConversion": true
        }
      }
    ]
  ]
}

Any updates? It doesn't work with create-react-app as well.

If you are trying to implement @ryanwalters's solution but are using a babel.config.js you have to use a function like so:

plugins: [
  ...
  [
    'transform-imports',
    {
      '@fortawesome/free-solid-svg-icons': {
        transform: member => `@fortawesome/free-solid-svg-icons/${member}`,
        skipDefaultConversion: true,
        preventFullImport: true,
      },
    },
  ],
]

I recommend adding preventFullImport: true, as well to ensure expected behaviour.


Also as an aside if you currently use fas as a way to get icons via their string name, importing this will cause an error and cannot be used. (Also, now it simply won't function as it won't have reference to all the icons you are now no longer importing)

I am dealing with this now after upgrading from Font Awesome 4 (painlessly referenced with a tag via a CDN) to Font Awesome 5 with webpack.

I am importing a single icon. My bundle grew from 300KB without Font Awesome to over 1MB with it. I followed the advice of doing:

import { faDollarSign } from "@fortawesome/free-solid-svg-icons/faDollarSign";

...and it shaved it down to 700KB, but that's still 400KB for a single icon. This is absurd.. the whole point of importing single icons is to reduce bundle sizes.

Here's my code:

import { icon } from '@fortawesome/fontawesome-svg-core';
import { faDollarSign } from "@fortawesome/free-solid-svg-icons/faDollarSign";

const dollarSign = icon(faDollarSign).html;
Was this page helpful?
0 / 5 - 0 ratings

Related issues

johnnunns picture johnnunns  路  4Comments

lomse picture lomse  路  5Comments

v8tix picture v8tix  路  4Comments

lehresman picture lehresman  路  6Comments

johnnunns picture johnnunns  路  6Comments