📸

インラインSVGのReactコンポーネントを撲滅したらファイルサイズが94%削減された

2024/09/27に公開

はじめに

みなさんはReactでの開発する中で、どのようにSVGを扱っていますでしょうか?
CSSStyleの当てやすさから私たちのプロダクトではSVGをReactコンポーネント内で定義していましたが、パフォーマンスが良くないという問題にぶちあたりました。
今回はその問題への対処方法を共有したいと思います。
前提条件として弊社は以下の環境となっています。

next : 14.2.7
react : 18.3.1
react-dom : 18.3.1
typescript : 5.5.4
Node.js : 20.17.0

デプロイ環境 : Vercel

問題

before first load js
トップページのサイズが217kbありFirstLoadJSは452kbもあり、読み込みに時間がかかっていました。
before avoid an excessive dom size
Lighthouseの評価もDOM sizeが1,747elementsとなっており異常な数でした。

同じSVGコンポーネントが同じページで連続して使用されてもキャッシュが効かず都度ロードされるため、ページの読み込みにも影響を与えていました。

解決方法

やることは2つです。

  1. SVGを.svgファイルとして切り出す
  2. Next.jsのImageコンポーネントを使ってSVGを読み出す

SVGを.svgファイルとして切り出す

以下のようなアイコンコンポーネントの場合は、svgタグの中身を外出しして.svgファイルにします。

export const ChevronRight = () => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width="12"
    height="13"
    viewBox="0 0 12 13"
    fill="none"
  >
    <path
      d="M7.43878 6.96456L4.2568 3.78258C4.06154 3.58732 4.06154 3.27074 4.2568 3.07548C4.45206 2.88022 4.76864 2.88021 4.9639 3.07548L8.14589 6.25746C8.34115 6.45272 8.34115 6.7693 8.14589 6.96456C7.95062 7.15983 7.63404 7.15983 7.43878 6.96456Z"
      fill="#777777"
    />
    <path
      d="M8.14596 6.96454L4.96398 10.1465C4.76872 10.3418 4.45214 10.3418 4.25687 10.1465C4.06161 9.95126 4.06161 9.63468 4.25687 9.43942L7.43885 6.25743C7.63412 6.06217 7.9507 6.06217 8.14596 6.25743C8.34122 6.4527 8.34122 6.76928 8.14596 6.96454Z"
      fill="#777777"
    />
  </svg>
)

Next.jsのImageコンポーネントを使ってSVGを読み出す

import Image from "next/image";

type Props = {
  className?: string
}

export default function ChevronRight({ className }: Props) {
  return (
    <div className={className}>
      <Image
        src="/assets/icons/chevron-right.svg"
        alt="chevron-right"
        width={12}
        height={13}
      />
    </div>
  )
}

おわりに

after first load js
after an excessive dom size
全てのSVGを外部リソース化したところSizeが94%も削減され、DOM sizeも59%削減されました!
参考になればと思います!

参考

https://zenn.dev/okamoai/articles/a8d5cf1b094edd#インライン-svg

株式会社モニクル

Discussion