LaravelのBladeにVueコンポーネントを組み込む

vue.jsロゴ

はじめに

Laravelは、以前は標準でVue.jsが使用できるようになっていたのですが、Laravel6.0以降は自前でVue.jsをインストールし、resources/js/app.jsを編集する必要があります。

この記事では、SPAとしてではなく、Bladeを使ったマルチページアプリケーションとして作っているLaravelアプリケーションに対して、部分的にVueコンポーネントを導入する方法を解説します。

目次

環境

  • Laravel 6.x
  • Vue.js 2.6.11

Vue.jsのインストール

package.jsonに、vuevue-template-compilerを追加し、npm installを実行します。

{
  // 略
  "devDependencies": {
    "axios": "^0.19",
    "cross-env": "^5.1",
    "laravel-mix": "^4.0.7",
    "lodash": "^4.17.13",
    "resolve-url-loader": "^2.3.1",
    "sass": "^1.15.2",
    "sass-loader": "^7.1.0",
    "vue": "^2.6.11",
    "vue-template-compiler": "^2.6.11"
  }
}
$ npm install

Vueコンポーネントを作成する

resources/jsディレクトリ配下にVueコンポーネントを作成します。

今回はcomponentsディレクトリを作成した上で、そこにVueコンポーネントを作成することにします。

<template>
  <!-- 略 -->   
</template>

<script>
  // 略
</script>

app.jsの編集

Laravelで共通的に使用されるJavaScriptであるapp.jsを編集し、Vue.jsと、先ほど作ったVueコンポーネントを使用するよう定義します。

import './bootstrap'
import Vue from 'vue'
import FooBar from './components/FooBar'

const app = new Vue({
  el: '#app',
  components: {
    FooBar,
  }
})

JavaScriptのコンパイル

JavaScriptをコンパイルするため、npm run watch-pollを実行します。

これにより、JavaScriptがLaravel Mixにより自動コンパイルされるようになります(JavaScriptの状態を定期的に監視し、保存されると自動でコンパイルします)。

$ npm run watch-poll

なお、Laravel Mixの設定はwebpack.mix.jsに記述されています。

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js')
  .sass('resources/sass/app.scss', 'public/css')
  .version();

mix.js('resources/js/app.js', 'public/js')と記述されていますが、これにより

  • resources/js/app.js

がコンパイルされて、コンパイル後のファイルが

  • public/jsディレクトリ

に、同じapp.jsというファイル名で保存されます。

ブラウザに読み込まれて使用されるのは、このpublic/js/app.jsの方です。

BladeへのVueコンポーネントの組み込み

LaravelのBladeの設計としては、まずベースとなるBladeを作り、そこへheadタグやscriptタグを記述し、これを継承した各Bladeをビューとして使用することが多いと思います。

ここでは、ベースとなるapp.blade.phpが存在する前提で、これを継承する全BladeでVueコンポーネントを組み込み可能にしています。

<!DOCTYPE html>
<html lang="ja">
<head>
  {{--略--}}
</head>

<body>
  <div id="app"> 
    @yield('content')
  </div>

  <script src="{{ mix('js/app.js') }}"></script>   
  {{--略--}}
</body>
</html>

なお、<script src="{{ mix('js/app.js') }}"></script>としている箇所は、HTMLにレンダリングされると、以下になります。

<script src="/js/app.js?id=dadc3a844ded5d18d741"></script>

コンパイルのたびに付与されるランダムなidが付くことで、ブラウザのキャッシュ対策となっています。

また、idはpublic/mix-manifest.jsonで管理されています。

{
    "/js/app.js": "/js/app.js?id=dadc3a844ded5d18d741",
    "/css/app.css": "/css/app.css?id=d41d8cd98f00b204e980"
}

本題から話が少し逸れましたが、後は、各Bladeに必要に応じてVueコンポーネントを組み込みます。

@extends('layouts.app')

@section('content')
  <section>
    <h2>以下はVueコンポーネントです</h2>
    <foo-bar></foo-bar>
  </section>
@endsection

Laravelの変数をBlade経由でVueコンポーネントに渡す

Laravelの変数をBlade経由でVueコンポーネントに渡す時は、Bladeの@jsonディレクティブが便利です。

@extends('layouts.app')

@section('content')
  <section>
    <h2>以下はVueコンポーネントです</h2>
    <foo-bar
      :prop-sample-price='@json($sample->price)' 
    ></foo-bar>
  </section>
@endsection
<template>
  <!-- 略 -->
</template>

<script>
  export default {
    props: {
      propSamplePrice: {
        type: Number,
      },
    },
</script>

VueコンポーネントからLaravelへ非同期通信する

以下は、Bladeに組み込んだVueコンポーネントからLaravelに対して非同期通信を行う一例です。

Blade側では非同期通信先のURLをLaravelのroute関数で取得し、Vueコンポーネントへプロパティendpointとして渡すようにしました。

@extends('layouts.app')

@section('content')
  <section>
    <h2>以下はVueコンポーネントです</h2>
    <foo-bar
      :prop-sample-price='@json($sample->price)'
      endpoint="{{ route('sample.update', ['sample' => $sample]}}" 
    ></foo-bar>
  </section>
@endsection

そして、Vueコンポーネントではaxiosを使い、Bladeから渡されたendpointに対して非同期通信を行なっています。

<template>
  <!-- 略 --> 
</template>

<script>
  export default {
    props: {
      propSamplePrice: {
        type: Number,
      },
      endpoint: {
        type: String,
      },
    },
    methods: {
      async sampleUpdate() {
        const response = await axios.put(this.endpoint)
        // 略
      },
    },  
</script>

Laravelでは標準でaxiosが使用できるようになっています。

app.jsでは、bootstrap.jsをimport(本記事でimportに書き換えましたが、Laravelインストール直後ではrequire)していますが・・・

import './bootstrap'

このbootstrap.jsでは、以下の通り、axiosをrequireしています。

window.axios = require('axios');

なお、axiosによる非同期通信のリクエストヘッダのX-XSRF-TOKENには、Laravelのクッキーから取得したCSRFトークンの値が自動でセットされます。

CSRFトークン

ですので、CSRFトークンや認証済みであることがLaravel側から求められるようなルーティングに対しても、通信できるはずです。

参考