【Next】svgr/cli v7で.svgをReactコンポーネントに一括変換

2023/05/03に公開

背景

svgファイルをReactコンポーネントに変換する方法の記事を参考に、
.svgをReactコンポーネントに一括変換しようとしていたところ、バージョンの違いでちょっと沼ったので、記事にしました。

環境

  • Node.js v18.14.0
  • Next 13.3.1
  • React 18.2.0
  • svgr/cli 7.0.0

svgr/cli設定

1. インストール

公式ドキュメントを参考に、インストールします。

npm install --save-dev @svgr/webpack

2. コマンド

試しに、フォルダを作って以下を実行すると、
public/images/iconにある.svgが、components/iconsに出力されます。

npx @svgr/cli -d components/icons public/images/icon

3. .svgrrc.js作成

ここでは、以下のように変換したいので、.svgrrc.jsを作成し、設定していきます。

  1. 出力される拡張子を、.jsではなく、.tsxに変換
  2. 名前付きexportのコンポーネントに変換

.tsxに変換

module.exports = {
  typescript: true,
}

名前付きexportのコンポーネントに変換

module.exports = {
  typescript: true,
  template: (variables, { tpl }) => {
    return tpl`
    ${variables.imports};

    ${variables.interfaces};

    export const ${variables.componentName} = (${variables.props}): JSX.Element => {
        return ${variables.jsx};
      }
    `
  },
}

4. package.json

ここで、3.で実行した以下のコマンドを毎回実行するのは面倒なので、
package.jsonscripts部分に以下を追加します。

"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    // 追加
    "icons": "npx @svgr/cli -d components/icons public/images/icon"
  },

そうすると、

npm run icons

するだけで、public/images/iconにある.svgcomponents/iconsに一括変換されるようになります。

結果

public/images/iconにあったhome.svgが、

<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
  <path d="M0 0h24v24H0V0z" fill="none"/>
  <path d="M12 5.69l5 4.5V18h-2v-6H9v6H7v-7.81l5-4.5M12 3L2 12h3v8h6v-6h2v6h6v-8h3L12 3z"/>
</svg>

components/iconsHome.tsxとして変換されました。

import * as React from "react";
import { SVGProps } from "react";
export const SvgHome = (props: SVGProps<SVGSVGElement>): JSX.Element => {
    return (
        <svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} {...props}>
            <path fill="none" d="M0 0h24v24H0V0z" />
            <path d="m12 5.69 5 4.5V18h-2v-6H9v6H7v-7.81l5-4.5M12 3 2 12h3v8h6v-6h2v6h6v-8h3L12 3z" />
        </svg>
    );
};

Discussion