今更だけどLaravel+Vue.jsを試す

Webサイトをよりアプリっぽくするために
Vue.jsを試してみます。

# 開発環境

| 使用ツール名       | バージョン |
|:-----------------|:------------------|
| Laravel             | 5.7.14 |
| Vue.js             | 2.5.17 |
| Homestead             | 6.6.0 |

# やること

- CDN版で試す
- NPMで試す
- 単一ファイルコンポーネント

# とりあえず10分くらいで試したい場合

Vue.js公式が優しいので参考にしながら。
CDNから引っ張ってきてやるのが簡単です。

https://jp.vuejs.org/v2/guide/index.html

## HelloWorld

https://jsfiddle.net/chrisvfritz/50wL7mdz/

```php:hello.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <p>@{{ message }}</p>
    </div>
    <script>
    new Vue({
        el: '#app',
        data: {
        message: 'Hello Vue.js!'
        }
    });
    </script>
</body>
</html>
```

blade使っている場合、二重中括弧の前に＠付けないと正常に表示されません。

## ルーティング

公式のサンプルを先程のHelloWorldに合体させます

```php:hello.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
    <div id="app">
        <p>@{{ message }}</p>
        <router-link to="/foo">Go to Foo</router-link>
        <router-link to="/bar">Go to Bar</router-link>

        <router-view></router-view>
    </div>
    <script>
    const Foo = { template: '<div>foo</div>' };
    const Bar = { template: '<div>bar</div>' };

    const routes = [
        { path: '/foo', component: Foo },
        { path: '/bar', component: Bar }
    ];

    const router = new VueRouter({
        routes // `routes: routes` の短縮表記
    });


    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue.js!'
        },
        router: router
    });
    </script>
</body>
</html>
```

ただこれだとFooやBarのテンプレートの中に全てのHTMLを書かねばなりません。
ページ内の1コンポーネントならいいですがページ全体となると気が遠くなりますね。
そこで単一ファイルコンポーネントに行き着くのですが、この辺りからCDN版ではできなくなります。はやー

# もう少し突っ込んで試したい場合

## NPMインストール

Laravelだとこの辺り最初から揃っているのが嬉しいです（注：揃っているがインストールはされていない）
Laravelのインストールディレクトリ直下にpackage.jsonがあるのですが、何もいじらず以下のコマンドを入力します

```console:console
$ vagrant ssh
$ npm install
```

後々、と言ってもすぐに必要になるのでvue-routerもインストールしてしまいます。

```console:console
$ npm install vue-router
```

この後コンパイルすると、必要なファイル一式がどこどこ出来上がってきます。
Laravelの場合Laravel Mixというコンポーネントを使ってVue.jsと連携してくれます。

```console:console
$ npm run dev
```

これで準備完了です。

## NPM版に合わせてソース修正

既に単一ファイルコンポーネントが入ってしまってますが、こんな感じで。

```php:hello.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
    <div id="app">
        <p>@{{ message }}</p>
        <router-link to="/foo">Go to Foo</router-link>
        <router-link to="/bar">Go to Bar</router-link>

        <router-view></router-view>
    </div>
    <script src="{{ mix('js/app.js') }}" ></script>
</body>
</html>
```

vueのソースを書いていた部分がjs/app.jsに移動しています。

```javascript:js/app.js
import VueRouter from 'vue-router';

import page1 from './components/page1.vue';
import page2 from './components/page2.vue';

require('./bootstrap');

window.Vue = require('vue');

const routes = [
    { path: '/page1', component: page1 },
    { path: '/page2', component: page2 }
];

const router = new VueRouter({
    routes // `routes: routes` の短縮表記
});

const app = new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue.js!'
    },
    router: router
});
```

```html:js/components/page1.vue
<template>
    <div>foo</div>
</template>

<script>
</script>

<style>
</style>
```

page2.vueは同じソースなので省略します。

ここまで出来たらビルドして動作を確認します。

```console:console
$ npm run dev
```

# エラー類

## - Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

npm run devあたりで表示されるエラー
templateタグの中はdivで括らないと上記エラーが出ます。

## 画面遷移でずれる
absoluteで位置決めしておかないと画面遷移でパーツがいろいろずれます

# その他メモ

## 全ページ共通のcssを読み込む

```javascript:js/app.js
require('../../public/css/laravel-vue.css');
```

こんな感じで。
ブラウザ側から見えるパスではなく、サーバー内のパスで書いています。

## bladeの範囲

.vueの単一ファイルコンポーネントの中はbladeの範囲外となります。

つづく

# 参考

https://jp.vuejs.org/
https://router.vuejs.org/ja/
https://blog.capilano-fw.com/?p=432
http://blog.asial.co.jp/1496
https://techblog.securesky-tech.com/entry/2018/09/03/