laravel のフロントは livewire が最も学習コストが低いとのことで livewire でいろいろ設定してきたのですが、 リアルタイムのチャットを思うように導入できず、vue を始めてみようと思いました。
livewire + reverb で動くようにはなったものの、タイムラグがあり時に起動しないことがありなんだか安定しません。
そこで livewire + pusher で実装しようと思ったのですが、chatGPT にお願いしても 100 時間ほど付き合ってもらったもののうまく行かず、 livewire の代わりに vue に挑戦しようと考えました。
vue は livewire より難しそうです。例によって hello world から。
composer create-project laravel/laravel my-laravel-vuecd my-laravel-vuenpm install vuenpm installnpm install @vitejs/plugin-vuenpm install -D tailwindcss postcss autoprefixernpx tailwindcss init -p
resources/js/components/HelloWorld.vue
<template> <div class="flex flex-col items-center justify-center min-h-screen bg-gray-100"> <h1 class="text-3xl font-bold text-blue-500">Hello, Laravel + Vue + Tailwind!</h1> </div></template>
resources/views/welcome.blade.php
<!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Laravel + Vue + Tailwind</title> @vite(['resources/css/app.css', 'resources/js/app.js'])</head><body> <div id="app"> <hello-world></hello-world> </div></body></html>
resources/js/app.js
import './bootstrap'; // Laravel の初期化コード
import { createApp } from 'vue';import HelloWorld from './components/HelloWorld.vue'; // HelloWorld コンポーネントをインポート
const app = createApp({});app.component('hello-world', HelloWorld);app.mount('#app');
vite.config.js
import { defineConfig } from 'vite';import vue from '@vitejs/plugin-vue';import laravel from 'laravel-vite-plugin';
export default defineConfig({ plugins: [ laravel({ input: ['resources/css/app.css', 'resources/js/app.js'], refresh: true, }), vue() ], resolve: { alias: { 'vue': 'vue/dist/vue.esm-bundler.js', } }});
#!/bin/bash
# プロセス終了時に一括で停止する設定trap 'kill 0' EXIT
cd ~/my-laravel-vue
# キャッシュなどをクリアphp artisan config:clearphp artisan cache:clearphp artisan view:clearphp artisan route:clearnpm run build
# NPMの開発サーバーをバックグラウンドで実行npm run dev &echo "Started npm run dev with PID $!"
# PHP Artisanのサーバーをバックグラウンドで実行php artisan serve &echo "Started php artisan serve with PID $!"
# 全プロセスが終了するまで待機wait
ベースになるファイルとして app.blade.php を設定します。
<!-- resources/views/layouts/app.blade.php --><!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Laravel + Vue + Tailwind</title> @vite(['resources/css/app.css', 'resources/js/app.js'])</head><body class="bg-gray-200"> <div id="app"> <!-- ここにVueのコンポーネントが表示される --> @yield('content') </div></body></html>
HelloWorld.vue の編集。
<!-- resources/js/components/HelloWorld.vue --><template> <div class="flex flex-col items-center justify-center min-h-screen bg-gray-100"> <h1 class="text-3xl font-bold text-blue-500">Hello, Laravel + Vue + Tailwind!</h1> <button @click="changeMessage" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600"> メッセージ変更 </button> <p class="mt-2 text-lg text-gray-700">{{ message }}</p> </div></template>
<script>export default { data() { return { message: '初期メッセージ' }; }, methods: { changeMessage() { this.message = 'ボタンがクリックされました!'; } }};</script>
vue はとても複雑です。
構成図
resources/├── js/│ ├── app.js (Vueのエントリーポイント)│ └── components/│ └── HelloWorld.vue (Vueコンポーネント)└── views/ └── layouts/ └── app.blade.php (ベースレイアウト) └── home.blade.php (実際のページ)
まずルーティング。
Route::get('/', function () { return view('home');});
http://127.0.0.1:8000/ でアクセスすると、home ビュー・つまり views/home.blade.php が呼ばれます。
@extends('layouts.app') <!-- layouts/app.blade.php を読み込む -->
@section('content') <hello-world></hello-world>@endsection
ここで layouts/app.blade.php を読み込んで、その content に
<hello-world></hello-world>
を埋め込みます。
chatGPT によると、
「この時点では、<hello-world>
はただのタグで、まだ何も動いていない!」
<!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Laravel + Vue + Tailwind</title> @vite(['resources/css/app.css', 'resources/js/app.js']) <!-- resources/js/app.js を読み込む --></head><body class="bg-gray-200"> <div id="app"> <!-- ここにVueのコンポーネントが表示される --> @yield('content') </div></body></html>
ここで resources/js/app.js を読み込みます。
import './bootstrap'; // Laravel の初期化コード
import { createApp } from 'vue';import HelloWorld from './components/HelloWorld.vue'; // HelloWorld コンポーネントをインポート
const app = createApp({});app.component('hello-world', HelloWorld);app.mount('#app');
ここまではなんとなくわかりますが、難解なのは この app.js です。
chatGPT の説明では、
createApp は、Vue 3 で新たに導入された Vue アプリケーションの作成方法です。これを使って、Vue のインスタンスを作成します。 引数としてオブジェクトを渡すこともできますが、基本的には空のオブジェクト {} を渡して、コンポーネントの登録やアプリケーションの設定は別途行います。
const app = createApp({});
この行は、hello-world という名前のコンポーネントを、Vue アプリケーションに登録しています。 これによって、Vue のコンポーネント HelloWorld.vue を hello-world というタグで使えるようになります。
app.component('hello-world', HelloWorld);
最後に、app.mount(‘#app’) は、Vue アプリケーションを特定の HTML 要素にマウント(取り付け)するためのメソッドです。
#app は HTML 側の <div id="app"></div>
に該当します。この #app の部分を Vue アプリケーションが管理することになります。
app.mount('#app');
この段階で Vue が #app を探し、hello-world コンポーネントを表示!
…
と、ここまでが chatPT の説明です。
作成された HelloWorld コンポーネントが
... <div id="app"> <!-- ここにVueのコンポーネントが表示される --> @yield('content') </div>...
この<div id="app">
にマウントされるということ。
…
なんと難しい。