javascriptreactjsnext.jsdynamic-importreact-icons

NextJS imports everything when trying to use dynamic imports with `react-icons`


I need to use an Icon from the react-icons package.
Whenever I use it with an import statement, this is the bundle size I get:

Route (pages)                              Size     First Load JS
┌ ● /                                      7.41 kB        87.1 kB
├   /_app                                  0 B              77 kB
├ ○ /404                                   181 B          77.2 kB
├ ○ /auth                                  2.19 kB        79.2 kB
├ ○ /create (483 ms)                       3.72 kB        83.4 kB
├ λ /post/[name]                           78.8 kB         158 kB
├ λ /post/author/[name]                    3.24 kB        82.9 kB
├ ○ /settings                              3.6 kB         83.3 kB
├ λ /users                                 3.09 kB        82.8 kB
└ λ /users/[name]                          3.2 kB         82.9 kB
+ First Load JS shared by all              81.1 kB
  ├ chunks/framework-3b5a00d5d7e8d93b.js   45.4 kB
  ├ chunks/main-b5f8370d8042886c.js        27.4 kB
  ├ chunks/pages/_app-db3210ce0bd19d50.js  1.92 kB

users/index.tsx

import { BsFillPeopleFill } from "react-icons/bs";

Basically, the First Load JS is always consistent between 70 - 83kb (Although /post/[name] route has 158kb)

But whenever I am trying to dynamically import the icon component with dynamic, this is what I get:

Route (pages)                              Size     First Load JS
┌ ● /                                      7.42 kB         266 kB
├   /_app                                  0 B              77 kB
├ ○ /404                                   181 B          77.2 kB
├ ○ /auth                                  2.19 kB        79.2 kB
├ ○ /create                                3.73 kB         262 kB
├ λ /post/[name]                           78.8 kB         337 kB
├ λ /post/author/[name]                    3.25 kB         262 kB
├ ○ /settings                              3.61 kB         262 kB
├ λ /users                                 3.12 kB         262 kB
└ λ /users/[name]                          3.21 kB         262 kB
+ First Load JS shared by all              81.1 kB
  ├ chunks/framework-3b5a00d5d7e8d93b.js   45.4 kB
  ├ chunks/main-b5f8370d8042886c.js        27.4 kB
  ├ chunks/pages/_app-db3210ce0bd19d50.js  1.92 kB
  ├ chunks/webpack-e486fd67877a5f73.js     2.25 kB
  └ css/a905066d5b28cc23.css               4.07 kB

users/index.tsx

const BsFillPeopleFill = dynamic(() => import("react-icons/bs").then(bootstrapIcons => bootstrapIcons.BsFillPeopleFill));

As you can see, it just spiked up to 200kb in routes that use an icon. I don't really why it is importing the entire react-icons/bs part instead of just importing the one icon and splitting it into one bundle.

Can anyone help with this issue?


Solution

  • Siri. I ran into a similar problem few months ago. Here's how I fix it.

    First of, create a new file for e.g. 'utils/components/icons.ts' and export the icon you need from the react-icons package in the file. Like this:

    export { BsFillPeopleFill } from "react-icons/bs";
    

    Then in your users/index.tsx file you can dynamically import the icon from the 'utils/components/icons.ts' file. Like this:

    const BsFillPeopleFill = dynamic(() => import("utils/components/icons").then(icons => icons.BsFillPeopleFill));
    

    Hope this helps.