FortAwesome / react-fontawesome

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

Bug: Defining icons from strings in React works, but there is always the 'Could not find icon' error message #525

Open rmachado-studocu opened 1 year ago

rmachado-studocu commented 1 year ago

This is a direct copy of this bug report by @Stephcraft

Describe the bug When you do this for example:

<Icon icon={['fas', 'gamepad']}/>

and I even add every icon to the font awesome react library object. I've tried two different ways, same outcome:

import { library  } from "../../node_modules/@fortawesome/fontawesome-svg-core"
import { fas } from '@fortawesome/free-solid-svg-icons'
import { far } from '@fortawesome/free-regular-svg-icons'
import { fab } from '@fortawesome/free-brands-svg-icons'

library.add(fab)
library.add(fas)
library.add(far)
import { library  } from "../../node_modules/@fortawesome/fontawesome-svg-core"
import * as FontAwesomeSolidIcons from '@fortawesome/free-solid-svg-icons'
import * as FontAwesomeRegularIcons from '@fortawesome/free-regular-svg-icons'
import * as FontAwesomeBrandsIcons from '@fortawesome/free-brands-svg-icons'

const geticonList = (module) => Object
    .keys(module)
    .filter(key => key !== "fas" && key !== "far" && key !== "fab" && key !== "prefix" )
    .map(icon => module[icon])

library.add(...[
    ...geticonList(FontAwesomeRegularIcons), 
    ...geticonList(FontAwesomeSolidIcons),
    ...geticonList(FontAwesomeBrandsIcons)
])

The icons do display, but the error message is still present:

Could not find icon { prefix: 'fas', iconName: 'gamepad' }

Reproducible test case

Steps to reproduce:

  1. Access https://codesandbox.io/s/zen-chihiro-ku0do2?file=/pages/index.js
  2. Open the preview in a new tab (or open this URL to go directly: https://ku0do2.sse.codesandbox.io/ )
  3. Open Chrome DevTools, CTRL+SHIFT+P / CMD+SHIFT+P, type "Disable Javascript" and press enter
  4. Refresh the page
  5. You'll notice the 'search' icon doesn't render

Expected behavior Expected the search icon to render server side and be in the HTML

Desktop (please complete the following information):

(Although the issue is with SSR, not the browser 😉 )

Additional context

If you change the line

import { config, library } from "@fortawesome/fontawesome-svg-core";

to

const { config, library } = require("@fortawesome/fontawesome-svg-core");

(and restart the server on codesandbox)

you'll notice it start server side rendering....

robmadole commented 1 year ago

The library is a singleton. So I'm betting that there is something going on with the SSR side of things that results in that singleton being instantiated multiple times.

This will take some investigation into how Next.js works. The workaround for this would be to explicitly reference icons instead of using the Library object.

import { faGamepad } from '@fortawesome/free-solid-svg-icons'

<Icon icon={faGamepad} />
rmachado-studocu commented 1 year ago

The library is a singleton. So I'm betting that there is something going on with the SSR side of things that results in that singleton being instantiated multiple times.

Well, yes... But I'd probably point out that the SSR (NextJS) might be using the ES version and somehow the react-awesome might be using the non-ES version which might lead to inconsistencies at the singleton value...

kochie commented 1 year ago

FWIW I've been able to solve this in testing bu adding the library to a client side component like below

"use client"

export default function SMButton({ sm }: { sm: SocialMedia }) {
  console.log(sm.icon)
  library.add(faTwitter)
  const icon = findIconDefinition({
    prefix: sm.icon[0],
    iconName: sm.icon[1],
  })
  console.log(icon)
  return (
    <div>
      <Link
        href={sm.link}
        className="text-white transition ease-in-out duration-200"
        onClick={(): void => trackGoal(sm.tracking, 0)}
        onMouseEnter={(event): void => {
          event.currentTarget.style.color = sm.color
          // event.currentTarget.style.transform = 'scale(1.2)'
        }}
        onMouseLeave={(event): void => {
          event.currentTarget.style.color = ''
          // event.currentTarget.style.transform = 'scale(1)'
        }}
      >
        <FontAwesomeIcon
          icon={icon}
          size="1x"
          className="mx-1 transform-gpu transition duration-200 ease-in-out"
        />
      </Link>
    </div>
  )
}
oniice commented 1 year ago

Also getting this in NextJs on client side components. They work as expected in server side components, but I think it fails in client side as it doesn't see the config.

It is throwing error Could not find icon { prefix: 'far', iconName: 'home' }

I am using the @fortawesome/react-fontawesome to render the icons as recomened in the FA setup. FA is configured like this in the new layout.tsx file.

import { config, library } from '@fortawesome/fontawesome-svg-core'
import { fas } from '@fortawesome/pro-solid-svg-icons';
import { far } from '@fortawesome/pro-regular-svg-icons';
config.autoAddCss = false;
library.add(fas, far, fal);

The using a icon like so <FontAwesomeIcon icon={['far', 'home]} />

I have tried dumping all the imports into a client side component - that fixes it, but then its looking like a lot of bloat from the mulitple imports!

Doing the const { config, library } = require("@fortawesome/fontawesome-svg-core"); hack around does not fix this