Laravel + Viteで画像が表示されない問題から学ぶLaravel+Viteの連携・仕組み

Laravel + Viteで画像が表示されない問題から学ぶLaravel+Viteの連携・仕組み

ここ最近、Laravelでの開発をする機会があります。Laravel12のキャッチアップも頑張っていますが、まあLaravelは毎度変更が多いですね…

Bladeで記載するくらいのライトな感じの需要もあると思うのですが…

さてそれはさておき、私もキャッチアップする中で、最近のLaravelにおいて採用されているViteとの関連性についてしっかりと整理して、自分なりにブログに書いてみようと思うに至りました。

前提として、以下の環境が用意されているものとして説明をしていきます!ただし、今回のブログで取り上げることは、Laravel12でも使える知識だとは思います。

  • Laravel 11
  • Viteを使用
  • フロントはBladeで書いてることを前提

Laravel + Viteにおける2つのサーバ

Viteを活用する形でLaravelプロジェクトにおけるフロントエンドの開発を行う際は、PHP(Laravel)が動くサーバとは別にnpm run devコマンドを打つなどして、Viteでの開発サーバ(通常はPORTが5173)を起動することになると思います。

そもそも、なぜ別途サーバを立ち上げる必要があるのでしょうか?

ここは、近年のフロントエンド開発の歴史を紐解いていくことで、答えが掴めていきます。

フロントエンド開発の進化と変換の必要性

近年のフロントエンド開発においては、TypeScriptやReact・Vueなどの技術を利用することがある種当たり前になってきた感があります。(少し前だとSass)

これらの技術に共通する特徴は「ブラウザが直接読み込むことができないファイル形式である」です。

TypeScriptやReact・Vueなどを利用した場合、最終的にはこれらをブラウザが読めるノーマルJavaScript(CSS)に変換(トランスパイル)する必要があります。

ノーマルJavaScript(CSS)への変換をLaravel起動サーバが行うとどうなるのか?

では、先ほど言及したノーマルJavaScript(CSS)への変換作業をLaravelサーバが直接行うとどうなるのでしょうか?

そうなると、それこそCSSを1px修正しただけで、都度都度ノーマルJavaScriptへの変換作業を行う必要があり、アプリケーション全体を巻き込んだ重たい処理が走ります。

そうすると、開発のスピード感が損なわれてしまうことは容易に想像できます。

考えられた分業制の仕組み

この問題を解決するために考えられたのが「JavaScriptの変換作業担当のサーバを別に設ければいいのではないか」というものです。

開発中、TypeScriptやReact/Vueで書かれたソースコードが編集された際に、メインのアプリケーションサーバとは別に、JavaScript への変換作業を専門に行うサーバを用意する仕組みです。

この仕組みをHMR(ホットモジュールリプレイスメント)といいます、

最近のLaravelあたりでは、これらのHMRを変換作業をViteが担当しています。HMRのおかげで、開発中、CSSやJavaScript等のフロントエンド開発においても、スムーズな開発を行うことができるようになります。

Laravel+Viteにおいて重要なpublic/hotの存在

さて、ここからはLaravelにおいてViteを使い開発用サーバが立ち上がってからの仕組みを見てみたいと思います。

npm run dev等で開発用サーバが立ち上がると、publicフォルダの中にhotというファイルが作成されるのがわかります。

このhotファイル、謎の存在のように見えるのですが、めちゃくちゃ重要な役割を担っています!

  • hotファイルが存在する場合・・・LaravelアプリケーションはCSSやJSはViteサーバに存在するものを読み込みしに行きます。
  • hotファイルが存在しない場合・・・Laravelアプリケーションはpublicフォルダ内にあるCSSやJSを読み込みしに行きます。

いわば、Viteサーバが立ち上がっているかどうかをhotファイルの存在有無で判断することができるようになるわけですね!

Bladeファイルで使用する@viteというディレクティブがありますが、このディレクティブもhotファイルの有無を確認し、出力するURLを自動で切り替えてくれるというものになっています!

■public/hotが存在する場合

<script type="module" src="http://localhost:5173/@vite/client"></script>

<link rel="stylesheet" href="http://localhost:5173/resources/css/app.css">

■public/hotが存在する場合

