この記事をおすすめしたい人
- Nuxt3で画像が表示できなくなった人
- サブディレクトリにデプロイしたら画像が表示されない人
- つまりオレ
Nuxt v3の調査、画像のパスの指定編です。
Nuxt3ではCommonJS(何か分かってない)からESM(何か分かってない)へ移行したことで、requireが使えなくなりました(分かる)。
モジュールの読み込みはimport使えば簡単に移植できたんですが、imgタグのsrcでこんな↓風にrequireを使っていたのが全滅でした。
:src="require('~/static/img/bg.jpg')"
:src="require('~/assets/arrow.svg')"
Nuxt3ではどのように画像パスを指定すればいいのか調べていきます。
static(public)フォルダの挙動
まず「static」フォルダは「public」フォルダへ変更になったので配置に注意してください。
publicフォルダ内の画像は基本的にはこの↓書き方で問題なかったです。
<img src="/img/banner.jpg">
相対パスとか久々に書いたぜ…。
ネットで調べてると変数の時にダメってのが多かったんですが、うちではこれ↓で問題なかったです。
<img :src="'/img/banner.jpg'">
<img :src="'/img/banner_' + i + '.jpg'">
え、いや、どうだろ。 確か問題なかったはず。 少なくともローカル環境では今もちゃんと機能してます。
問題が出るケース
サブディレクトリの時に問題が出ました。
デフォルトでベースURLが「/」になっているせいで、ドメインルートではなくサブディレクトリ(「/test/」とか)にアップすると、ルートからの相対パスで探すせいで画像が見つかりません。
そこでnuxt.config.tsにこの↓ようにベースURLを指定してやると解決します。
app: {
baseURL: process.env.NODE_ENV === 'development' ? '/' : '/test/',
},
開発環境では「/」、ビルド時には「/test/」。
ところがこの際に変数で書いてたこの↓パターンが表示できなかったです。
<img :src="'/img/banner.jpg'">
<img :src="'/img/banner_' + i + '.jpg'">
ベースURLが反映されてなくて、ルートからの相対パスになってました。
CSSの挙動
こう↓書いてたものを、
url("~static/img/bg.jpg");
これ↓ではダメで、
url("~public/img/bg.jpg");
こう↓書くとちゃんと動きました。
url("/img/bg.jpg");
サブディレクトリの場合もベースURLを変更していれば正しく反映されました。
assetsフォルダの挙動
オーソドックスなこの↓書き方ではそもそもエラー。
<img src="~/assets/img/banner.jpg">
<img src="@/assets/img/banner.jpg">
いや、えっ!?
公式に出来るって書いてない?
変数として囲う↓ととりあえずエラーはでなくなりました。
<img :src="'~/assets/img/banner.jpg'">
<img :src="'@/assets/img/banner.jpg'">
ところが展開されたHTMLを見てもsrcの中身がこう↓なっていて表示されませんでした。
~/assets/img/banner.jpg
@/assets/img/banner.jpg
CSSでも同じ挙動でした。
assetsフォルダ使えなくなったの?
正直、staticフォルダとassetsフォルダの違いがよく分かってなくて、assetsフォルダに軽いSVG入れてたら勝手にインラインにしてくれるとか、それくらいしか分からないです。 今後は全部publicフォルダに放り込めばいいのかな?
解決方法
assetsフォルダはまぁ置いておくとして、staticの方は「サブディレクトリ」かつ「srcに変数を入れている」状況で正しく表示できませんでした。
その理由は変数にするとベースURLが反映されていなかったから。
てことは、変数で操作するときにもベースURLを反映してやればいいだけです。
nuxt.config.tsでこの↓ようにベースURLが設定されているとして、
app: {
baseURL: process.env.NODE_ENV === 'development' ? '/' : '/test/',
},
この値へのアクセスはこの↓ようにやります。
this.$config.app.baseURL
これをcomputedとかでこの↓ように設定して
baseURL() {
return this.$config.app.baseURL
},
呼び出し側でこう↓書けばいいだけです。
<img :src="baseURL + 'img/banner.jpg'">
<img :src="baseURL + 'img/banner_' + i + '.jpg'">
これだと相対パスの先頭にスラッシュの有無が生まれてしまうから、computedをこう↓定義して、ベースURLの末尾スラッシュを削除すると、
baseURL() {
return this.$config.app.baseURL.replace(/\/$/, '')
},
呼び出し側も「/」からスタートするので、変数の時とそうじゃない時で同じ書き方ができます。
<img :src="baseURL + '/img/banner.jpg'">
<img :src="baseURL + '/img/banner_' + i + '.jpg'">
こういう仕様のimgタグをオーバーライドしたコンポーネントを作ってしまってもよさそう。
作りました。
<template>
<img :src="baseURL + src">
</template>
<script lang="ts">
export default defineNuxtComponent({
props: [
'src',
],
computed: {
baseURL() {
return this.$config.app.baseURL.replace(/\/$/, '')
},
},
})
</script>
これでimgタグと同じように使えて、srcだけbaseURLが反映されたものになります。 コンポーネントなので閉じタグ必須。
とりあえずこれでうちでは思った挙動になりました。
Nuxt.js v3の目次
- 第1回 インストール方法とかフォルダ構成の違いとか
- 第2回 nuxt.config.jsの書き方の違い
- 第3回 注意が必要そうなモジュール
- 第4回 コンポーネントのscriptの書き方がめっちゃ変わった
- 第5回 trailingSlashに手動で対応
- 第6回 injectの代用品を3つ紹介
- 第7回 v-forとv-ifの併用の代替案
- 第8回 defineNuxtComponentは救世主!
- 第9回 composablesがめっちゃ強いかもしれない
- 第10回 手動でAMPに対応する
- 第11回 フック一覧を簡単に調べた
- 第12回 axiosの代用品(useFetch、$fetch、useAsyncData)