Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
202
Help us understand the problem. What is going on with this article?
@fruitriin

Laravel7からVue.jsを使う最短レシピ

More than 1 year has passed since last update.

LaravelからVue.jsを使う最短レシピ - Qiita という記事を公開していたのですが、情報が古くそのままの手順で再現できませんでした。

そのため、Laravel7用にブラッシュアップした記事を書きたいと思います。

間違ったことが書いてあるとか、Laravelが新しくなってこの記事の通りにできなくなった等あれば
この記事にコメントをいただけると嬉しいです。

Laravel から最短でVue.jsを使う

インストールから動かして本番投入まで一通りっていうのが見つからなかったのでまとめてみます。
知らないとわかんないよそんなの!みたいな罠がそこかしこにありました。

TL;DR

  • Vue(やReact)が別のパッケージになったので自分でインストールする
  • bladeテンプレートの修正とコマンドをいくつか実行すれば使える
  • bladeのいじるとこ

今回の環境

macOS Catalina
PHP 7.3.11 (composerがインストールされている)
Node.js (というよりnpm) v10.15.1(10系のLTSか12系のLTSなら良いはず)
Laravel 7.4

インストール

Installation - Laravel - The PHP Framework For Web Artisans
とかに従ってLaravelをインストールします。

# Laravel installerをグローバルインストールしてLaravelインストーラーからインストール
composer global require laravel/installer
laravel new blog

# Laravelのプロジェクトだけ作成
composer create-project --prefer-dist laravel/laravel blog

それから作成したプロジェクトに移動して laravel/ui を追加します。

cd blog
composer require laravel/ui

最後に、UIとしてVueを利用すると指定し、npm install

# php artisan ui vue --auth で認証系の画面を一緒に作ってくれるっぽい?
php artisan ui vue 
npm install

インストールはこれでおしまい。
ちなみにvue以外にもreactも選択できます。

bladeの修正

ポイントは3つ。

<!-- Headタグ内に足す -->
<meta name="csrf-token" content="{{ csrf_token() }}">

Laravelがセキュリティを高めるために「ajax通信をするときはcsrfトークンをいつも使いましょうね」
っていうデフォルト設定がbootstrap.jsに書いてあるんだけどblade側にtokenが埋め込まれてないので埋め込みます。なんでだろう?

<!-- Headタグ内に足す -->
<link rel="stylesheet" href="{{ mix('/css/app.css') }}">

{{mix('パス')}} が、Laravelのアセットのパスをいい感じに解決してくれます。

<div id="app">
    <!-- デフォルトだとこの中ではvue.jsが有効 -->
    <!-- example-component はLaravelに入っているサンプルのコンポーネント -->
    <example-component></example-component>
</div>
<!-- body タグの最後に足す-->
<script src=" {{ mix('js/app.js') }} "></script>

