Laravelのフロントエンド開発にvue-cliを導入したい。
あると思います。
本記事では、Laravel6にvue-cliを利用して
yarn serve
でフロントエンドの開発環境の導入をしてみたいと思います。
なお、本記事で使用したソースはこちらに置いております。
https://github.com/kyhei/qiita-laravuel6
開発環境
- macOS Mojave 10.14.4
- Docker Desktop for Mac 2.1.0.2
- Engine 19.03.2
- Compose 1.24.1
- Laravel 6.0
- vue-cli 3.11
Dockerイメージの構成と構築
Docker Composeするイメージ郡概要
上記のような構成をDocker Composeで構築したいと思います。
MYSQL、phpMyAdmin,Mailhogは本記事の中では使用しませんのでお好みでお願いします。
要点としては
- Nginxコンテナで受けたHTTPリクエストをPHP-fpm上で処理する
- Laravelのインストールやvue-cliの実行はwork-spaceコンテナで行う
の2点です。
Laravel Serverについて
今回は以下のような構成でLaravelサーバを構築しました。
Nginxコンテナで受けたリクエストをUNIXソケット経由でPHP-fpmに伝えるという構成です。
これらの3つのコンテナ郡を便宜上Laravel Server
と呼ぶことにします。
Dev Serverについて
開発作業を行うwork-spaceコンテナ上でyarn serve
するためこちらのコンテナはそのままポートを外部に開放しております。
work-spaceコンテナの特徴は下記の点です。
-
composer create-project laravel/laravel
ができる。 -
php artisan migrate
等が実行できる。 -
yarn serve
等Node.jsの実行ができる。
VSCodeやシェルから中に入って作業を行うためのコンテナです。
ローカルのプロジェクトディレクトリは/work
以下にバインドしております。
Docker及びDocker Composeの定義ファイルは下記をご参照くださいませ。
https://github.com/kyhei/qiita-laravuel6
Laravelとvue-cliのインストール
ここからようやくコードを書いて参ります。
とりあえずDocker Composeをupしておきましょう。
$ git clone https://github.com/kyhei/qiita-laravuel6.git
$ cd qiita-laravuel6
$ docker-compose up -d
workspaceコンテナに以下のコマンドで接続します。
$ docker-compose exec workspace bash
Composerはインストール済みですので早速Laravelをインストールしましょう。
/work# composer create-project --prefer-dist laravel/laravel laravuel
/work# ls
docker docker-compose.yml laravuel
カレントディレクトリ下にLaravelプロジェクトのフォルダが作成されていたらOKです。
続いてNginxコンテナのドキュメントルートを作成したLaravelプロジェクトのpublicディレクトリに設定します。
server {
listen 80;
root /work/laravuel/public; # <- ここに設定
〜後略〜
設定を反映させるためにNginxコンテナを再起動しましょう。
/work# exit
$ docker-compose restart nginx
コンテナの再起動を確認後、ブラウザからLaravelのHello world画面が表示されていればOKです。
http://localhost:8000
vue-cliによるフロントエンド雛形作成
再びworkspaceコンテナにログインします。
$ docker-compose exec workspace bash
/work#
まずはvue-cliをグローバルにインストールしましょう。
/work# yarn global add @vue/cli
/work# which vue
/usr/local/bin/vue
つづいてフロントエンドの雛形を作成します。
/work# cd laravuel
/work/laravuel# vue create frontend
何をインストールするか色々聞かれますが
vue routerとhistoryモードを有効化にしたらあとはお好みで構いません。
(本記事ではTypeScript + vue-property-decoratorを使用しております。)
yarn serve
でvue-cliの初期画面を表示してみましょう。
まずはvue.config.js
ファイルを作成しdevServerがリッスンするポートを指定します。
module.exports = {
devServer: {
port: 9001
}
}
次にyarn serve
を実行します。
/work/laravuel# cd frontend
/work/laravuel/frontend# yarn serve
http://localhost:9001
で初期画面が表示されたらOKです。
本番用ビルドの設定
本項のvue.config.js
及びpackage.json
の設定内容は
Evan You氏の下記のリポジトリを参考にしております。
https://github.com/yyx990803/laravel-vue-cli-3
今回はフロントエンドをSPAで構築するため、Laravelはウェブページのリクエストが来たら
常に同じHTMLファイルを返す必要があります。
Laravelのルーティングを次のように書き換えましょう。
Route::get('/{any?}', function () {
return view('index');
})->where('any', '.+');
簡単のためコントローラは用意せずクロージャで対応しました。
これで任意のリクエストに対してindex.blade.php
を返すことができます。
つづいてvue-cliの本番ビルド時に
laravuel/resources/views/index.blade.php
を作成するよう設定します。
module.exports = {
devServer: {
port: 9001
},
outputDir: '../public',
assetsDir: 'assets',
indexPath: process.env.NODE_ENV === 'production'
? '../resources/views/index.blade.php'
: 'index.html'
}
なお、outputDir
オプションにてCSSやJSファイルが配置されるパスを設定しています。
assetsDir
オプションと組み合わせることで、ビルド結果のファイル郡は全て
public/assets
下に配置されます。
最後にpublic
ディレクトリ下のindex.phpなど必要なファイルをビルド時に削除してしまわぬよう、package.jsonの内容を書き換えます。
"scripts": {
"serve": "vue-cli-service serve",
- "build": "vue-cli-service build",
+ "build": "rm -rf ../public/assets && vue-cli-service build --no-clean",
"lint": "vue-cli-service lint"
},
--no-clean
オプションで既存のビルドファイル削除を無効しているため、
rmコマンドで既存ファイルを削除しています。
ここまでの設定を終えたらフロントエンドをビルドしましょう。
/work/laravuel/frontend# yarn build
publicディレクトリ下にassetsフォルダが作成され、
resources/views下にはindex.blade.phpが作成されたかと思います。
http://localhost:8000
でLaravel Serverにアクセスし、vue-cliの初期画面が表示されたらOKです。
Dev ServerからLaravel Serverへのプロキシ設定
vue-cliのDev serverとLaravel Serverはそれぞれ別々のコンテナ上で動作しているため、
Dev server上のvue-cliプロダクトからLaravelのAPIを叩くにはDev serverでプロキシする必要があります。
具体的には下記のような感じです。
vue.config.jsのdevServer項目にproxyの設定を追加しましょう。
devServer: {
port: 9001,
proxy: {
'^/api': {
target: 'http://nginx'
}
}
}
workspaceコンテナとnginxコンテナはDockerの同一ネットワーク上に存在するため、
nginx
というホスト名で名前解決が可能です。
環境構築及び設定については以上で完了です。
お疲れ様でした!
vue.config.jsの要点をまとめると、
開発環境に関わらず、
- 出力先のファイル、ディレクトリをLaravel用に変更する。
- フロント開発サーバとバックエンドのAPIサーバとのやり取りはproxyを設定する。
となります。
まとめとして、vue.config.js
ファイル全文を載せておきます。
module.exports = {
devServer: {
port: 9001,
proxy: {
'^/api': {
target: 'http://nginx'
}
}
},
outputDir: '../public',
assetsDir: 'assets',
indexPath: process.env.NODE_ENV === 'production'
? '../resources/views/index.blade.php'
: 'index.html'
}
Dev ServerとLaravel Server間の通信ハンズオン
サンプルのAPIを作成
/api/ping
とリクエストしたらJSONを返すシンプルなAPIを作成します。
Route::get('/ping', function () {
return response()->json([
'message' => 'pong'
], 200);
});
ブラウザで
http://localhost:8000/api/ping
とリクエストしたらJSON文字列が表示されるかと思います。
フロントエンドにHTTPクライアントの導入
今回はaxiosを導入してAPIを叩いてみます。
$ docker-compose exec workspace bash
work/# cd laravuel/frontend
work/laravuel/frontend# yarn add axios
インストールが完了したらaxiosインスタンスを作成する処理を記述します。
import axios from 'axios'
const axiosInstance = axios.create()
export default axiosInstance
HelloWorldコンポーネントの修正
HelloWorldコンポーネントを修正し、
Laravel Serverからのレスポンスをブラウザで表示してみます。
<template>
<div class="hello">
<h2>Request for Laravel Server</h2>
<h3>/api/ping</h3>
<h3>Response: {{apiText}}</h3>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import axiosInstance from '@/modules/axios'
import { AxiosResponse } from 'axios'
interface Ping {
message: string
}
@Component({})
export default class HelloWorld extends Vue {
apiText: string | null = null
async initialize() {
const res: AxiosResponse<Ping> = await axiosInstance.get('/api/ping')
if (res.status === 200) {
this.apiText = res.data.message
}
}
created() {
this.initialize()
}
}
</script>
<style scoped>
〜後略〜
TSを使っていない等の環境の違いについては適宜読み替えていただけたらと思います。
yarn serve
を実行しDev Serverにアクセスしてみましょう。
http://localhost:9001
成功です!!!
もちろんyarn serve
の実行下ではホットリロード等、開発サーバの恩恵を得られますので
いろいろいじってみるとリアルタイムで変更が反映されるかと思います。
最後にyarn build
でフロントエンドをビルドし、
http://localhost:8000
で同じ結果を得られるか確認してみてください。
終わりに
Dockerの構築からハンズオンまで盛りだくさんになってしまいました。
フレームワークに依らず、
outputDirとdevServer.proxyの設定さえ上手いことできたら
後はいつものvue-cliで開発を進められる!!
ということが感じられてたら嬉しいです。