Simplifying Font Awesome implementation with Nextjs App Router!
kouliavtsev
Posted on June 4, 2023
The Next.js team has successfully transitioned the App Router from beta to a stable release. The App Router uses Server Components. This makes working with Font Awesome icons even more "Font Awesome"!
Before we would have to destructure icons from the library like this:
// pages/example.js
import { faBug, faBugs } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
export default function MyBugsPage() {
return(
<>
<h1>Bugs π</h1>
<FontAwesomeIcon icon={faBug} />
<FontAwesomeIcon icon={faBugs} />
</>)
}
If your application would have to many icons, you would could create a library file that you would import into _app.js
.
// _app.js
import "lib/icons";
...
// lib/icons.js
import { library } from "@fortawesome/fontawesome-svg-core";
import {
faBug,
faBugs,
} from "@fortawesome/pro-solid-svg-icons";
library.add(
faBug,
faBugs,
);
By doing this, you could skip the step on importing font awesome icons in the component.
// pages/example.js
export default function MyBugsPage() {
return(
<>
<h1>Bugs π</h1>
<FontAwesomeIcon icon="bug" />
<FontAwesomeIcon icon="bugs" />
</>)
}
This is great, yet not ideal.
Centralizing the configuration of icons could substantially streamline the process. However, expanding from 2 to 50 (or more) icons may introduce several challenges:
- An extensive list may become difficult to sift through.
- It's annoying to add icons twice in the configuration file.
- Identifying unused icons can become complex.
- The JavaScript bundle delivered to the client is likely to increase in size.
To solve 1, 2, 3 we could do something like this:
// lib/icons.js
import { library } from "@fortawesome/fontawesome-svg-core";
import { fas } from "@fortawesome/pro-solid-svg-icons";
library.add(fas);
Unfortunately, point 4 becomes more of a problem. If you run next build
you will see that you are shipping a whooping 1mb+
to the client.
Route (pages) Size First Load JS
β β / (564 ms) 9.66 kB 1.06 MB
β /_app 0 B 1.05 MB
Yikes! π
Why is the bundle size hurting the performance?
This is due how rendering in Nextjs works. Scratch that! How it used to work. All components that are in the pages folder would be pre-render on the server and hydrated. While hydrating we would ship 1mb+
to the client. Nextjs uses tree shaking under hood, yet is not able understand how to do this with the fas
import.
The quickfix with App Router Server Components?
With the new App Router we can use Server Components without any set up required. All React (Server Components) run the code on the server and thus reduce bundle size that is sent to the client.
Before:
// pages/example.js π
export default function MyBugsPage() {
return(
<>
<h1>Bugs π</h1>
<FontAwesomeIcon icon="bug" />
<FontAwesomeIcon icon="bugs" />
</>)
}
After:
// app/example/page.js π
export default function MyBugsPage() {
return(
<>
<h1>Bugs π</h1>
<FontAwesomeIcon icon="bug" />
<FontAwesomeIcon icon="bugs" />
</>)
}
And you are done! π«
Your bundle size should look, something like this:
Route (pages) Size First Load JS
β β / (564 ms) 9.66 kB 84,5 kb
β /_app 0 B 84,5 kb
NOTE: You need to have Nextjs version 13.4
.
If you starting fresh? Good for you, simply use the example above.
If you you are stuck with Nextjs older version, don't worry you can incrementally migrate by using this adoption guide, written by the Nextjs team.
Links
Posted on June 4, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.