これはなに
Vuetify 2で動いていたv-img
のコードがVuetify 3で動かなくなったので対処した。
そのときの対処法を記す。
環境
- node v19.3.0
- Vue 3.2.45
- Vite 3.2.5
- Vuetify 3.0.5
- typescript 4.9.4
背景
Vuetifyを2から3にアップグレードした。
そしたら、いままで読み込めていた画像が読み込めなくなった。
どうやらpath aliasで定義されていた@
がきちんと処理されていない模様。
Vuetify 2だと、下記の記述で問題なく画像が読み込まれていた。
<v-img src="@/assets/logo.png" />
この記述をVuetify 3で使うと、下記のエラーが出て、画像は読み込めない。
Failed to load resource: the server responded with a status of 404 (Not Found)
ちなみに、Vuetifyのv-img
タグではなく、普通のimg
タグだと問題なく読み込める。
すなわち、下記の書き方なら、きちんと画像が表示される。
<img src="@/assets/logo.png" />
普通のimg
タグなら読み込めるため、path aliasは問題なく設定できていると思われる。つまりv-img
タグが@
をうまく処理できていないとみられる。
何が原因だったのか?
Vuetify 3が動くVue 3では、ビルドツールがvue-cliからViteに移行した。 どうやらその関係で動かなくなったっぽい。
対処法
動作が確認できている対処法は次の2つ。 どちらかの対応を取ればよい。
- 画像ファイルをimportする
- 画像ファイルをpublic配下に配置する
どちらの方法が良いのか?
画像ファイルをimportする方法では、画像ファイルも含めてビルドされる。 一方で画像ファイルをpublic配下に配置する方法では、画像ファイルはビルドに含まれない。 よって、コンポーネントの一部として用いられる画像はimportし、それ以外の画像はpublic配下に置くのが良さそう。
1. 画像ファイルをimportする方法
<script>
ブロック内で画像ファイルをimportし、それを利用する方法。
まず、<script>
ブロックで、適当な変数名で画像ファイルをimportする。
このときはpath aliasである@/
が使える。
<script setup lang="ts">
import logo_img from '@/assets/logo.svg';
</script>
次に、<template>
ブロック内に画像を配置する。
src
属性は変数になるのでbindさせる必要がある。
ゆえに、src
ではなく:src
(あるいはv-bind:src
)にしなければならない。
<template>
<!-- ... -->
<v-img contain height="300" :src="logo_img" />
<!-- ... -->
</template>
これで表示自体はできるようになる。
yarn dev
でローカルサーバを立ち上げると、きちんと画像が表示される。
しかし、このままだとTypeScriptで下記のエラーを吐かれる。
モジュール '@/assets/logo.svg' またはそれに対応する型宣言が見つかりません。ts(2307)
ビルド時にも、下記のエラーが発生してビルドが通らない。
error TS2307: Cannot find module '@/assets/logo.svg' or its corresponding type declarations.
これはTypeScriptの仕様である。TypeScriptでコード以外のアセットを利用するためには、そのインポートに対して型を繰り下げる必要がある。どうすればよいかというと、公式 にもあるように、.svgファイルのcustom definitionsを用意すればよい。
まず、custom.d.tsファイルを作り、svgの拡張子の型を定義する。
declare module '*.svg' {
const content: any;
export default content;
}
次に、定義した型をTypeScriptのコンパイラに伝えるため、tsconfig.jsonにcustom.d.tsファイルの存在を追記する。
{
"include": [
"src/**/*.ts",
"custom.d.ts"
]
}
こうすると、TypeScriptのエラーは解消され、yarn build
も通るようになる。
2. 画像ファイルをpublic配下に配置する方法
これはもっと簡単にできる。
まず、画像ファイルをpublicディレクトリ下に配置する。
たとえば、public/assets
ディレクトリ内にlogo.pngを置く。
そして、それをv-img
のsrc
で参照する。
次に、<template>
ブロック内で画像ファイルを参照する際、src
属性に/assets/logo.png
を指定する。例を次に示す。
<template>
<!-- ... -->
<v-img contain height="300" src="/assets/logo_test.svg" />
<!-- ... -->
</template>
これで、画像ファイルが正常に表示される。
まとめ
Vuetify 3でv-img
が動かなくなった場合、以下の2つの方法で対処できる。
- 画像ファイルをimportして使用する
- 画像ファイルをpublicディレクトリ下に配置して使用する
どちらの方法でも、画像の表示は問題なくできる。コンポーネントに密接に関連する画像などはimportし、それ以外の画像はpublicディレクトリ下に置くという使い分けが適切だろう。