はじめに
Laravelは、以前は標準でVue.jsが使用できるようになっていたのですが、Laravel6.0以降は自前でVue.jsをインストールし、resources/js/app.js
を編集する必要があります。
この記事では、SPAとしてではなく、Bladeを使ったマルチページアプリケーションとして作っているLaravelアプリケーションに対して、部分的にVueコンポーネントを導入する方法を解説します。
目次
- はじめに
- 目次
- 環境
- Vue.jsのインストール
- Vueコンポーネントを作成する
- app.jsの編集
- JavaScriptのコンパイル
- BladeへのVueコンポーネントの組み込み
- Laravelの変数をBlade経由でVueコンポーネントに渡す
- VueコンポーネントからLaravelへ非同期通信する
- 参考
環境
- Laravel 6.x
- Vue.js 2.6.11
Vue.jsのインストール
package.json
に、vue
とvue-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トークンや認証済みであることがLaravel側から求められるようなルーティングに対しても、通信できるはずです。