react-fontawesome
react-fontawesome copied to clipboard
[feature request] Remove library.add() with a better solution
Is your feature request related to a problem? Please describe.
- Importing each separate icon is too declarative.
- Annoying developer experience - just let us start!
- Have I missed an icon?
- Generates huge boilerplate if looking to modularize
library.add()into each component that uses an icon. - Not part of the react paradigm.
Describe the solution you'd like
- Internally lazy load icons. Many bundlers code split when they see a lazy import (inline
require()). This means it'll add itself into your app only when you call it. - Possibility to override it on a particular component if the component dynamically chooses an icon. An example would be an icon picker.
Describe alternatives you've considered
An alternative is what already exists: use library.add() to add icons to the sheet. An understandable solution, but I have no idea what icons I may be using for my project. I just want to use them.
Additional context
Picture to show I'm not being dramatic:
You can do this using react-fontawesome:
import { faSquare } from '@fortawesome/fontawesome-svg-solid-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
<FontAwesomeIcon icon={faSquare} />
Since you are loading icons one at a time, this is going to be part of a lazy loaded chunk. So, you can just completely ignore using library. I personally like selecting icons based on names:
<FontAwesome icon="square" />
Since you are loading icons one at a time, this is going to be part of a lazy loaded chunk. So, you can just completely ignore using
library. I personally like selecting icons based on names:<FontAwesome icon="square" />
@GasimGasimzada When I do the above, wouldn't I have to add the icon to the library? It seemed clear to me that the above only works when adding a library, according to this documentation.
That's why this issue was created in the first place.
Yes you do but you can also use imported Icon directly into FontAwesome.
I have to agree with OP on this one. The developer experience of library.add is not great. I've used @material-ui/icons and their API is simply:
import { AccessAlarm } from '@material-ui/icons';
I don't understand why react-fontawesome can't be:
import { SquareIcon } from '@fortawesome/react-solid'; // (or similar)
Am I missing something? In the context of code-split JAMstack apps, this import scheme seems more beneficial for optimizing bundles per page too.
@ricokahler like this?
import { faSquare } from '@fortawesome/fontawesome-svg-solid-icons';
@robmadole I was thinking theFontAwesomeIcon component would be in there too I suppose
the implementation of the SquareIcon could be as simple as this:
// SquareIcon.js
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSquare } from '@fortawesome/fontawesome-svg-solid-icons';
function SquareIcon(props) {
return <FontAwesomeIcon icon={faSquare} {...props} />;
}
export default SquareIcon;
Realistically this is small wish list item but I would love it π
Oh gotcha! Yeah, we probably won't do that because it would introduce a build step and make the library HUGE.
Yeah that makes sense and I don't disagree with your sentiment, but on the flip side, the DX would probably be better if you bit the bullet.
If you're worried about the source code becoming huge, you can probably just defer creating the icon component files until build (kind of like a JAMstack app actually lol). The footprint of the library in NPM would definitely still be giant but in general bundlers would be able to tree shake everything unused.
Startup times might be slower since tree shaking generally doesn't happen until the production build is created but material-ui solved this problem using a babel transform plugin while exposing direct imports.
So here's the full proposal:
- create JAMstack-esque setup that creates the different icon files during build. this build should also output a giant es-modules index.js file that's tree shakable
- create a new repo for each type of icon (
@fortawesome/react-solid,@fortawesome/react-light, etc) - expose each file so that they can be directly imported like
import SquareIcon from '@fortawesome/react-solid/SquareIcon';so that babel plugin material-ui suggested will work.
What does this achieve?
This π
import { SquareIcon, CoffeeIcon } from '@fortawesome/react-solid'
What's the impact?
Users are now using ONE less line of code for while still creating tree shakable builds.
Is it worth it?
Maybe! I believe this API is marginally better π
and has nearly the same API footprint (i.e. the import is still one line) as library.add.
β¦but also I understand if you're not feeling it π
Well described and thanks for illustrating the solution so well. But I don't think this provides enough of an advantage to devote the effort into it. So yeah, not quite feeling it π
That's completely fair. Thanks for considering it.
Not really what I'd necessarily recommend long term because its a lot of wasted imports/bloat, but if you just want to be able to access all the icons without being annoyed while you're prototyping, something like this will work and register all the icons :)
import { library } from "@fortawesome/fontawesome-svg-core";
import * as icons from "@fortawesome/free-solid-svg-icons";
import { isObject, isNull } from "lodash";
library.add(
...Object.keys(icons)
.filter(icon => isObject(icons[icon]) && !isNull(icons[icon]))
.map(icon => icons[icon])
);
I found it too cumbersome to declare individual icons I use separately from where I actually use the icon but importing all icons bloats the codebase, so I created a babel plugin macro which transforms code like
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { fas } from 'fontawesome.macro'
<FontAwesome icon={fas`square`} />
into
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSquare } from "@fortawesome/free-solid-svg-icons"
<FontAwesome icon={ faSquare } />
https://github.com/javascripter/fontawesome.macro
I don't know if fontawesome team wants to include a helper like this in their package though, as this feels like a magic :)
That's pretty slick! It does feel like magic but if you are using Babel you are signing up for at least a small cup of magic with your lunch. Let me think on this. Thanks for sharing @javascripter
@javascripter Please publish your package on npm.
We'll certainly post it on the README if you publish it. I don't think that's something we'd bundle into the core of this package right now.
I wrote type definitions for this macro: javascripter/fontawesome.macro#1
This is beautiful:

@thorn0 Thanks. Merged and published to npm π https://www.npmjs.com/package/fontawesome.macro
@robmadole Yes that'll be great as well. I've written some tests and also setup CI, etc. to make sure my macro continues to work properly.
When I use
import { solid } from "@fortawesome/fontawesome-svg-core/import.macro";
I get error Module not found: Can't resolve 'fs'
You can do this using
react-fontawesome:import { faSquare } from '@fortawesome/fontawesome-svg-solid-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; <FontAwesomeIcon icon={faSquare} />Since you are loading icons one at a time, this is going to be part of a lazy loaded chunk. So, you can just completely ignore using
library. I personally like selecting icons based on names:<FontAwesome icon="square" />
After years of usage I think this is the better way to go about it.