question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dynamically Importing Icons

See original GitHub issue

I’m trying to dynamically import icons using import(), but am running into some issues. Has anyone done this or is this not supported?

Below is what I’ve tried, with varying results. I’m using a Pro icon here and have everything correctly set up to use the Pro packages (Pro icons imported via the static import work just fine). This code is in my main.js, before I bootstrap Vue.

First I tried:

import { library } from '@fortawesome/fontawesome-svg-core';

const x = '@fortawesome/pro-light-svg-icons/faAlicorn';
import(x)
  .then((icon) => {
    library.add(icon);
  });

which results in:

Error: Cannot find module '@fortawesome/pro-light-svg-icons/faAlicorn'
Could not find one or more icon(s) Object { prefix: "fal", iconName: "alicorn" } Object {  }

Next I tried:

import { library } from '@fortawesome/fontawesome-svg-core';

import('@fortawesome/pro-light-svg-icons/faAlicorn')
  .then((icon) => {
    library.add(icon);
  });

which results in the icon showing up on the screen, but I see this in my console:

TypeError: icon is undefined[Learn More]

If anyone has some insights into what’s going on and/or how to get it working (w/o errors in the console), I’d appreciate it!

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:5
  • Comments:13 (1 by maintainers)

github_iconTop GitHub Comments

15reactions
jarvelovcommented, Aug 14, 2019

I don’t know what the official stance is on this but I got it working by wrapping the FontAwesomeIcon component in my own component. It supports icons using both String and Array as the icon prop.

It has no real error handling other than that it shows the spinner-thirdicon while loading the icon and the exclamationicon if it fails to load.

These are the versions I’m using

    "@fortawesome/fontawesome-svg-core": "^1.2.17",
    "@fortawesome/free-solid-svg-icons": "^5.8.1",
    "@fortawesome/vue-fontawesome": "^0.1.6",

This is the component, place it in a .vue file and use it as you would use the FontAwesomeIconcomponent.

<script>
import { library } from '@fortawesome/fontawesome-svg-core';
import { faExclamation, faSpinnerThird } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { camelCase } from 'lodash';

library.add([faExclamation, faSpinnerThird]);

export default {
  name: 'font-awesome-dynamic-icon',
  props: FontAwesomeIcon.props,
  data() {
    return {
      fetched: null,
      fetchedIcon: null,
      iconTypes: {
        fas: 'solid',
        far: 'regular',
        fal: 'light',
      },
    };
  },
  computed: {
    iconDefinition() {
      if (this.fetchedIcon) {
        return this.fetchedIcon;
      }

      if (library.definitions[this.iconPrefix] && library.definitions[this.iconPrefix][this.iconName]) {
        return {
          icon: library.definitions[this.iconPrefix][this.iconName],
          iconName: this.iconName,
          prefix: this.iconPrefix,
        };
      }

      return null;
    },
    iconFileName() {
      return camelCase(`fa-${this.iconName}`);
    },
    iconName() {
      return Array.isArray(this.icon) ? this.icon[1] : this.icon;
    },
    iconPrefix() {
      return Array.isArray(this.icon) ? this.icon[0] : 'fas';
    },
    iconType() {
      return this.iconTypes[this.iconPrefix];
    },
  },
  methods: {
    fetchIcon() {
      this.fetched = false;
      return import(/* webpackChunkName: "fonts/[request]" */
      `@fortawesome/free-${this.iconType}-svg-icons/${this.iconFileName}.js`)
        .then((response) => {
          this.fetched = true;

          if (response && response.definition) {
            this.fetchedIcon = response.definition;
            library.add(response.definition);
          }
        })
        .catch(() => {
          this.fetched = true;
        });
    },
  },
  created() {
    if (!this.iconDefinition) {
      this.fetchIcon();
    }
  },
  watch: {
    icon() {
      if (!this.iconDefinition) {
        this.fetchIcon();
      }
    },
  },
  render() {
    if (!this.iconDefinition) {
      if (!this.fetched) {
        return this.$createElement(FontAwesomeIcon, {
          props: {
            spin: true,
            icon: faSpinnerThird,
          },
        });
      }

      return this.$createElement(FontAwesomeIcon, {
        props: {
          icon: faExclamation,
        },
      });
    }

    return this.$createElement(FontAwesomeIcon, {
      props: {
        ...this.$options.propsData,
        icon: this.iconDefinition,
      },
    });
  },
};
</script>
3reactions
klausXRcommented, Jan 9, 2021

You need to add the .js extension after the filename, otherwise it does not work.

Webpack, however, seems to detect the partial dynamic part, and since it cannot safely assume which file you will import at runtime, it takes the entire contents of the folder and adds it to the build.

For example, if you use this path @fortawesome/free-solid-svg-icons/ with an attempt to later load the atom icon, like so @fortawesome/free-solid-svg-icons/atom.js, webpack will put all of the icons from free-solid-svg-icons/ in your bundle, which causes a major size impact.

I’m not completely sure as to why exactly they end up in the main bundle.

They can still end up in the bundle, but be lazily loaded on demand, however, once I tried that, a huge file chunk ends up in the bundle even without importing all of them - ie, they are all served to the client despite the fact that I only use a small portion of them.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dynamic import of react-icons - Stack Overflow
Is it possible to import dynamically react-icons if each of icon is a separate component? My code looks like this: import React from...
Read more >
How to import icon component dynamically? #364 - GitHub
I note for posterity that the Sanity code I am using to set icons dynamically is as follows: import * as icons from...
Read more >
Dynamic imports of Material UI Icons - Manuel Kruisz
Typically when we build sites with Material UI's icons, we just import the icon to use directly and insert it into our react...
Read more >
Add Icons with React | Font Awesome Docs
There are a few ways to add icons when using React. The easiest way is to use Dynamic Icon Importing which automatically imports...
Read more >
End user choose React icons component dynamically - Reddit
Sounds like you want a dynamic import. ... Can't you do "import * as icons" and loop through them? ... You could just...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found