🙆

【Next.js】SVGRでSVGファイルをReactコンポーネントに変換する

2023/12/21に公開

イントロダクション

みなさんはNext.jsでSVGをどのように扱っていますか?
ReactならばReactComponent asで変換する方法を用いて簡単に描画ができますが、create-next-appで立ち上げたNext.jsだとそれが使えず、imgタグで描画している方もいらっしゃるのではないでしょうか。
そこで今回はNext.jsでもSVGのReactコンポーネントを使えるようにするため、SVGファイルからReactコンポーネントに変換する方法をご紹介いたします。

SVGファイルをReactコンポーネントに変換するメリット

まずはSVGファイルをReactコンポーネントに変換するメリットをご紹介します。
メリットはいくつかありますが、中でも大きいのは以下の3つかと思います。

  • imgタグを使わないのでレンダリングの遅延によるレイアウト崩れが起こらない
  • サイズや色の変更が容易になる
  • TypeScriptによるサポートが受けられる

SVGファイルをReactコンポーネントに変換する方法

今回、SVGファイルをReactコンポーネントに変換するためにSVGRというライブラリを使用します。

https://react-svgr.com/

GithubのStar数は10kを超えており、2023年時点でまだメンテナンスやリリースが続いているため、安心して導入しやすいかなと思います。

このSVGRのCLIを用いて、コマンド1つでReactコンポーネントに変換します。

SVGRの導入

まずは@svgr/cliをインストールします。
例ではpnpmを使用していますが、各自使っているパッケージマネージャに変換してください。

pnpm add --save-dev @svgr/cli

次に、svgrを実行するスクリプトを作成します。

scripts/generate-icons.sh
#!/usr/bin/env bash

set -eu

pnpm svgr \
  --typescript \
  --memo \
  --filename-case kebab \
  --out-dir src/icons src/icons

スクリプトで指定しているオプションの意味は以下の通りです。

オプション 意味
--typescript .tsxで作成する
--memo React.memoでラップする
--filename-case kebab ファイル名をケバブケースにする
--out-dir src/icons 出力先をsrc/iconsにする

その他のオプションが気になる方は以下を参照してください。

https://react-svgr.com/docs/options/

最後に、作成したスクリプトを実行するためにpackage.jsonのscriptsに追加します。

package.json
{"scripts": {
    "gen:icons": "./scripts/generate-icons.sh"
  }
}

これでpnpm run gen:iconを実行すれば無事src/icons配下に置いたSVGファイルがReactコンポーネントに変換されるようになりました!
ただ、このままだとCSSでサイズを変更できなかったり、clipPathのidが一律でaとなってしまったりと使いづらい面が残っています。
そこで、設定ファイルを作成し、それらの問題を解消しましょう。

.svgrrc.js
module.exports = {
  svgoConfig: {
    plugins: [
      {
        name: "preset-default",
        params: {
          overrides: {
            removeViewBox: false,
            cleanupIds: false,
          },
        },
      },
    ],
  },
};

removeViewBox: falseはviewBoxを残す設定で、これによってCSSによるサイズ変更が可能になります。cleanupIds: falseは未使用のIDの短縮を無効化しているため、clipPathのidが一律でaになるのを防いでくれます。

応用:Reactコンポーネントのテンプレート編集

基本的な導入は以上なのですが、SVGRにはReactコンポーネントのテンプレートを編集する機能があり、一部の人には需要がありそうなので、簡単にご紹介します。

まずはテンプレートをいじる前に.svgrrc.jsでtemplateの指定をします。

.svgrrc.js
module.exports = {
  template: require("./src/icons/template.js")}

後は./src/icons/template.jsにテンプレートを書いていくだけです。デフォルトのテンプレートは以下のようになっています。

const template = (variables, { tpl }) => {
  return tpl`
${variables.imports};

${variables.interfaces};

const ${variables.componentName} = (${variables.props}) => (
  ${variables.jsx}
);

${variables.exports};
`
}

module.exports = template

このデフォルトテンプレートを元に、例としてファイルの最上部にコメントを追加した場合、以下のようになります。

src/icons/template.js
const tips = `
  // このファイルは自動生成されています。直接編集しないでください。
`

const template = (variables, { tpl }) => {
  return tpl`
${tips}
${variables.imports};
${variables.interfaces};

const ${variables.componentName} = (${variables.props}) => (
  ${variables.jsx}
);

${variables.exports};
`
}

module.exports = template

詳しい解説は長くなりそうなので割愛しますが、以下の公式ドキュメントに詳細が記載されているので、気になる方はご覧になってください。

https://react-svgr.com/docs/custom-templates/

あとがき

以上、SVGRを用いてSVGファイルをReactコンポーネントに変換する方法でした。
SVGRは弊社のプロダクトでも採用しており、今でもワークしているライブラリです。導入と運用がとても簡単なので、迷ったらぜひ一度試してみてください。

ゲームエイトテックブログ

Discussion