DEV Community

Cover image for Simplifying Font Awesome implementation with Nextjs App Router!
kouliavtsev
kouliavtsev

Posted on

Simplifying Font Awesome implementation with Nextjs App Router!

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} />
   </>)
}
Enter fullscreen mode Exit fullscreen mode

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";

...
Enter fullscreen mode Exit fullscreen mode
// lib/icons.js

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

import {
  faBug,
  faBugs,
} from "@fortawesome/pro-solid-svg-icons";

library.add(
  faBug,
  faBugs,
);
Enter fullscreen mode Exit fullscreen mode

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" />
   </>)
}
Enter fullscreen mode Exit fullscreen mode

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:

// lib/icons.js
import { library } from "@fortawesome/fontawesome-svg-core";

import { fas } from "@fortawesome/pro-solid-svg-icons";
library.add(fas);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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" />
   </>)
}
Enter fullscreen mode Exit fullscreen mode

After:

// app/example/page.js πŸ‘ˆ

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

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
Enter fullscreen mode Exit fullscreen mode

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

Top comments (3)

Collapse
 
konraddeskiewicz profile image
Konrad

No matter what I can't get icons defined in lib/icons.js to work. I'm importing this in top-level layout.tsx but then on page I need to import FontAwesomeIcon each time. After that icon name is not recognized.

What am I missing here?

Collapse
 
mathieudehaeck profile image
Mathieu De Haeck

Hi, great article, but your before and after example seems identical.

Collapse
 
geni94 profile image
geni94

the comment is what's important: i.e., where you're putting the code.