vue-svg-loaderとfile-loaderを使い分ける
vue-svg-loaderとfile-loaderを使い分ける
2020/01/21

やりたいこと

SVGをVueComponentとして読み込む場合と、ファイルパスとして読み込む場合のどちらにも対応したい。

例えば、アイコンなどは、vue-svg-loaderを使ってVueComponentとして読み込んで、色や塗り、線などをスタイルの変更をしたい。

<template lang="pug">
  download-icon.icon
</template>
<script>
import DownloadIcon from '@/assets/images/icons/download.svg'

export default {
  components: {
    DownloadIcon,
  },
}
</script>
<style>
  .icon {
    fill: #000;
  }
</style>

ロゴ画像の場合は、ファイルパスとして読み込んで画像として出力したい。

<template lang="pug">
  img(src="@/assets/images/logo.svg")
</template>

しかし、VueCLIのデフォルトの設定やvue-svg-loaderのリファレンスの設定だと、どちらか一方の方法でしか読み込めないので、設定方法を変更する必要がある。

実現方法

WebpackにoneOfという設定がある。

oneOfを使うと、一つの条件(今回の場合は、test: /\.svg/ )に対して、どのLoaderを使うかを指定できる。

公式リファレンスでは、cssに対して、hoge.css?inline?inlineを付けた場合は、url-loaderで読み込み、hoge.css?fileとした場合は、file-loaderで読み込む設定となっている。

今回紹介するのは、SVGファイルに対して、デフォルトではfile-loaderで読み込み、@/assets/images/icons/download.svg?component?componentと付けた場合は、vue-svg-loaderで読み込みVueComponentになるように設定する。

実装

Webpackの設定は以下のようになる。

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.svg$/,
        oneOf: [
          // VueComponent
          {
            resourceQuery: /component/,
            use: 'vue-svg-loader',
          },
          // デフォルト
          {
            use: 'file-loader',
          },
        ],
      },
    ],
  },
}

VueCLIを使っている場合

VueCLIの場合は、すでにsvgに対するルールが設定されているので、それを書き換える必要がある。

vue.config.jsに以下の設定を追加する。

module.exports = {
  //...
  chainWebpack: (config) => {
    const svgRule = config.module.rule('svg')
    svgRule
      .oneOf('component')
      .resourceQuery(/component/)
      .use('vue-svg-loader')
      .loader('vue-svg-loader')
      .end()
      .end()
    svgRule.oneOf('normal').uses.merge(svgRule.uses.entries())
    svgRule.uses.clear()
  },
}

以上の設定で、VueComponentとして読み込むこともできるし、ファイルパスとして読み込むことができる。

まとめ

以下のように、VueComponentとファイルパスの両方で、SVGを読み込むことができる。

<template lang="pug">
  div
    download-icon.icon
    img(src="@/assets/images/logo.svg")
</template>
<script>
import DownloadIcon from '@/assets/images/icons/download.svg?component'

export default {
  components: {
    DownloadIcon,
  },
}
</script>
<style>
  .icon {
    fill: #000;
  }
</style>