この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:T
更新日時:2026-06-11 07:10:02

タイトル: vue.jsとの連携
SEOタイトル: Laravel + Vue.js 連携完全ガイド (Vite / Inertia / SPA)

この記事の要点
  • Laravel + Vue 連携パターン 4 つ: ① Blade 内で Vue マウント ② Inertia.js (SPA 風) ③ API + Vue SPA 分離 ④ Nuxt SSR + Laravel API
  • Laravel 9.x 以降は Laravel Mix → Vite が公式デフォルト
  • Blade から Vue へのデータ受け渡しは :user="{{ json_encode($user) }}" または data-* 属性
  • Inertia.jsBlade 不使用 + Vue/React コンポーネント + Laravel ルーティング のハイブリッド (Laravel Jetstream / Breeze で対応)
  • API 分離型は Sanctum (SPA 認証) + axios + Pinia が定番

連携パターンの選択

パターン特徴向いている用途
① Blade + Vue 部分導入Blade に <my-component> を埋め込み既存 Laravel への段階導入
② Inertia.jsVue でビュー、Laravel ルーティング維持SPA UX が欲しいが認証は Laravel
③ API + Vue SPA 分離Laravel = JSON API のみ、Vue = 別プロジェクトモバイル併用 / フロント独立
④ Nuxt + Laravel APINuxt で SSR、Laravel で APISEO 重要 / SSR 必要

パターン1: Blade + Vue 部分導入 (Vite)

Laravel 9.x 以降のデフォルト構成。vite.config.js + resources/js/app.js で Vue 3 をマウントします。

# Laravel 新規プロジェクト
composer create-project laravel/laravel my-app
cd my-app

# Vue 3 と Vite プラグインを追加
npm install vue@3 @vitejs/plugin-vue
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [
    laravel({
      input: ['resources/css/app.css', 'resources/js/app.js'],
      refresh: true,
    }),
    vue({
      template: {
        transformAssetUrls: {
          base: null,
          includeAbsolute: false,
        },
      },
    }),
  ],
});
// resources/js/app.js
import './bootstrap';
import { createApp } from 'vue';
import HelloWorld from './components/HelloWorld.vue';

const app = createApp({});
app.component('hello-world', HelloWorld);
app.mount('#app');
{{-- resources/views/welcome.blade.php --}}
<!DOCTYPE html>
<html>
<head>
  @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
  <div id="app">
    {{-- Laravel から Vue へ props 渡し --}}
    <hello-world :user="{{ json_encode($user) }}"
                 message="こんにちは"></hello-world>
  </div>
</body>
</html>
<!-- resources/js/components/HelloWorld.vue -->
<script setup>
const props = defineProps({
  user: Object,
  message: String,
});
</script>

<template>
  <div>
    <h1>{{ message }}, {{ user.name }} さん</h1>
    <p>email: {{ user.email }}</p>
  </div>
</template>
# 開発サーバ起動 (HMR 付き)
npm run dev

# 本番ビルド
npm run build
# → public/build/ に出力

パターン2: Inertia.js (SPA 風)

Blade を捨てて Vue でビューを書きながら、ルーティング / 認証 / バリデーションは Laravel に任せる。Jetstream / Breeze のオプションで導入できます。

# Breeze + Inertia + Vue
composer require laravel/breeze --dev
php artisan breeze:install vue
npm install
npm run dev
// routes/web.php
use Inertia\Inertia;
use App\Models\Post;

Route::get('/posts', function () {
    return Inertia::render('Posts/Index', [
        'posts' => Post::latest()->get(),
    ]);
});

// または Controller
public function index() {
    return Inertia::render('Posts/Index', [
        'posts' => Post::latest()->paginate(20),
        'filters' => request()->only(['search']),
    ]);
}
<!-- resources/js/Pages/Posts/Index.vue -->
<script setup>
import { Link } from '@inertiajs/vue3';

defineProps({
  posts: Array,
});
</script>

<template>
  <h1>記事一覧</h1>
  <ul>
    <li v-for="post in posts" :key="post.id">
      <Link :href="`/posts/${post.id}`">{{ post.title }}</Link>
    </li>
  </ul>
</template>

パターン3: API + Vue SPA 完全分離

Laravel をバックエンド API のみとして使い、Vue は別ディレクトリ / 別サーバで動かします。認証は Laravel Sanctum が定番。

# Laravel 側
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

# .env
SANCTUM_STATEFUL_DOMAINS=localhost:5173
SESSION_DOMAIN=.example.test

# Vue 側 (別プロジェクト)
npm create vue@latest my-spa
cd my-spa
npm install axios pinia vue-router
// routes/api.php
use App\Http\Controllers\Api\PostController;

Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('posts', PostController::class);
    Route::get('/user', fn() => auth()->user());
});
// src/api.js (Vue 側)
import axios from 'axios';

const api = axios.create({
  baseURL: 'http://api.example.test',
  withCredentials: true,   // ★ Sanctum クッキー認証
  headers: { 'Accept': 'application/json' },
});

// ログイン
export async function login(email, password) {
  // 1. CSRF クッキー取得
  await api.get('/sanctum/csrf-cookie');
  // 2. ログイン
  await api.post('/login', { email, password });
}

// 記事一覧取得
export async function fetchPosts() {
  const { data } = await api.get('/api/posts');
  return data;
}

パターン4: Nuxt 3 + Laravel API (SSR)

# Nuxt 3 プロジェクト作成
npx nuxi@latest init my-nuxt
cd my-nuxt
npm install
npm run dev   # http://localhost:3000

# .env
NUXT_PUBLIC_API_BASE=http://api.example.test
<!-- pages/posts/index.vue -->
<script setup>
const config = useRuntimeConfig();

// SSR でサーバ側 fetch
const { data: posts } = await useFetch(`${config.public.apiBase}/api/posts`);
</script>

<template>
  <ul>
    <li v-for="post in posts" :key="post.id">
      <NuxtLink :to="`/posts/${post.id}`">{{ post.title }}</NuxtLink>
    </li>
  </ul>
</template>

Laravel Mix から Vite への移行

古い Laravel (8.x 以前) は webpack.mix.js を使っていました。新規は Vite に移行してください:

# Mix を削除
npm uninstall laravel-mix
rm webpack.mix.js

# Vite を導入
npm install -D vite laravel-vite-plugin @vitejs/plugin-vue
# vite.config.js を作成 (前述参照)

# Blade テンプレートを書き換え
# 旧: <link href="{{ mix('css/app.css') }}" rel="stylesheet">
# 新: @vite(['resources/css/app.css', 'resources/js/app.js'])

# 起動
npm run dev

FAQ

Q: Inertia と API + Vue SPA、どちらを選ぶ?
A: Laravel チームで Vue を書きたい → Inertia。フロントとバックを別チームで分けたい → API 分離。

Q: Vue から CSRF トークンを送る
A: Laravel Sanctum なら /sanctum/csrf-cookie で自動。Blade 内 Vue は <meta name="csrf-token" content="{{ csrf_token() }}"> を axios のヘッダにセット。

Q: TypeScript 対応は?
A: Vite + Vue 3 で npm install -D typescript vue-tsctsconfig.json 配置。Inertia + TS も Breeze で選択可。