<link rel="stylesheet" href="http://localhost/build/assets/app-xxxxx.css">

よくできた仕組みですねー。

画像が表示されない問題の原因

さて、ここからが本題。そもそもこの記事を書こうと思うに至ったのは、開発中に画像が表示されない現象が発生した際に、対処法を私が忘れてしまっていたことにあります。

ここまでJavaScriptやCSSについての扱いを中心に書かせていただきましたが、では画像についてはどういう扱いになるのでしょうか?

画像は、当然公開されるページにおいて使用されることになります。

そしてLaravelでは、公開データ(画像等)は基本的にpublicフォルダの中に置くこととなります。

では、開発中(npm run devの起動中)に、CSSで背景画像を指定した場合、具体的には

background-image: url('/assets/images/hogehoge.png');

のようなものを指定したとしたら、どういう挙動になるでしょうか?

先ほど申し上げたように、開発中(npm run devの起動中)はViteサーバ(port5173)が起動します。

そしてhotファイルが存在することによって、画像もViteサーバから読み込みしようとしてしまうのです。

一方、publicフォルダの中に置かれている画像データは、Laravelサーバの管轄下になります。

つまり、この状態のままだと「そんな画像ないですよ」というエラーが表示されてしまい、画像が表示されなくなってしまうのです…

画像が表示されない問題の解決策

では、画像が表示されない先述の状況を解決するにはどうしたらいいのでしょうか?

考え方としては、「特定のケースにおいて転送処理を行い、Laravelサーバにある画像を読み込みしにいく」でOK!

実際に上の考え方を実現するために、vite.config.jsを以下のようにしてみます。

// vite.config.js

import { defineConfig } from 'vite';

import laravel from 'laravel-vite-plugin';


export default defineConfig({
  
  // ... pluginsなど
  server: { 
    proxy: {

    // '/assets'で始まるリクエストをLaravelサーバーに転送する

    '/assets': {
        target: 'http://localhost:8000', // Laravel SailのデフォルトURLの場合で紹介
    }

  }

}

上記のように、proxy設定を追加します。

この設定を行った場合、先ほどの背景画像の表示については以下のような処理が順番に行われます。

  1. ブラウザは「`/assets/images/logo.png`」と書かれているので、Viteサーバ(5173)に画像を見に行こうとする。. Viteサーバは指定された画像を探そうするが、vite.config.jsの記述内容を見て「あ、`/assets`フォルダか!じゃあViteサーバじゃなくてLaravelサーバを見に画像を見に行こう」という動きに変わる
  2. Viteサーバ は Laravelサーバーに対して、これこれこういうわけで、「`/assets/images/logo.png`をください」とお願いをする
  3. Laravelサーバーはリクエストのあった画像を探し、「はい、どうぞ」とViteサーバに対して画像を渡す。
  4. Viteサーバは、: 受け取った画像を、あたかも自分が持っていたかのようにブラウザに渡す。こうして無事に画像が表示される。

これで万事解決!仕組みを理解すれば忘れにくくなるだろうなぁ…ということをこの記事を書きながら僕も痛感しています。

もそもLaravelにおいて画像はどこに置くべきか?

さて、今回のことを機に、改めてLaravelにおける画像置き場について調べてみました。

ユーザーがアップロードした画像などはS3など外部サービスを利用することが多いのだろうと思いますので、ここではサイト内で使用する画像に絞って画像の配置場所はどこが適切なのかについて調べてみました。

readouble.comを見てみると、publicディレクトリについて以下のような記述がされています。

publicディレクトリには、アプリケーションへの全リクエストの入り口となり、オートローディングを設定するindex.phpファイルがあります。また、このディレクトリにはアセット(画像、JavaScript、CSSなど)を配置します。

基本的には、この記述が全てでは?というのが諸々調べた上での結果・見解でした。

まとめ

ということで、開発中と本番とでどういう挙動の違いがあるかを理解することは改めてものすごく大事だなと思った今回の内容でした!

こうやってしっかりと調べて手を動かすことで、自分の血肉にすることの大切さを痛感しました。

AIも便利ですが、「AIが言ってるからそうなんだ」で終わらないよう、今一度気を引き締めて行きたいと思います!

シェアする

  • このエントリーをはてなブックマークに追加

フォローする