1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

Laravel × Vite × jQuery のビルド・デプロイで慌てた人の備忘録

Last updated at Posted at 2024-07-17

Laravel × Vite × jQuery のプロジェクトでビルド・デプロイした際に色々うまくいかないことがあったので、自分のための備忘録として記載します。

前提

使用バージョン

以下のバージョンを使用しています。

PHP 8.3
Laravel 10.48
Vite v5.2
Node v20.12

ビルド・デプロイ時に遭遇したエラー

① 静的アセットの設定をしておかないとビルド時に画像が読み込まれない :confounded:

<img>から呼び出す画像があったため、以下の記事を参考にして対応しました。

今回はプロジェクトのresources/imgディレクトリに画像ファイルを配置していたので、以下のように追記しました。

resources/js/app.js
+ import.meta.glob([
+     '../img/**',
+ ]);

② jQueryが読み込まれない

Uncaught ReferenceError: jQuery is not defined

ビルド後に上記のエラーが出ており、jQueryが読み込まれていないんだなと察します。その時のapp.jsは以下でした。

app.js
import './bootstrap';
import './jquery-3.7.1.min';

調べると、jQueryをインストールする必要があるようです。npm install jqueryします。

npm install jquery 

以下を参考にして、設定等を変更します。

app.js
import './bootstrap';
- import './jquery-3.7.1.min';
resources/js/bootstrap.js
+ import $ from 'jquery';
+ window.jQuery = window.$ = $
vite.config.js
export default defineConfig({
+    build: {
+        rollupOptions: {
+            output: {
+                globals: {
+                    jquery: 'window.jQuery',
+                }
+            }
+        }
+    },
});

これでjQueryも無事に動くようになりました:relieved:

どうしてViteでjQueryを読み込めなかった?

Viteで以下の様に読み込んでいるのに、ビルドした時にjQueryを読み込まなかった理由が気になりました。

import './jquery-3.7.1.min';

良い調べ方が思い浮かばなかったので、生成AIのphindさんに聞いてみました。

Integrating jQuery with Vite can be challenging due to differences in module systems and how Vite optimizes dependencies. Vite uses ES modules, whereas jQuery is traditionally used as a global variable attached to the window object. This discrepancy can lead to issues like $ is not defined errors when trying to use jQuery in a Vite project.

回答を意訳とすると、

  • モジュールシステムの違いと、Viteが依存関係を最適化する方法により、ViteとjQueryの統合は難しい
    • Vite : ESモジュール
    • jQuery : グローバル変数としてwindowオブジェクトにアタッチされて使用される

モジュールシステムの違いが大きいのだろうか...:rolling_eyes:
※ もう少し詳しく調べて追記したいと思います

httpでアクセスしようとしてChromeにブロックされる

CSSが反映されていない!とコンソールを確認したところ「HTTPS経由で読み込まれたページが、HTTP経由でスタイルシートをリクエストしようとしてたからブロックした」旨のメッセージが...:fearful:

Mixed Content: The page at 'https://xxxx.jp' was loaded over HTTPS, but requested an insecure stylesheet 'http://xxxx.jp/build/assets/app-xxx.css'. This request has been blocked; the content must be served over HTTPS.

ひとまずAppServiceProvider.phpURL::forceScheme('https');を追加することで解消しました。

AppServiceProvider.php
// boot() に追加
+ if (! app()->isLocal() && ! app()->runningUnitTests()) {
+     URL::forceScheme('https');
+ }

上記解決策は、URLスキーマを強制的にhttpsにしているものです (Vite で何らかの設定を行えば、Laravelでわざわざスキーマを強制しなくてもいけそうではあるんですがやり方が分からず...)。

Apacheの設定

唐突ですが、今回のシステムにおけるApacheの設定の話をします。

今回はApacheのドキュメントルート/var/www/html以下に

  • APIのapiディレクトリ
  • 管理画面のadminディレクトリ
  • 利用者向け画面userディレクトリ
    があり、各ディレクトリごとにLaravelプロジェクトがあります。
/var
└─ www
   └─ html
      ├─ api   // APIのLaravelプロジェクト
      ├─ admin // 管理画面のLaravelプロジェクト
      └─ user // 利用者向け画面のLaravelプロジェクト

パス/apiにリクエストが来た場合は/var/www/html/apiで処理を行う...というのでApachevhost.confは以下の設定になっています。

vhost.conf
<VirtualHost *:80 *:443>
    ServerName xxxx.jp
    DocumentRoot /var/www/html

    <Directory "/var/www/html">
        Options FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    RewriteEngine On

    # /api へのアクセスは /var/www/html/api/public へ
    RewriteCond %{REQUEST_URI} !^/api/public
    RewriteRule ^/api(/.*)?$ /api/public$1 [L]
    
    # /admin へのアクセスは /var/www/html/admin/public へ
    RewriteCond %{REQUEST_URI} !^/admin/public
    RewriteRule ^/admin(/.*)?$ /admin/public$1 [L]

    # /user へのアクセスは /var/www/html/user/public へ
    RewriteCond %{REQUEST_URI} !^/user/public
    RewriteRule ^/user(/.*)?$ /user/public$1 [L]

    DirectoryIndex public/index.php

</VirtualHost>

この設定の影響を受けたと見られるエラーが以降に続きます。

ASSET_URLにパスを指定しなかったのでjsファイルなどが404になる

続いては、Laravelの.envファイルの環境変数の話です。

