Simplifying Font Awesome implementation with Nextjs App Router!
Tags: nextjs, react, javascript
Published: 2023-06-04 15:46:31

The Next.js team has successfully transitioned the App Router from beta to a [stable release](https://nextjs.org/blog/next-13-4). The App Router uses [Server Components](https://nextjs.org/docs/getting-started/react-essentials#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:

```jsx
// 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`.

```jsx
// _app.js

import "lib/icons";

...
```

```js
// 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.

```jsx
// 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:

1. An extensive list may become difficult to sift through.
2. It's annoying to add icons twice in the configuration file.
3. Identifying unused icons can become complex.
4. The JavaScript bundle delivered to the client is likely to increase in size.

To solve 1, 2, 3 we could do something like this:

```js
// 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.

```shell
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](https://www.joshwcomeau.com/react/the-perils-of-rehydration/). 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:

```jsx
// pages/example.js 👈

export default function MyBugsPage() {
  return(
   <>
    <h1>Bugs 🐞</h1>
    <FontAwesomeIcon icon="bug" />
    <FontAwesomeIcon icon="bugs" />
   </>)
}
```

After:

```jsx
// 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:

```shell
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](https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration), written by the Nextjs team.

## Links
- [App Router](https://nextjs.org/docs/app)
- [Incrementally migrate to the App Router](https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration)