この数年、たいへんなスピードでフロントエンド開発技術が発展しておりますね。
私はバックエンド開発が続いていたことを言い訳に、直近の小規模な Web ツール開発をjQueryで頑張ってしまったため、次は同じ轍を踏まない ために Vue.js を勉強してみました。

jQuery で頑張ってはいけない理由

jQuery(ジェイクエリー)は、ウェブブラウザ用のJavaScriptコードをより容易に記述できるようにするために設計された軽量なJavaScriptライブラリ

https://ja.wikipedia.org/wiki/JQuery

jQueryはフロントエンドの開発に大きく貢献してきた素晴らしいライブラリで、「Web サイトにちょっとしたギミックを足す」用途には使いやすいツールです。

しかしながら、jQuery での開発で、少しでも規模が大きくなってくると途端に苦しくなってきます。

それは「DOM の操作」や「データの連携」などはすべて自前で実装する必要があるためで、作り込めば作り込むほど、「 変更が聞かないガチガチのプログラム 」になってしまいます。


私が jQuery を初めて利用したのは 2011年 に開発したブラウザゲームでした。
その頃はまだこれほどまでにフロントエンドの開発技術が発展する前で、JavaScriptのフレームワークも限られたものしかありませんでした。

最初はギミックが小さかったため良かったのですが、プロジェクトが世に出てフロントエンドの要件が増えれば増えるほど、JavaScript ソースが混沌とし、ダークサイドへと堕ちていくよが自分でもよくわかりました。

JavaScriptパターン ―優れたアプリケーションのための作法

Stoyan Stefanov
出版社:オライリージャパン  発売日:2011-02-16

Amazonで詳細を見る

オライリーの JavaScript 本をこ購入してコードの改善を図りました、自分の力不足ですぐに限界がきました。
悔しかったですね。

このプロジェクトは、その後半年ほどで私の手を離れました。

次にこのプロジェクトを引き継いだエンジニアさんに、「黒いコードを引き渡してごめんなさい」と激しくお詫びしたかったです。


そして 2014年。
札幌の有名企業インフィニットループさんが外部解放されている勉強会に参加し、その中で次のお話を伺い「 JavaScript にもこんな素晴らしいライブラリがでてきたんだな 」と時の経過を感じたものです。

株式会社インフィニットループ技術ブログ
5分でわかるVue.jsと、jQueryで頑張ってはいけない理由
https://www.infiniteloop.co.jp/blog/2014/06/5min_vuejs/

さて、前置きが長くなりました。

ゴール

Vue.js を使ってバックエンドと通信する簡単な Web アプリを実装する。

  • Laravel 5.4 を導入し Laravel Mix を利用する
  • データ管理はバックエンド
  • フロントエンドは Vue.js

Laravel Mixとは

Laravel Mix とは「Laravel で CSS や JavaScript をビルドするための API を提供するもの」です。

Laravel Mix
https://laravel.com/docs/5.4/mix

Laravel 5.3 まではGulpを利用しLaravel Elixirという名称でした。

Laravel 5.4 からWebpackの利用に変更され、「異なるライブラリがベースである」ことがわかるよう、名称も変えたという理解です。

Vue.js とは

Vue.js とは データバインディングに特化 したシンプルで軽量な JavaScript フレームワークです。

Vue.js
https://jp.vuejs.org/

ドキュメントが豊富であり、かつ学習コストも高くありません。

そして、最初から Laravel Mix に組み込まれています。

環境

  • Laravel 5.4
  • PHP 7.0
  • node.js 7.7.1
  • npm 4.4.2

PHP は次で環境構築済みです。

PHPBrew でかんたんに PHP 環境を管理する
atuweb 開発ブログ

node.js は今回新しく環境を整えます。

実装編

Laravelプロジェクトを作成し、Mixを準備

プロジェクトの作成

Laravel 5.4 の新規プロジェクトを追加します。

1$ composer create-project laravel/laravel MyProject 5.4
2$ cd MyProject
3$ composer install

node.jsの導入

Laravel Mix を利用するためにはNode.jsの環境構築が必須です。

homebrew でのインストールではなく、便利そうなnodebrewを導入しました。

インストール
1$ brew install nodebrew
nodebrewのパスを通す
1$ vi ~/.bash_profile
2export PATH=$HOME/.nodebrew/current/bin:$PATH
1$ source ~/.bash_profile
利用可能バージョン確認
1$ nodebrew ls-remote
インストールと利用バージョン指定
1$ nodebrew install-binary latest
2$ nodebrew use latest
インストール確認
1$ node -v
2v7.7.1
3$ npm -v
43.10.10
npmをアップグレードする
1$ npm install -g npm
2$ npm -v
34.4.2

Laravel Mixの準備

Laavel Mix の依存ライブラリはプロジェクトルートのpackage.jsonに定義されています。

