🍏

Vue3 + ViteでSVGファイルを読み込む方法

2022/07/06に公開

久しぶりに案件でVueを触り、Ver3.2から導入されたComposition APIで書き方がまるっきり変わって浦島太郎状態ですが、型サポートが手厚くなり、TypeScriptが扱いやすくなって嬉しいです

今回はVue3+ViteでSVGファイルをbabel-plugin-inline-react-svgのようにSVGファイルを読み込ませる際に、色々つまづいたのでメモします

SVGファイルを読み込む方法

手動でコンポーネント化

Vueの公式ドキュメントの編集可能なSVGアイコンシステムの項目で紹介されていますが、SVGファイルをVueファイルのコンポーネントとしてラップすることで、SVGファイルを読み込ませることができます
このやり方は一番手軽ですが、都度SVGファイルを変換するのが手間だったため、今回自分はこの方法を採用しませんでした

test.vue
<template>
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
    <path
      d="M470.531,378.938c0.031-0.422,0.141-0.844,0.141-1.281v-248c0-12.875-10.547-23.406-23.406-23.406H64.734 c-12.859,0-23.391,10.531-23.391,23.406v248c0,0.438,0.109,0.859,0.141,1.281H0v6.391c0,11.219,9.188,20.422,20.406,20.422h471.156 c11.25,0,20.438-9.203,20.438-20.422v-6.391H470.531z M440.25,370.625H71.75V136.672h368.5V370.625z"
    />
  </svg>
</template>

vite-svg-loaderでコンポーネント化

BuilderにWebpackを使う場合は、vue-svg-loaderあたりが鉄板でよさそうですが、
自分はViteを使用するため、vite-svg-loaderを採用しました
babel-plugin-inline-react-svgのようにSVGファイルをコンポーネント化してくれます

まずvite-svg-loaderをインストールします

npm i -D vite-svg-loader

Viteの設定ファイルにプラグインを追加します

vite.config.ts
import vue from '@vitejs/plugin-vue'
import pages from 'vite-plugin-pages'
import svgLoader from 'vite-svg-loader'

export default defineConfig({
  plugins: [vue(), pages(), svgLoader({ defaultImport: 'component' })],
  // ...
})

その後、VueファイルでSVGファイルをimportできるようになります
vite-svg-loaderではSVGファイルのimport方法として、URL、文字列、コンポーネントの3種類が用意されています
SVGファイルをインポートする際にそれぞれ対応したサフィックスを付けることで、識別できます
今回のようにコンポーネントとして扱う場合は?componentです

Test.vue
<script setup lang="ts">
import TestSVG from '../assets/svg/test.svg?component'
</script>

<template>
<TestSVG class="test">
</template>

Storybookでvite-svg-loaderを利用する際の注意点

このままStorybookでSVGファイルをコンポーネントとして呼び出すと下記のエラーが発生します
これはBuilderがコンポーネントとしてではなくファイルとして読み込んでしまうのが原因です

Failed to execute 'createElement' on 'Document': The tag name provided ('xxxx/xxxx.svg') is not a valid name. 

https://github.com/storybookjs/storybook/issues/9070

BuilderがViteの場合、Storybookのmain.jsでViteの設定ファイルと同様に、プラグインを追加することで解決できます

.storybook/main.js
const { mergeConfig } = require('vite')
const svgLoader = require('vite-svg-loader')

module.exports = {
  // ...
  async viteFinal(config) {
    return mergeConfig(config, {
      plugins: [svgLoader()],
    })
  },
}

Discussion

ログインするとコメントできます