コンソールでjsファイルなどが軒並み404エラーになって慌てました。
どうやらbuild/assets/app.jsを見に行って404になっていたようです。

先述したように、https://xxxx.jp/userパスにアクセスされた場合、/var/www/html/user/publicで処理を行うようにしています。
Apacheさんにはuser/build/assets/app.jsを取得して欲しいので、ASSET_URLにパスを追加します。

.env
- ASSET_URL="${APP_URL}"
+ ASSET_URL="${APP_URL}/user"

baseにパスを指定しなかったのでCSS内にある画像ファイルが404になる

やっとCSSが読み込まれた!わーい!と喜んでいたのもつかの間。
コンソールを見ると、CSS内で使用している画像が読み込まれていない...:cold_sweat:

エラー内容的に、再びパスの/userが欠けているがゆえのエラーだったので、vite.config.jsに以下を追記します。

vite.config.js
+ base: '/user/build/',

この設定を追加して、デプロイ時にCSSの画像などが参照されて一安心、としていたら、
今度はローカル環境で開発中(npm run devを実行)にCSSが反映されないときた...。まあbuildってパスに入っているし...。

そのため、baseを「ローカル環境なら/user/、それ以外の環境なら/user/build/」と設定することで凌ぐことにしました。


このあたり、かなり手探りなので、もっといいやり方があるよというのがあればご教授お願いします:bow_tone1:

npm run devを動かしている時、現在の環境をローカル環境としたいと思います。

じゃあViteのimport.meta.env.DEVを使ってこうだ!

vite.config.js
base: import.meta.env.DEV ? '/user/' : '/user/build/',
TypeError: Cannot read properties of undefined (reading 'DEV')

ダメだった...:grimacing:
import.meta.env.ENVvite.config.jsでは使えなさそうなのでprocess.env.NODE_ENVで判定するようにします。

npm run devの起動時に、NODE_ENV = localとなるように設定しました。

package.json
"scripts": {
-    "dev": "vite",
+    "dev": "NODE_ENV=local vite",
}
vite.config.js
- base: '/user/build/',
+ process.env.NODE_ENV === 'local' ? '/user/' : '/user/build/',

ひとまずこれでローカル環境での開発時にもCSSが読み込まれるようになりました。

余談 : npm run dev.envファイル

ローカル環境でnpm run devとしてViteを起動すると、LaravelのAPP_URL.env.developmentから読み込んでしまい困りました:confounded:

VITE v5.1.6  ready in 199 ms

  ➜  Local:   http://localhost:5173/user/
  ➜  Network: http://XXX.XX.X.X:5173/user/
  ➜  press h + enter to show help

  LARAVEL v10.48.4  plugin v1.0.2

  ➜  APP_URL: https://開発環境FQDN #.env.developのAPP_URL

違う、そうじゃない。.env.env.localAPP_URLを読み込んでおくれ...。

.envファイルの設定

.envファイルは4種類用意し、環境によってコピー元を変えるようにして運用しています。

  • .env.local:ローカル環境用ファイル
  • .env.testing:ローカル環境テスト用ファイル
  • .env.development:開発環境用ファイル
  • .env.production:本番環境用ファイル
.env
# .env.local
APP_ENV=local
APP_URL=http://localhost:8080

# .env.testing
APP_ENV=testing
APP_URL=http://localhost

# .env.development
APP_ENV=development
APP_URL=https://開発環境FQDN

# .env.production
APP_ENV=production
APP_URL=https://本番環境FQDN

Viteのモードと.envファイル

Viteの仕様として「モード」の仕組みがあり、devコマンドはdevelopmentモードで動作します。

特定のモードの env ファイル(例: .env.production)は、汎用の env ファイル(例: .env)よりも優先されます。1
今回で言えば、.env.development > .envの優先順位になっているようです。

では、モードにlocalを指定すれば良いのでは?

package.json
"scripts": {
-    "dev": "vite",
+    "dev": "vite --mode local",
},
npm run dev

> dev
> vite --mode local

error when starting dev server:
Error: "local" cannot be used as a mode name because it conflicts with the .local postfix for .env files.

モードにlocalは指定できなかった...ぐぬぬ...:innocent:

プロジェクトでは

  • .env.local : ローカル環境の環境変数
  • .env.development : 開発環境の環境変数

をセットしていました。

しかしnpm run devを叩く時はローカル環境なので、.env.developmentではなく、.env OR .env.localを読み込んで欲しいです。

なので今回は、npm run devを実行時に、.envのファイルを読み込んでもらうようにしました。Node v20.12.0以降で使えるprocess.loadEnvFile()を使用します。

vite.config.js
export default defineConfig({
+    define: {
+        // .envを読み込む
+        'process.env': process.loadEnvFile('.env')
+    },
});

npm run devを実行した際に、LARAVELのAPP_URLがローカル環境用の値になりました。

VITE v5.1.6  ready in 199 ms

  ➜  Local:   http://localhost:5173/user/
  ➜  Network: http://XXX.XX.X.X:5173/user/
  ➜  press h + enter to show help

  LARAVEL v10.48.4  plugin v1.0.2

  ➜  APP_URL: http://localhost:8080 # .env.localをコピーして作られた.envのAPP_URL

とりあえず今回は上記で対応したのですが、どうやるのが一番良かったのだろうな、と考える日々です。

  1. 環境変数とモード | Vite

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?