Laravelも10がリリースされ開発環境を新たに作成、LaravelはPHP8.1以上が必要とのことなので、AlmaLINUX9を使って仮想マシンに構築していきました。そして、最新のLaravelを導入するからには、いっそのことバックエンド処理用フレームワークも導入しようと、ひとまずVue3.3を導入。
ここまでは良かったのですが、問題はどうやってそれをブラウザで表示し、かつVueを起動させるかです。
ひとまずVue3.3とLaravel10を導入
LaravelとVite、そしてVue3.3の導入は以下の記事を参考にしています(PHP8.1は事前にインストールしておいてください)。
ところが、この記事と全く同じようにnpm、php artisanを順番に起動していっても、仮想マシンの場合Vueが読み込んでくれません。かといって無理にホストやポートを合わせてみても、server invalidなどと表示され、うまく接続されません。
解決方法
解決方法を調べていたところ、HMRを設定するといいようです。
Windows - Failed to load when loading vite dev server resources
この賞賛の多い回答にしたがってvite.config.jsを以下のように追記します。ついでにbootstrapも設定しておきます。
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import path from 'path';
export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/sass/app.scss',
'resources/js/app.js',
],
refresh: true,
server:{
hmr:{
host: 'localhost'
}
}
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
'~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap') //bootstrap
},
},
});
これでjsフレームワークは起動ホストとポートにしたがって起動してくれます。ですが、これで終わりではありません。今度はviteに対するホストとポートの設定、それからLaravelに対するホストとポートの設定も必要です。
vite側のホスト・ポート設定
vite側のホスト、ポート設定ですが、HMRを使用したことで、ホストは明示的に記述しないと、Laravelはそのパスのまま読み込もうとするので、packege.jsonにホスト情報を追記しておきます。
"scripts": {
"dev": "vite --host 0.0.0.0", //ここにホスト情報を追記する
"build": "vite build"
},
なお、デフォルトポートは5173ですが、これはそのままにしておいても大丈夫です。
Laravel側のホスト設定
Laravel側はphp artisanコマンドで制御します。
#php artisan serve --host 0.0.0.0
これでポートを8000とした場合にルートアドレスでVueが起動すれば成功です。失敗している場合は開発コンソールで、jsの設定部分を見直してください。
VueとLaravelを同時に起動したい場合
これが一番の難問でした。現状ではViteとLaravelの双方に対してサーバを起動しないといけなく、CUIが最低2基必要になります(Virtual BoxのターミナルとTeraterm、Puttyなど)。その解決方法を調べていたのですが、Viteをビルドしておくだけで大丈夫です。
npm run build
リビルドが面倒な場合はコマンドを合体させましょう。
#npm run build && php artisan serve --host 0.0.0.0
あとは同じようにLaravelを起動すれば、App.jsファイルで設定したidに対してVueを起動することができます。Vite3はVue3.3にも対応しているので、setup script記法を用いれば、上記リンクのカウンターもここまでシンプルに書けます。
<template>
<div class="page">
<p>{{ counter }}</p>
<button @click="counter += 1">
click!
</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
const counter = ref(0)
</script>
vue-routerを用いる
ここからが本題で、この状態でvue-routerを設定します。Vue3.2以上はvue-router4からでしか対応していないので、あらかじめインストールしておきます。
#npm install vue-router@4
ルーティング設定
ここで引っかかったのが、どうやってルーティング情報をLaravelに受け渡すかです。各種サイトや記事ではよくapp.blade.phpにrouter-viewタグを付与したりしていますが、Laravel10では#appにマウントできるのは単一コンポーネントのみとなっています。
そこで#appにSPA情報を書き込んでいく手法を用いることにします。したがって#appの領域には何も記入しない
のが正解です。
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Vue Laravel SPA') }}</title>
<!-- Styles -->
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<!-- この領域はVueが起動している -->
<div id="app">
<!-- 何も記入しない -->
</div>
<!-- Scripts -->
</body>
</html>
ルーティングの設定ファイル
重要な役割を担うのがルーティング用の設定ファイルです。要領はVue-CLIのSPAと同じで、トップに置きたいページ(ブラウザを設定したいページ)をルートコンポーネントにしておきます。
Laravelからresouces/app.jsを編集します。
//ビルドしてから使用する依存ライブラリ
import './bootstrap';
import '../sass/app.scss'; //bootstrapを使う場合は必須
import {createApp } from 'vue';
import {createRouter,createWebHistory } from 'vue-router';
import App from './components/AppComponent.vue'; //ルートコンポーネント
import ItemsComponent from './components/ItemsComponent.vue';
import DetailComponent from './components/DetailComponent.vue';
//新規に作りたいVueコンポーネントをここに追記していく
const app = createApp(App); //ルートコンポーネントを主体とする
//ルーティング設定
const routes = [
{
path: '/items',
name: 'Items',
component: ItemsComponent,
},
{
path: '/detail/:id',
name: 'Detail',
component: DetailComponent,
props: true,
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
//app.blade.phpの#app領域にマウントしていく
app.use(router).mount("#app");
ルートコンポーネント
そして、遷移用のブラウザ(router-view)タグはルートコンポーネントに置いておきます。
<template>
<HeaderComponent />
<router-view />
</template>
<script setup>
import HeaderComponent from './HeaderComponent.vue'
</script>
これで#appに複数のコンポーネントを呼び出すことができます。この環境で構築していったのが以下の記事の制御プログラムになります。