ゲームエンジニアの雑記ブログ

ゲームエンジニアの雑記ブログ。テーマ自由、技術について解説します

【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ

【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ

こんにちは、エンジニアのオオバです。

はてなブログからNext.jsで構築した本ブログ。
画像のレンダリングは旧来の<img />

Next.js v10で登場したImageコンポーネントに
置き換えていませんでした。

MarkDownの画像にサイズ指定ができない。

↑これが解決できませんでした。

今回少し工夫してImage置き換えに成功しました。
そのノウハウを共有をしたいと思います。

→11万文字で徹底解説した「DOTweenの教科書」Unityアニメーションの超効率化ツールはこちら

LightHouse 7ポイント上昇

まずは結果からお伝えします。

Imageに置き換えたことで、
パフォーマンススコアは7ポイント上昇しました。

【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ_0

ページの読み込み速度が上がるというのは
単純にうれしいです。

画像URLにサイズ取得用のハッシュを仕込む

ここから実装についてのお話です。

画像サイズ情報を埋め込んだmdx
![【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ_1](https://sample.com/img.png#300_200)  

mdxファイル内の画像URLに
「#幅_高さ」 というキーワードを埋め込み、
Next.jsでレンダリング時に参照します。

具体的にどう実装していくのか解説していきます。

画像サイズをMarkDownは未サポート

通常MarkDownで執筆する時、
画像サイズは指定しません。

というかできません。

![【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ_2](https://sample.com/img.png)  

MarkDownの仕様に画像サイズが
サポートされていないからです。

画像サイズを無理やり埋め込む

前述したとおり、
幅と高さをURLにハッシュで埋め込むことで
サイズ取得を実現しました。

![【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ_3](https://sample.com/img.png#幅_高さ)  

大量の画像のサイズを埋め込む方法

Pythonでスクリプトを書いて、

  • キー : 画像URL
  • バリュー : 幅_高さ

という構成のキャッシュファイルを作りました。

https://sample.com/img1.png, 910_978  
https://sample.com/img2.png, 930_509  
https://sample.com/img3.png, 32_69  
https://sample.com/img4.png, 120_387  
https://sample.com/img5.png, 672_429  

このファイルを参照して、
画像パスを変更しています。

分かりやすい図を用意しました

分かりやすい図_1

  1. ネットから画像を取得
  2. サイズを取得
  3. URL、画像の幅高さをセットにしたcsvを作成

分かりやすい図_2

  1. MarkDownからMDXへ変換
  2. 変換時に先のCSVを参照
  3. 画像のURLに画像サイズ情報を埋め込む

分かりやすい図_3

  1. MDXProviderを使ってimgタグを置き換える
  2. 最適された画像がレンダリングされる

といった流れです。

正規表現とMDXProviderで画像URLからサイズを取得

_app.jsxに記述しているMDXProviderで
MDXの整形処理をしています。

MDXProviderに渡している
ルールスクリプトは以下です。

const mdComponents = {  
  img: (props) => {  
    // 正規表現で画像URLから「#幅_高さ」を検索  
    const match = props.src.match(/#([0-9]*)_([0-9]*)/);  
    // サイズ情報が見つかったらImageを適用する  
    return (  
    <Image src={props.src}  
    width={match[1]}  
    height={match[2]}  
    />  
    )  
  }
}

imgタグの時に正規表現を使って
画像URLからサイズを拾います。

その値をwidthheight
それぞれ値をセットします。

MDXProviderでMDXを整形する方法は
こちらの記事で詳しく解説しています。
もしやり方がわからない方はぜひ読んでみてください。

外部サイトの画像はnext.config.jsに登録

💻ソースコード : next.config.js抜粋
images: {  
    domains: [  
      "sample.com"  
    ]  
},  

外部サイトに配置した画像を表示するときには
next.config.jsにドメイン登録が必要です。

設定し忘れると以下のエラーが出力されます。

Unhandled Runtime Error  
Error: Invalid src prop (【img url】) on `next/image`,  
hostname "【ドメイン名】" is not configured under images in your `next.config.js`  

パフォーマンス大幅アップ

Imageコンポーネントへの置き換えは、
パフォーマンスアップのため
言っても過言ではありません。

震える手でドキドキしながら
計測ボタンを押しました。

以下LightHouseでの計測です。

Before : Imageコンポーネント適用前

【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ_4

After : Imageコンポーネント適用後

【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ_5

Imageコンポーネント適用前後で
パフォーマンスが7ポイントも上昇!!
素晴らしい!!

はてなブログ時代の同じページ

【Next.js】next/imageをMDXに適用してパフォーマンス大幅アップ_6

※はてなブログとの比較はImageだけの影響ではなく、Next.js化自体のパフォーマンスも計上されています。

結果

  • Imageコンポーネント適用前後 : 7%アップ
  • はてなブログ時代と比較 : 28%アップ

素晴らしいです。
苦労して実装した甲斐がありました。

まとめ

imgからImageに置き換えました。
結果的にパフォーマンスが大幅アップ!
まだImageを使っていない方、オススメですよ。

実装方針として、
MarkDownに画像サイズを仕込むのが味噌でした。


最後に、ブログをNext.js化して、
全ての機能を自分で
作らなければならないのは非常に面白いです。

まだまだ改善したい機能がたくさんあるので、
実装でき次第ブログで報告させていただきます。

「Unity初心者大学」というUnity初心者向けのYouTube始めました!!
ぜひチャンネル登録をお願いします!

最後まで読んでいただきありがとうございました!
すばらしいNext.jsブログライフをお過ごしください。

オススメ記事
検証環境
  • Next.js v11.1.2