Next.jsのDynamic Importを使ってパフォーマンス改善する
2023/10/06

Next.jsのDynamic Importを使ってパフォーマンス改善する

2 mins to read

Next.jsのDynamic Importを使ってPageSpeed Insightsのパフォーマンススコアを60→94まで改善する事に成功しました!

デスクトップだと100点でした!

改善したページはこのサイトのコンポーネントページです。

実際に見てもらうとわかるんですが、iframeを使ってプレビュー画面を実装していたりcodemirrorでエディタ部分を実装していたりするので、普通のimportを使って実装すると最初に読み込むjsのサイズが大きくなってしまい、スコアがかなり落ちてしまうのが想像できるかと思います。

スクショ撮るの忘れちゃったんですが、改善前はスマホが60、PCが70ぐらいのパフォーマンススコアでした。

実際のコード

importからdynamic importに変更して、ローディング時の設定も行います。

Before

import Iframe from "./iframe";
import Editor from "./editor";

After

import dynamic from "next/dynamic";
import { Loading } from "@/components/loading";

const Iframe = dynamic(() => import("./iframe"), {
  loading: () => (
    <Loading />
  ),
});

const Editor = dynamic(() => import("./editor"), {
  loading: () => (
    <Loading />
  ),
});

ただ、これだけだと一番重いプレビューコンポーネント(iframe)は初期表示時に読み込みされてしまうので、editorの分しか早くなってません。

この時点でのスコアはこんな感じです。

なのでスタートボタンがクリックされるまではサムネイル画像を表示しておき、スタートボタンがクリックされてからプレビューコンポーネントを読み込むような形に変更しました。簡潔に書くと以下のような感じになります。

import dynamic from "next/dynamic";
import { Loading } from "@/components/loading";

const Iframe = dynamic(() => import("./iframe"), {
  loading: () => (
    <Loading />
  ),
});

const Editor = dynamic(() => import("./editor"), {
  loading: () => (
    <Loading />
  ),
});

export const Panel = ({ thumbnail, mode }) => {
  const [clicked, setClicked] = useState(false);

  return mode === "preview" ? (
    !clicked ? (
      <div className="relative h-[100%] w-[100%]">
        <img
          src={thumbnail}
          className="absolute h-[100%] w-[100%] object-cover z-[1]"
          alt="プレビュー画像"
        />
        <div className="absolute z-[2] flex h-[100%] w-[100%] items-center justify-center">
          <button onClick={() => setClicked(true)}>
            クリックしてプレビューを開始する
          </button>
        </div>
      </div>
    ) : (
      <Iframe />
    )
  ) : (
    <Editor />
  );
};

これでスマホが94点、PCでは100点の状態になりました!

おわりに

今回はクリックで読み込むように変更しましたが、画面の下のほうで読み込まれるコンポーネントだったらスクロールイベントを検知した時にコンポーネントを読み込むという風に設定する事もできますね。

とりあえず初期表示時に必要ではない大きいコンポーネントはなるべくdynamic importで読み込むという風に考えておくといいかもしれません。