『Laravel + Vue.js』プロジェクト導入前の３つの心得

#はじめに


[Vue #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vue2) の7日目の記事です

この記事は
企業レベルで**『プロジェクトとしてVue.jsを導入してみての感想』**の共有を行うことが目的です、
そしてその中でも**私の感じた『Laravel + Vue.jsプロジェクト導入前の３つの心得』**についてご紹介致します。
記事内容に、間違いなどございましたらコメント欄でやさしくリプライしていただければ嬉しいです(^^♪
今回初投稿なので・・・

###前提条件
・ウェブフレームワークは既にLaravelを使用
・プロジェクト目的は、速度改善、脱スパゲッティーコード化、新規技術導入などを含む
・具体的なプロジェクト内容は、スマホのウェブページ、コンポーネント化
・Vue.jsの単一コンポーネントの利用（CDNではない）


#TL;DR
上記の条件下で私の感じた3つの心得

**その１：JSのバンドルサイズ意識しよう**
**その２：ライブラリ導入の選定は早めに行おう**
**その３：なんでもVue.jsでやろうとせずスコープを決めよう**

では詳しく紹介していきます


##心得その１：JSのバンドルサイズを意識してコーディングしよう
単一コンポーネントを利用する際、Laravelでは**「laravelmix」**と呼ばれるwebpackの進化系みたいなもの（warpper）を利用してアセットのコンパイルを行わないといけないのですが、
この際、**バンドルされたJSファイルがすぐに肥大化**するので最初から意識してコーディングしてねという話です。

laravemixの設定ファイルはデフォルトでは以下みたいな感じになっています（Laravel 5.x系）

```js: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');
```

###webpack知識の重要性
事前に「laravelmix抜き」の**"本来のwebpackでVue.js"**を使用する場合は、利用者さんがきちんとwebpackを理解してVue.jsを利用している可能性が高いかもしれませんが
あなたがもし今回初めてVue.jsを利用するVue.js初学者さんでwebpack利用経験がないのであれば、
**「laravelmixで利用するwebpack」が別物**だということを心得ておく必要があるかもしれません。

実際Laravelで利用するlaravelmixは、webpackへの詳細な知識がなくてもある程度簡単に動作してくれます。
しかしwebpackについて理解なしにwebpackのwrapperのlaravelmixから利用するのは危険です。
あなたがもしwebpackの知識をきちんと理解しているのであれば**この設定ファイルの設定見直しだけでもページの速度改善になります。**
ちなみにwebpackの設定はlaravelmixより詳細に設定項目があり、より細かに調整ができます。

###バンドルサイズ肥大化の原因
```js:webpack.mix.js
mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css');
```

上記の設定ファイルの中を見てみましょう。
laravelmixでバンドルする対象のファイルの記述が設定されていますね。
（resources/js/app.jsがVue.jsの**Vueインスタンスファイル**にあたります。）
こちらのファイルが１ファイルにバンドルされて、public/js配下にコンパイルされます。（npm run~コマンド実行時）
肥大化する原因は私なりですが**以下の2つ**のいずれかです。

**原因１：ライブラリの追加しすぎ**
バンドルしたJSファイルは**デフォルトのままで既に2万行近くある**ので、そのままではとても重いです。
加えて使いたいライブラリなどが追加されれば、追加した分だけバンドルサイズが大きくなっていきます。

**原因２：Atomic Designを細かく分けすぎる**
今回のプロジェクトでは部品化する際のデザインパターンを「Atomic Design」に則り進めたのですが、部品を細かくしすぎてもあまりよくありません。Atomレベルでさえ１つの.vueファイルで3KBくらいはあるのでコンパイル時にバンドルするJSサイズが肥大化する原因になってしまうのです。よって、再利用性の少ない「Atomレベルは作成しない」などルールを決めてもよいかもしれません。

###おまけ：extract設定してライブラリファイル分割する方法
```js:webpack.mix.js
mix
   .js("resources/assets/js/app.js", "public/js") 
   .extract(["vue", "axios", "vuex"])//bootstrap.js内でimportしているライブラリー名を記述
   .version(); 
```
バンドルで１ファイルになるとお伝えしましたが、laravelmixではextractに記述するだけでライブラリファイル分割可能です。
extractにライブラリ指定してあげれば、指定したライブラリ群がバンドルJSファイルから外にだされ、別ファイルとして（manifest, vendor.js）分割できます。このような設定は[laravelmixのアセットコンパイル公式](https://readouble.com/laravel/5.6/ja/mix.html)の各バージョン毎に記述の仕方が書いてあります。Vue.jsをLaravelで書き始める前にぜひご一読ください。

###バンドルしたJSファイルサイズ目安

JSのバンドルサイズの目安は[一休.comさんのスマホサイトのパフォーマンス](https://user-first.ikyu.co.jp/entry/2018/09/20/090000)についてのブログにも記載がありますが、
"一休"さんのスマホサイトのプロジェクト時では、１ページ300KBを上限にして、それ以下に抑えるようにコーディング意識していたりします。

私のプロジェクトではこのようなルール決めを一切行いませんでした。結果、バンドル後のJSファイルがかなり肥大化してしまい重いスマホサイトが出来上がってしまいました。( ;∀;)

###解消策：より具体的な目標を立てる

**プロジェクト開始前にメンバー間で、具体的なバンドルサイズ目標をたてることが効果的です。**1ページ300KB以下のバンドルJSファイルと残りのリソース700KBまでに抑えるなどより具体的な数値を設定しましょう。
他には、『Googleのpage speed insights（速度計測ツール）で70点以上を獲得する』などでもよいかもしれません。大事なのは達成できなさそうだとしても**「意識すること」**です。そのための目標の設定は重要かと思います。

ちなみに
グーグル推奨値のリソースの合計サイズが1.6MBとの発表の記事を以前読んだことがあります。これは３G回線のモバイル端末でストレスなくアクセスできる*最低の基準*です。（実際には1.6MBでもまだ重い気がするので。）1.6MBは全体のリソースサイズなので、この中でJSはさらに小さく抑えるべきです。こういった基準値をプロジェクト前に調べてルール決めを行い認識合わせすることは大事です。
せっかく導入したのなら、ページが重くならないように気を付けましょう。

##心得その２：ライブラリ導入の選定は早めにしよう

これもかなり悩ましかったのですが、「とりあえずVue導入して、それからあとのこと考えればいいさ」みたいに考えていたので
Vue.js導入を最優先したのですが（ダメ人間）
**導入前のライブラリの選定はものすごく大事**です。選定を間違えると、先ほどの話のJSのバンドルサイズの肥大化につながります。

加えて後から導入すると改修がより困難なものなどもあるので早めに検討してから導入したほうが良いでしょう。
**ライブラリ選定も設計の一部だと心得てきちんと選定しましょう**


###初めから導入したかったライブラリ
・vuex(状態管理ライブラリ)
・vue-cli（cli）
・storybook（UIコンポーネント管理系）
・vue-router（ルーティング系）
・SPAも可能ならNuxt.js

中でもvuexは最初に導入しておけば手戻りが発生しなかったかと後悔しています。
propsでの受け渡しが親子孫までの関係のあるモジュールを作成した場合、vuexを導入した方がより簡単に人為的ミスを無くしてスマートにコードを書くことができると感じました。しかしvuexも完璧ではなく、全てvuex化してしまうと逆に重くなってしまったりするので、トレードオフを忘れずに。
vue-cliについてはあればおそらく前準備をコマンドライン入力で簡単にはじめられたことでしょう・・・[参考サイト：『これでわかるはじめてのvue-cli』](https://reffect.co.jp/vue/finally-understand-vue-cli)
storybookが初めからあればデザイナーとのコンポーネントのデザイン及び設計についてのやり取りがもっとスムーズになったことでしょう・・・[参考サイト：Qiita記事『Storybook for Vue 入門』](https://qiita.com/SotaSuzuki/items/b20167ee811aa3bd29df)
vue-routerがあれば遅延ローディングルートを利用して各ルートコンポーネントごとに別々にチャンクして、訪れたルートの時だけロードできるようにルーティングできたでしょう・・・[参考サイト：公式リファレンス『Vue Router』](https://router.vuejs.org/ja/guide/advanced/lazy-loading.html)

###おまけ：一般的にWeb関連の企業で導入されているnode_modulesのライブラリ群
株式会社LINE様のVue.jsの勉強会で行われたUIT#5イベントでは多くの企業が以下のライブラリを導入してVue.jsのWebページなどを実装していました。参考までに共有します。
・vue-router
・vue-cli
・storybook
・vue-whiteroom(storybookに変わるライブラリ)
・Nuxt(SPA化など検討する場合のVue.jsのライブラリ)

イベント情報詳細：[UIT#5 わたしたちにとってのVue.js](https://uit.connpass.com/event/107337/)

###解消策：プロジェクトスタート前にライブラリ調査・選定
vuexの導入を例に挙げたように使う可能性があるライブラリ群は早めに決めておきましょう。ただし、不要なライブラリは取り除かないとすぐに肥大化します。必要か不必要か今一度メンバーで確認し必要最低限のライブラリ選定を心がけ、同じようなライブラリが存在するか確認、もし存在すれば、より軽いサイズの代用ライブラリを導入しましょう。

又、ライブラリ自体をバンドルJSファイル外で読むこともできるので**「バンドルに何を含めるのか」**よく考えて選定してください。

##心得その３：なんでもVue.jsでやろうとせずスコープを決めよう
今回のVue.jsの導入はLaravelでのVue.js導入だったのですが、プロジェクト開始直後私の頭の中では『新しい技術の良さを他のエンジニアに理解してもらう』ことに比重を置いていたので、Vue.jsをたくさん利用しようと考えていました。広める為にできるだけVue.jsでコーディングしようとしていたのです。その結果、本来Laravel側で事足りるものですらVue化してしまいました。JSバンドルサイズは3万行を超え、SPの初期読み込み時間はtestmysiteで（3Gで）10秒ほども出てしまうほど重いものになりました。JSのファイル数を減らせば読み込みが早くなると思っていた私ですが、1ファイルが非常に長い場合も同様にペナルティーになってしまいます。なんでもVue.jsでやろうとしてしまうと結果ページが重くなることさえありうるのです。（私の設計ミスの可能性もありますが・・・）

プロジェクトが進んでいくにつれ私の作成したVue.jsページはただ単に重い不便なページになっていました。( ;∀;)
ではどうすればよかったのでしょうか・・・

私が今回、具体的に失敗した点は、
**Laravelで利用できるインクルードなどを捨てすべてVue.jsのコンポーネントに修正**していたところにあります。既存の動いているコードはどんなコードであれ資産です。なんでも改修しようとするのでなく、不便さや不要箇所、エラーやバグがある場合のみ改修すればよかったのかもしれません。
既にLaravelのインクルードで実装されていたヘッダー部分の共通部品までVue化を行い、ほかにもフッターなどのすでにあるモジュールですらすべてVueのコンポーネントにしてしまったのです。プロジェクトの目的にもよるとは思うのですが、パフォーマンスの観点でいうと部品が増えればバンドルしたJSファイルのサイズも比例して大きくなるので動いているモジュールすべてをスコープに含むことは間違っていたかもしれません。
Vue.jsの実装パターンはいろいろあるということを忘れてはいけません。
ページ全体をVue化してSPA化したり、一部品だけをVue化したり。
これはすべてに言える話なのですが**『大事なのは何の目的で、そのライブラリ、又はそのフレームワークを利用しているのか念頭に置いてコーディングすること』**です


###解消策：Vue.js適用範囲のスコープを決める
**『どれがLaravel側で行うべきこと』**で、**『どれがVue.js側で行うべきこと』**かということを意識する。これらは、おそらく「心得レベル」の話ではなく、「設計レベル」の話になってしまうかと思われます。しかし、Vue.jsをプロジェクトに導入する際は、適用範囲のスコープを決めて実装することが重要だと感じました。**加えて、スコープの妥当性、適用範囲の妥当性についても考えましょう。**
せっかくLaravelでVue.jsを使っているのに、Laravelの良さを捨てて何でもかんでもVue化してしまうのはもったいないこと。
Vue化する際は必ず、よりいい方法をトレードオフすることがとても重要だと強く感じました。



##結論
**その１：バンドルサイズを意識したコーディングを心がけないと重いサイトになる**
**その２：ライブラリ選定を早めにしないと手戻りが発生する**
**その３：Vue.jsでなんでもやろうとすると保守しにくいサイトになる**

総じて
Vue.jsのプロジェクト導入を検討しているそこのアナタ！簡単に導入できるからと言って侮らないこと！