vue.jsのコンポーネントetcをロードするapp.jsは最後に読み込みましょう。
具体的には、すべてのコンポーネント用のタグ(今回だと #app)のあとに読み込まないと、
vue.jsのルートインスタンスが目的のDOMを捕まえられなくて死んでしまいます。

起動

Vue.js開発は、Laravelのartisan serveと別にコンポーネントのコンパイルが必要です。
ローカル環境で開発するなら下記のコマンドで開発すると幸せになれます。

npm run hot #vue cliでいうところの npm run dev相当。HMR!

npm run hot するとHot Module Replacement(HMR)有効な状態でビルドされます。。
つまりどういうことだってばよって、編集するとリアルタイムで結果が反映されてめっちゃ開発めっちゃ捗ります!

HotModuleReloading.gif

めちゃくちゃ開発が捗るようになるので是非。

また、開発/ステージングサーバーや本番にデプロイする時は以下のコマンドでビルドしましょう。

#開発デプロイ時
npm run dev # npm run develop のショートハンド
#本番デプロイ時
npm run prod # npm run production のショートハンド

やったねLaravelでVueが使えるようになったよ!

php artisan serve # Laravelの開発サーバーをlocalhostで立ち上げ

localhost:8000 にアクセスしてExample Componentが表示されていることを確認しましょう。

Laravel と Vue の変数展開がバッティングしている問題の解決方法

そもそも論、Betterな解決方法としてはBladeの中にVueのシンタックスを書くべきではないと思います。
ですが、Bladeだけ見た時の見通しの良さやチームメンバーのレベル感の問題で、
.vueファイルにコンポーネントに切り出さずにBladeファイル内に閉じてしまいたいと考えるかもしれません。

Laravel 7.4ではBladeの変数展開シンタックス{{ }}は変更できないようです。
代わりに @{{ }}とすることで、{{ }}を展開せずそのままレンダリングすることができます。

それでもやっぱり紛らわしい!という場合は、幸いVueの変数展開シンタックスを変更可能することが可能です。

resources/js/app.js を開いてください。

app.js
const app = new Vue({
    el: '#app',
    delimiters: ["<%","%>"], // この行を追加
});

 
これで、Vue側のテンプレートでの変数展開シンタックスを変更することが可能です。

Laravelから変数を受け取る方法

最も原始的な方法は、サーバー側で変数をBladeに送り込み、
受け取ったBladeではJSONでパースしてWindowオブジェクトに突っ込む方法です。

routes/web.php
Route::get('/', function () {
    $data = [
        "data" => ["name" => "Taro"] // dataがネストしてるのは間違いじゃない
    ];
    return view('welcome', $data);
});
resources/views/welcome.blade.php
<!-- 前略 -->
        <script>
            window.data = @json($data)
        </script>
    </head>
    <body>
<!-- 後略 -->

この方法は原始的ですが、もっともbladeらしいやり方ともいえます。
window.dataはグローバルに参照でき、破壊可能で、Vueによってリアクティブに監視されません。

Vueのコンポーネント内で利用するには、Vueコンポーネントのdata内で明示してあげたり、
メソッドの中で呼び出してあげる必要があるでしょう。
ちなみにこのサンプルでは上述のデリミタの変更は行っていません。

resources/js/components/ExampleComponent.vue
<template>
  <div class="container">
    <div class="row justify-content-center">
      <div class="col-md-8">
        <div class="card">
          <div class="card-header">Example Component</div>

          <!-- この行でコンポーネントの name を表示してる -->
          <div class="card-body">{{ name }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  mounted() {
    console.log("Component mounted.");
  },
  data() {
    return {
      name: window.data.name // この行を追加
    };
  }
};
</script>

こんな感じでできました。
グローバルスコープを汚すので、ちょっとお行儀が悪い気がしますね。

API から axios をつかってデータを取ってくる

まず適当にAPIをは生やしてみましょう

routes/api.php
Route::get("/sample", function(){
    $data = ["name" => "Jiro"];
    return $data;
});

これで、 http://localhost:8000/api/sample へアクセスすると、
{"name":"Jiro"} と表示されるのがわかると思います。

実態がDBへのアクセスを伴うものでも基本は変わりません。
それではVueからこのAPIを扱う方法を見ていきたいと思います。

API通信のためのAxiosはLaravelのデフォルトパッケージとしてインストールされています。
あとはコンポーネント内でそれをただ利用するだけです。

resources/js/components/ExampleComponent.vue
<script>
export default {
  async mounted() {
    console.log("Component mounted.");
    const ret = await window.axios.get("/api/sample")
    console.log(ret.data)
    this.name = ret.data.name;
  },
  data() {
    return {
      name: window.data.name
    };
  }
};
</script>

これで、リロードしたときに最初はTaroが表示されていて、
APIの通信の結果をうけてJiroが表示されることがわかるでしょう!

以上が、LaravelでのAPI通信の基本となります。

こんな記事書いてます

202
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
studist
「伝えることを、もっと簡単に」をミッションにビジュアルSOPマネジメントプラットフォームのBtoB SaaS「Teachme Biz」を開発・運営するスタートアップ

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
202
Help us understand the problem. What is going on with this article?