私はnpm runでエラーが発生したため、package.json を次のように編集しました。
詳しくは後述しております。

 1{
 2  "private": true,
 3  "scripts": {
 4    "dev": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
 5    "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
 6    "watch-poll": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --watch-poll --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
 7    "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
 8    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
 9  },
10  "devDependencies": {
11    "axios": "^0.15.3",
12    "bootstrap-sass": "^3.3.7",
13    "cross-env": "^3.2.3",
14    "jquery": "^3.1.1",
15    "laravel-mix": "^0.8.1",
16    "lodash": "^4.17.4",
17    "vue": "^2.1.10"
18  }
19}

npm コマンドを実行し Laravel Mix をインストールします。

1$ cd MyProject
2$ npm install

その後、プロジェクトルートでrunすると、JSやCSSファイルがビルドされます。

1$ npm run dev
Laravel Mix ビルド成功の通知
Laravel Mix ビルド成功の通知

ビルドが成功すると上のポップアップが表示されます。 嬉しくなる瞬間ですね。

ゴリゴリコードを書く段階では、ファイルの変更を監視し、速やかに処理してくれるrun watchがおすすめです。


「何をどこに配置するか」はwebpack.mix.jsに定義されています。

1const { mix } = require('laravel-mix');
2
3mix.js('resources/assets/js/app.js', 'public/js')
4   .sass('resources/assets/sass/app.scss', 'public/css');
5

フロントエンドの開発

Qiita さんに、自分にちょうど良い記事があり、追って開発することで Vue.js 開発の理解を得ました。 次の記事を基本に、ちょっと手を加えたものを掲載していきます。

LaravelからVueを使ってSPAっぽくする
http://qiita.com/acro5piano/items/712b6b84151b53d0c53b

Vue.js の実装の前に、Laravel が担当する処理を実装します。

app.blade.php

JavaScript ライブラリで構築した Web アプリケーションであっても、「まずは HTML を出力し、その HTML から JavaScript コードを実行する 」という流れが基本です。

この HTML を Blade で実装します。

resouces/views/app.blade.php
 1<!DOCTYPE html>
 2<head>
 3    <meta charset="utf-8">
 4    <link rel="stylesheet" href="{{ mix('css/app.css') }}">
 5</head>
 6<body>
 7    <div id="app">
 8        <navbar></navbar>
 9        <div class="container">
10            <router-view></router-view>
11        </div>
12    </div>
13</body>
14<script src="{{ mix('js/app.js') }}"></script>
15</html>
16

<router-view>タグは、router-view によって動的に各ページのコンテンツに差し替えられます。

サーバサイドルーティング

上記の HTML を出力する「TOPページ」と「Vue.js からアクセスする API」の URL を Laravel に定義します。

routes/web.php
1Route::get('/', function() {
2    return view('app');
3});
4
routes/api.php
 1Route::group(['middleware' => 'api'], function() {
 2    Route::get('book',  function() {
 3        return [
 4            ['id' => 1, 'title' => 'リーダブルコード'],
 5            ['id' => 2, 'title' => 'プリンシプル オブ プログラミング'],
 6            ['id' => 3, 'title' => 'リファクタリング(新装版)'],
 7            ['id' => 4, 'title' => '情熱プログラマー'],
 8        ];
 9    });
10});
11

※今回は仮実装のため、ルーターから直にレスポンスを返しています。

クライアントサイドルーティング

app.js を修正してクライアントサイドのルーティングを定義します。
取り急ぎ、TOP ページに対応する Vue.js のみとします。

resources/assets/js/app.js
 1import Vue from 'vue'
 2import VueRouter from 'vue-router'
 3
 4require('./bootstrap')
 5
 6Vue.use(VueRouter)
 7
 8const router = new VueRouter({
 9    mode: 'history',
10    routes: [
11        { path: '/', component: require('./components/Articles/Index.vue') }
12    ]
13})
14
15const app = new Vue({
16    router
17}).$mount('#app')

Ajax アクセス

クライアントサイドからの HTTP リクエストには package.json に定義済みの axios を使います。

bootstrap.js を修正し、Vue.js のコード内から axios を利用できるようにしましょう。

resources/assets/js/bootstrap.js
1window.axios = require('axios')
2
3window.axios.defaults.headers.common = {
4    'X-Requested-With': 'XMLHttpRequest'
5}
6Vue.prototype.$http = axios
7

TOP画面のリストを実装する

先ほどクライアントサイドルーティングで定義した Index.vue を実装します。

resouces/assets/js/components/Articles/Index.vue
 1<template>
 2  <div>
 3    <div v-for="article in articles">
 4      <div class="row">
 5        <div class="thumbs">
 6          <router-link :to="'/book/' + article.id"><img :src="'/img/books/' + article.id + '.jpg'" :alt="article.title"></router-link>
 7        </div>
 8        <div class="book-data">
 9          <router-link :to="'/book/' + article.id">{{ article.title }}</router-link>
