heic2anyの遅延読み込み

Next.jsで作ったWebアプリのパフォーマンスが悪いなぁと思っていろいろ調べてみた。
npm run build
したときのFirst Load JSが600kBとかになっていて、結構重くなっていた。
@next/bundle-analyzerというものがあるらしいので、それでまずはビルド時のバンドルサイズを確認する。
導入方法はこちら。

npm run analyze
すると、3つのタブが立ち上がる。nodejs.htmlとedge.htmlとclient.html。クライアント側で読み込まれるjsファイルはclient.htmlかな?
heic2anyがめちゃくちゃ重い。。
mantineも結構重い。

heic2anyはiPhoneで撮影した画像フォーマットであるHEIC/HEIF形式の画像をJPEGとかPNGとかに変換したい時に使うライブラリ。
mantineはReactベースのUIコンポーネントライブラリ。

heic2anyは以下のように変更。
Before
useEffect(
if (typeof window !== "undefined") {
const heic2any = require("heic2any");
// その後の変換処理
}
)
After
useEffect(
if (typeof window !== "undefined") {
(async () => {
const heic2any = (await import("heic2any")).default;
// その後の変換処理
})()
}
)
こうすることで遅延読み込みになって、この処理が行われるまでは読み込まれないようになる。
この対応を入れた後、@next/bundle-analyzerでバンドルサイズを見たときはclient.html
には特に変化はない。ただnpm run build
したときのFirst Load JSは200kBくらいになって確かに軽くなっていた。
またブラウザの開発ツールのNetworkタブで確認したところ該当部分が呼ばれるまではheic2anyの読み込みが発火しないことも確認できた。

mantineの方は使っていないコンポーネントもバンドルに含まれてるっぽかったので、実際に使っているコンポーネントだけ読み込めないか情報を探してみた。
結論、こういうNext.jsのオプションがあるようだった。
これを入れると実際に使っているモジュールだけ読み込みしてくれるらしい。
next.config.js
を編集する。
const nextConfig = {
...
experimental: {
optimizePackageImports: ['@mantine/core', '@mantine/hooks'],
},
...
}
...
@next/bundle-analyzerで確認すると不要なコンポーネントは除外されていた。また、First Load JSのサイズもちょっとだけ小さくなっていた。

ダイエット成功。外部ライブラリを導入する時にはそのライブラリのサイズも意識しないとパフォーマンスに影響が出ることを学んだ。

参考: