Vue3 + ViteでSVGファイルを読み込む方法
久しぶりに案件でVueを触り、Ver3.2から導入されたComposition APIで書き方がまるっきり変わって浦島太郎状態ですが、型サポートが手厚くなり、TypeScriptが扱いやすくなって嬉しいです
今回はVue3+ViteでSVGファイルをbabel-plugin-inline-react-svgのようにSVGファイルを読み込ませる際に、色々つまづいたのでメモします
SVGファイルを読み込む方法
手動でコンポーネント化
Vueの公式ドキュメントの編集可能なSVGアイコンシステムの項目で紹介されていますが、SVGファイルをVueファイルのコンポーネントとしてラップすることで、SVGファイルを読み込ませることができます
このやり方は一番手軽ですが、都度SVGファイルを変換するのが手間だったため、今回自分はこの方法を採用しませんでした
<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の設定ファイルにプラグインを追加します
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
です
<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.
BuilderがViteの場合、Storybookのmain.jsでViteの設定ファイルと同様に、プラグインを追加することで解決できます
const { mergeConfig } = require('vite')
const svgLoader = require('vite-svg-loader')
module.exports = {
// ...
async viteFinal(config) {
return mergeConfig(config, {
plugins: [svgLoader()],
})
},
}
Discussion