◀ 52.

【Laravel】Vue.jsと連携するSPA実行環境構築

▶
この記事の要点
  • Laravel + Vue.js で SPA 実行環境を構築する手順
  • 画面URLにはLaravelが共通HTMLを返し、画面内の遷移はVue Routerが担当。APIは別ルート
  • クライアントルーティング: vue-router 側で行う
  • API: routes/api.php 経由で /api/* を使う

 

前提と対象バージョン

この記事はVue 2・Vue Router 3・Laravel Mixを使用する旧LaravelプロジェクトのSPA構成を説明します。resources/assets/jsや文字列によるコントローラー指定は旧構成の例です。Laravel 13・Vue 3・Viteの新規構成へ、そのままコピーする手順ではありません。

Vue 2は2023年12月31日に公式サポートが終了しています。新規開発では現行の構成を選び、既存環境を保守する場合もcomposer.lockとpackage-lock.json等で実際の依存バージョンを確認してください。

Laravelが画面用HTMLを返し、Vue Routerが画面を選択。axiosは別途APIから記事データをJSONで取得する流れ

・Laravelプロジェクトを作成済み (まだの場合はこちらのページを参照)

・Vue.jsとの連携とvue-routerのインストール (まだの場合はこちらのページを参照)

・SPAの実行環境を構築するだけです。SPAの様々な記述方法は他のページを参照してください。

 

画面URLへ共通HTMLを返すLaravelルート

Laravelのルーティングを無効にするのではありません。historyモードの画面URLへ直接アクセスしたとき、LaravelがSPAの共通HTMLを返します。HTMLを読み込んだ後は、Vue RouterがURLに対応するコンポーネントを選びます。

※APIのルーティング(routes/api.php)は使用する(後述)

画面用のGETリクエストには共通ビューresources/views/app.blade.phpを返します。view('app')はこのファイルを指します。APIや認証などのサーバールートは残し、共通HTMLを返すルートは具体的な画面ルートの後に置いてください。

routes/web.php(APIのURLを除外する画面用フォールバック)

Route::get('/{any?}', function () {
    return view('app');
})->where('any', '(?!api(?:/|$)).*');

 

共通レイアウトの作成

Vue.jsを使うための最低限の設定と必要なheadタグ内の要素を記述すればよい。

resources/views/app.blade.php

<!DOCTYPE html>

<html lang="{{ app()->getLocale() }}">

    <head>

        <meta charset="utf-8">

        <!-- CSRF Token -->
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <!-- CSS -->
        <link href="{{ asset('css/app.css') }}" rel="stylesheet">

    </head>

    <body>

        <div id="app">

            <router-view></router-view>

        </div>

        <!-- Scripts -->
        <script src="{{ mix('js/app.js') }}"></script>

    </body>

</html>

 

 

サーバーサイド(Laravel)のAPIを作成

テスト用にDBから適当なデータを取得するAPIを作成する。

 

まずは適当なAPIルーティングを作成する。

routes/api.php

Route::get('articles', 'Article\ArticleController@getArticles');

 

適当なコントローラーを作成する。

app/Http/Controllers/Article/ArticleController.php

<?php

namespace App\Http\Controllers\Article;

use App\Http\Controllers\Controller;
use App\Models\Article;
use Illuminate\Http\Request;

class ArticleController extends Controller
{
    public function getArticles(Request $request)
    {
        $articles = Article::select(['article_id', 'title'])
            ->orderBy('update_datetime', 'DESC')
            ->orderBy('article_id', 'DESC')
            ->limit(3)
            ->get();

        return response()->json($articles);
    }
}

 

適当なモデルを作成する。(マイグレーションするなり直にcreate tableしてテーブル作成をしておく)

この例ではarticleテーブルにarticle_id(整数・自動採番の主キー)、title、update_datetimeが必要です。APIは画面で使うarticle_idとtitleだけを返します。update_datetimeの降順で3件取得し、同日時ならarticle_idの降順で順序を固定します。

モデルのincrementingはカラム名ではなく真偽値です。下のtrueは自動採番を使う場合の例です。Eloquentの保存も行うなら、created_at/updated_atを用意するか、独自のタイムスタンプ設定を実際のテーブルに合わせてください。

app/Models/Article.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    protected $table = 'article';

    protected $primaryKey = 'article_id';

    public $incrementing = true;

    protected $guarded = [
        'created_at',
        'updated_at',
    ];
}

 

 

ローカルサーバーの起動

以下の2つのコマンドをそれぞれ別窓で実行してローカルサーバーを起動する。

php artisan serve

 

npm run hot

 

Vue.jsでルーティングを作成

resources/assets/js/app.js(旧構成)

import Vue from 'vue'
import VueRouter from 'vue-router'
import Articles from './components/Articles.vue'

require('./bootstrap')
Vue.use(VueRouter)

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '/articles', component: Articles }
  ]
})

new Vue({ el: '#app', router })

 

ビューの作成とAPIの呼び出し

resources/assets/js/components/Articles.vue(旧構成)

初期表示でAPIを呼び、取得したtitleを一覧に表示します。axiosを明示的にimportし、読み込み中と通信失敗も表示する例です。HTMLの整形用p/spanはJavaScriptへ混ぜないでください。

<template>
  <div>
    <p v-if="loading">読み込み中です。</p>
    <p v-else-if="error">{{ error }}</p>
    <ul v-else>
      <li v-for="article in articles" :key="article.article_id">
        {{ article.title }}
      </li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  data() {
    return { articles: [], loading: true, error: '' }
  },
  created() {
    this.getArticles()
  },
  methods: {
    getArticles() {
      this.loading = true
      this.error = ''
      return axios.get('/api/articles')
        .then(res => {
          this.articles = res.data
          this.loading = false
        })
        .catch(() => {
          this.error = '記事を取得できませんでした。通信結果を確認してください。'
          this.loading = false
        })
    }
  }
}
</script>

 

以上の設定で「http://localhost:8000/articles」にアクセスするとarticleテーブルのtitle一覧が表示される。

 

表示されないときはHTMLとAPIを分けて確認する

確認先期待する結果異なる場合の確認
/articles共通HTMLの読み込み後、Vueが記事一覧を描画view('app')の保存先、Mixのビルド結果、ブラウザのConsole
/api/articlesarticle_idとtitleのJSON配列api.phpの定義、Controllerの名前空間、DBのカラムと接続
/articlesの再読み込みLaravelが再度共通HTMLを返し、同じ画面を表示historyモード用フォールバックとWebサーバーの設定
/api/not-found未定義APIとして404画面用フォールバックがAPIのURLまで捕まえていないか

Networkで/api/articlesのレスポンスを見ます。200でもHTMLが返っているなら、Vueの一覧処理ではなくルートの振り分けが問題です。空配列なら通信成功であり、DBに対象データがあるかを確認します。500ならLaravelのログとスキーマを照合し、例外を隠して画面だけ直そうとしないでください。

旧構成のまま動かすときの注意

  • npm run hotは、package.jsonにhotスクリプトがあるMix構成の開発用コマンドです。現行Viteのnpm run devとは混ぜません。JSファイルの配置もwebpack.mix.jsの入力先に合わせます。
  • 記事の文字列形式Controllerルートは旧Laravelの名前空間設定が前提です。現行版で使う場合はControllerをimportしたクラス配列形式とAPIルートの登録を別途確認します。
  • 未定義の画面URLも共通HTMLが200で返る構成です。Vue側のNotFound表示とサーバーのHTTP 404は別物なので、本番での404設計も必要です。
  • このAPI例は公開してよいテストデータ専用です。非公開データ・ユーザー別データには認証と権限検査を追加し、必要なカラムだけ返してください。
  • DB一覧・API・コンポーネントの順に確認します。まずAPIのJSONを確認してからVueの描画を調べると、問題の場所を絞れます。

確認した公式資料: Vue Router 3のhistoryモード、Vue 2のサポート終了、Laravel 5.5のルーティング、Eloquentのモデル設定(2026年10月確認)。

Post Share
子ページ

子ページはありません

同階層のページ
  1. インストールと設定
  2. クイックスタート & チュートリアル(初心者向け)
  3. クイックスタート & チュートリアル(中級者向け)
  4. ルーティング
  5. Bladeテンプレート(ビュー/レイアウト)
  6. コントローラー
  7. マイグレーションとテーブル定義
  8. データベースの設定
  9. Eloquentモデル (ORM)
  10. SQLとクエリビルダー
  11. バリデーション
  12. .envファイルの設定値へのアクセス
  13. 動作環境による分岐処理
  14. configフォルダ配下の設定値へのアクセス
  15. assetヘルパーを利用したpublicフォルダへのアクセス
  16. storageフォルダへのアクセス
  17. アプリケーション名の変更
  18. メンテナンス
  19. ログイン画面(認証システム)の作成
  20. ログインの必須化
  21. ログインユーザー情報の取得
  22. ルートの認証化
  23. 本番サーバーへのデプロイ方法
  24. 多言語化
  25. csrf_field
  26. ファイルのダウンロード
  27. CSVのアップロードおよび読み込み(maatwebsite/excel)
  28. ページタイトルの設定
  29. コマンド一覧
  30. エラー一覧
  31. SQLの実行ログ出力方法
  32. キャッシュのクリア
  33. Selectの結果の最初もしくは最後に任意の値を追加する方法
  34. ajaxでPOST通信する際の注意点
  35. ソーシャルログインの実装
  36. セッション情報の確認
  37. ログイン、ユーザー登録、パスワードリセット後のリダイレクト先の変更方法
  38. redirectやreturn viewにメッセージを付与する方法
  39. クッキー(cookie)の設定と取得
  40. クラスの再読み込み
  41. csrfの有効時間を変更する方法
  42. ViewComposerを用いてviewに共通の値を付与する方法
  43. View::shareを用いて共通の値を各ビューに渡す方法
  44. ミドルウェアを用いた処理の共通化
  45. Middleware内でAuth::check()などを使用する方法
  46. Controller以外でリダイレクトする方法
  47. セッションの値の取得/保存/更新/削除
  48. $requestの値を変更する方法
  49. 常時SSL化
  50. ページング(ページネーション)をする方法
  51. vue.jsとの連携
  52. Vue.jsと連携するSPA実行環境構築
  53. .envの値をvue.jsで参照する方法
  54. vue.jsを本番環境にリリースする方法
  55. could not find driver(Windows, MySQL編)