【Nuxt3】requireがなくなったせいで画像が表示できない問題を解決

シェアする:

この記事をおすすめしたい人

  • 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が反映されたものになります。 コンポーネントなので閉じタグ必須。

とりあえずこれでうちでは思った挙動になりました。

シェアする: