Nuxt.js(vue.js)でhtml-loaderを使ってSVGファイルをインラインで呼びだしたらscopedが使えなかったメモのほうで、html-loader使ったときにscopedが利用できないと記載しvue-svg-loaderならできるのではと思い引き続き試してみました。
vue-svg-loaderのBasic configuration Nuxt.js (1.x / 2.x)を見ながら下記のように設定。
hoge.inline.svgだけインラインで呼んでそれ以外は背景画像などでも利用できるように調整しています。
export default {
build: {
extend (config, ctx) {
const svgRule = config.module.rules.find(rule => rule.test.test('.svg'));
svgRule.test = /\.(png|jpe?g|gif|webp)$/;
config.module.rules.push({
test : /\.inline\.svg$/,
use: [
'vue-loader',
'vue-svg-loader',
],
});
config.module.rules.push({
test: /\.svg$/,
exclude: /\.inline\.svg$/,
use: [
'file-loader',
],
});
}
}
}
この設定したら、だいぶエラー文はしょってますが、モジュールが見つからないとエラー文が表示されました。
Cannot find module
色々検索しまくったんですが、公式ドキュメントのFAQに解決策を発見。
SVGコンポーネントをTypescriptがどう扱っていいか知らせる必要があり、型定義をしないといけないと。私自身が最初構築した設定ではないが、scriptのところに lang="ts"
とあったのでなんとなくTypescriptなんだろうなと思ってはいました。
Typescriptでの型定義の仕方を調べていたら、下記ドキュメントがあり、 vue-shim.d.ts
に記載しルートディレクトリに配置でうまくCannot find module のエラーは乗り切ることができました。
が!!!アイコンの回りに謎の囲みがでてる謎。。。透明な四角のパスがsvgに入っていてデザイン的に領域を確保するために入れてるものに線が引かれてしまっているよう。
実際のコードがどのように変換されているか確認しました。
■ロード前のsvgファイル
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 14 14"><polyline style="fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="4,1 11,7 4,13"/><rect style="fill:none;stroke:none;" width="14" height="14"/></svg>
■画面に表示されたsvg要素
<svg data-v-7e0418de="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" class="hoge"><path fill="none" d="M4 1l7 6-7 6"></path><path fill="none" d="M0 0h14v14H0z"></path></svg>
無事data-v-hogeは付与されてscopedが利用はできましたが、コードが変わってしまっては困りますので引き続き調査。
全く同じ症状ではないですが、svgの中身が変更されてしまっているものを発見。svgoが入っていて圧縮がかかっているので、webpackでoptionの設定を試してみました。
svgoではいろいろなオプションがあり、上から試していった結果
convertStyleToAttrsの機能をfalseにすることで解決しました。
style属性をよしなな属性に変換しコードを短くしてくれる機能ですかね。変換後のコード見ると確かにそうなってますね。それ以外にもいろいろ変更されてしまうものがデフォルト入ってるので、全部みて不要なものはfalseにする必要がありそうです。
基本不要だと思ってる全部falseの機能が欲しいくらいですね。
export default {
build: {
extend (config, ctx) {
const svgRule = config.module.rules.find(rule => rule.test.test('.svg'));
svgRule.test = /\.(png|jpe?g|gif|webp)$/;
config.module.rules.push({
test : /\.inline\.svg$/,
use: [
{ loader: 'vue-loader' },
{ loader: 'vue-svg-loader',
options: {
svgo: {
plugins: [
{ convertStyleToAttrs: false },
],
}
},
},
],
});
config.module.rules.push({
test: /\.svg$/,
exclude: /\.inline\.svg$/,
use: [
'file-loader',
],
});
}
}
}