🌀

Vite + React(typescript) で SVGファイルをコンポーネントとして読み込む方法

2022/03/16に公開

create-react-appで作成したアプリの場合、デフォルトで svg ファイルをコンポーネントとして読み込むことができます。

App.tsx
import { ReactComponent as Hart } from './assets/hart.svg';

export function App() {
  return (
    <Hart style={{stroke:'gray', fill:'lightblue', width:'300px', height:'300px'}}/>
  );
}

viteで作成したreactアプリは、デフォルトで svg ファイルをコンポーネントとして読み込むことができません。
そこで svg ファイルをコンポーンネントとして読み込むためのライブラリをインストールします。

ライブラリはたくさんありますが、2022年3月16日時点で主要そうなところをピックアップしました。

no plugin Weekly Downloads Unpacked Size Last publish Git Star
1 vite-plugin-svgr 29,992 6.44 kB 2 months ago 93
2 vite-plugin-react-svg 11,253 5.75 kB a year ago 91
3 Vite SVG loader 10,762 175 kB 2 months ago 134
  1. 「vite-plugin-svgr」はURL、コンポーネントとして、svg ファイルを importすることができます。
    importの書き方は、create-react-appで作成したアプリと同じです。
import { ReactComponent as MyIcon } from './my-icon.svg'
  1. 「vite-plugin-react-svg」 は1年ほど前から更新が止まってるようなのでパスします。
  2. 「Vite SVG loader」はURL、文字列、コンポーネントとして、svg ファイルを importすることができます。
    パッケージサイズが大きいのが気になります。
// 接尾辞「?url」を使用して、URLとしてインポートする
// '/assets/my-icon.2d8efhg.svg'
import iconUrl from './my-icon.svg?url'

// 接尾辞「?raw」を使用して、文字列としてインポートする
// '<?xml version="1.0"?>...'
import iconRaw from './my-icon.svg?raw'

// 接尾辞「?component」を使用して、コンポーネントとしてインポートする
// <IconComponent />
import IconComponent from './my-icon.svg?component'

文字列としてファイルを読み込む要件はありませんので、「1.vite-plugin-svgr」を採用しました。

vite-plugin-svgr の導入

Vite + React + typescript に vite-plugin-svgr を導入します。

インストール

npm install vite-plugin-svgr --save-dev

2022年3月16日時点で vite-plugin-svgr は v1.0.1です。

vite.config.ts

vite.config.ts に下記項目を追加します。

古い書き方
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
+ const svgrPlugin = require('vite-plugin-svgr')

// https://vitejs.dev/config/
export default defineConfig({

  resolve: {
    alias: [{ find: '@', replacement: '/src' }]
  },
  plugins: [
    react({
      jsxImportSource: '@emotion/react'
    }),
+    svgrPlugin({
+      svgrOptions: {
+        icon: true,
+        // ...svgr options (https://react-svgr.com/docs/options/)
+      }
+    })
  ]
})

2022/05/17 追記 新しい設定内容

vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
+ import svgr from 'vite-plugin-svgr'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
+    svgr()
  ]
})

tsconfig.json

tsconfig.json に下記項目を追加します。

tsconfig.json(抜粋)
  "compilerOptions": {
    ・・・
+    "types": ["vite-plugin-svgr/client"]
  },

2022/04/19 追記
tsconfig.json の typesを指定すると、jestなどのテストライブラリが型情報を読み込めずエラーになります。
下記のようにjest関連のパッケージも読み込むように設定します。

"types": [ "node", "jest", "@testing-library/jest-dom", "vite-plugin-svgr/client"]

デフォルトでは、node_modules/@types の全ての型情報のパッケージがコンパイル時にインクルードされます。
tsconfig.json の types に指定すると、指定したものだけが読み込まれるため、vite-plugin-svgr/client 以外に必要な型情報パッケージがあれば、個別に追記する必要があります。

動作確認

App.tsxでsvgファイルを読み込んでみます。
create-react-appで作成したアプリと同じ書き方で svg ファイルが読み込めます。

App.tsx
import { ReactComponent as Hart } from './assets/hart.svg';

export function App() {
  return (
    <Hart style={{stroke:'gray', fill:'lightblue', width:'300px', height:'300px'}}/>
  );
}

Discussion