10        </div>
11      </div>
12    </div>
13  </div>
14</template>
15
16<script>
17export default {
18  created() {
19    this.fetchArticles()
20  },
21  data() {
22    return {
23      articles: []
24    }
25  },
26  methods: {
27    fetchArticles() {
28      this.$http({
29        url: '/api/book',
30        method: 'GET'
31      }).then(res =>  {
32        this.articles =  res.data
33      })
34    }
35  }
36}
37</script>

ローカルホストを立ち上げ、ブラウザでアクセスすると次の画面が表示されました!

Vue.js実装ページの表示イメージ
Vue.js実装ページの表示イメージ
画像ファイルは[ public/img/books ]以下に直接を設置しております。

トラブルシュート

cross-env.js の追加

npm run で次のようなエラーが発生しました。

 1$ npm run dev
 2
 3> @ dev /Path/to/Project
 4> node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js
 5
 6sh: node_modules/cross-env/bin/cross-env.js: No such file or directory
 7npm ERR! file sh
 8npm ERR! code ELIFECYCLE
 9npm ERR! errno ENOENT
10npm ERR! syscall spawn
11npm ERR! @ dev: `node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js`
12npm ERR! spawn ENOENT
13npm ERR!
14npm ERR! Failed at the @ dev script 'node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js'.
15npm ERR! Make sure you have the latest version of node.js and npm installed.
16npm ERR! If you do, this is most likely a problem with the  package,
17npm ERR! not with npm itself.
18npm ERR! Tell the author that this fails on your system:
19npm ERR!     node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js
20npm ERR! You can get information on how to open an issue for this project with:
21npm ERR!     npm bugs
22npm ERR! Or if that isn't available, you can get their info via:
23npm ERR!     npm owner ls
24npm ERR! There is likely additional logging output above.
25
26npm ERR! A complete log of this run can be found in:
27npm ERR!     /Users/[user_name]/.npm/_logs/2017-03-10T05_07_17_593Z-debug.log

次の Issue を参考に、package.json を前述のものに修正しました。

https://github.com/JeffreyWay/laravel-mix/issues/478

コンパイルエラー

はじめに導入した Node.js のバージョンは6系にしていました。
上記のエラーで Node.js のバージョンも関係しているのかと思い、Node.js のバージョンを変更したところ、次のエラーが発生するようになりました。

1Module build failed: Error: Missing binding Path/to/Project/node_modules/node-sass/vendor/darwin-x64-51/binding.node
2Node Sass could not find a binding for your current environment: OS X 64-bit with Node.js 7.x
3
4Found bindings for the following environments:
5 - OS X 64-bit with Node.js 6.x

npm のキャッシュクリア、SASS のリビルドを行なったところ、このエラーは解消しました。

1$ npm cache clean
2$ npm rebuild node-sass
3$ npm install --save-dev cross-env
4$ npm install

リビルドは次の Issue 参考にいたしました。

https://github.com/sass/node-sass/issues/1585

おわりに

今回はさらっとしか Veu.js を触っていませんが、そのメリットは十分に理解できました。
1 サイトとして作り込んで行く予定です。

作ったサイトがこちらです。

Vue.js で実装したサイトを公開しました
atuweb 開発ブログ

また、最新の WEB+DB PRESS に SPA の特集が掲載されております。
フロントエンド開発のメリット、デメリット、対処法が的確にまとめられており、最近の動向を把握できるいい内容でしたよ。

WEB+DB PRESS Vol.97

外村 和仁,小林 徹,古川 陽介,佐藤 歩,yoku0825,是澤 太志,一野瀬 翔吾,加藤 颯史,のざき ひろふみ,うらがみ,水嶋 淳貴,久田 真寛,久保 達彦,伊藤 直也,遠藤 雅伸,ひげぽん,海野 弘成,はまちや2,竹原,倉岡 洋義
出版社:技術評論社  発売日:2017-02-24

Amazonで詳細を見る


PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応

竹澤 有貴,栗生 和明,新原 雅司,大村 創太郎
出版社:ソシム  発売日:2018-09-26

Amazonで詳細を見る

Vue.js入門 基礎から実践アプリケーション開発まで

川口 和也,喜多 啓介,野田 陽平,手島 拓也,片山 真也
出版社:技術評論社  発売日:2018-09-22

Amazonで詳細を見る

参考サイト

Node.jsの管理をHomebrewからnodebrewに変える
http://qiita.com/takeshi81/items/805f504503cd93151ca6

LaravelからVueを使ってSPAっぽくする
http://qiita.com/acro5piano/items/712b6b84151b53d0c53b

株式会社インフィニットループ技術ブログ
5分でわかるVue.jsと、jQueryで頑張ってはいけない理由
https://www.infiniteloop.co.jp/blog/2014/06/5min_vuejs/

ある蜜柑の上にアルミ缶
まだjQueryで消耗してるの? これからはVue.jsでラクにいこう
https://s8a.jp/jquery-to-vuejs