Laravel + Vue + Vuetifyでbundle sizeの削減を試みてみる

この記事は[ZOZOテクノロジーズ #4 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech4) 9日目の記事になります。
昨日は[@ahiru_official
](https://qiita.com/ahiru_official)さんの[一定以上スクロールしたらヘッダーが固定するScrollViewをたったの1行で実装する方法](https://qiita.com/ahiru_official/items/20cb614774895d5424b8)でした。

また、今年は全部で5つのAdvent Calendarが公開されています。
[ZOZOテクノロジーズ #1 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech)
[ZOZOテクノロジーズ #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech2)
[ZOZOテクノロジーズ #3 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech3)
[ZOZOテクノロジーズ #5 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/zozo_tech5)

## 環境
* OS
    * Mac OS
* Laravel 5.7
* Vue 2.6
* Vuetify 1.5

## 背景
Laravel-mixでテンプレート側でVuetify.jsを使用したところ、下記のような表示がでることに気づきました。
<img width="1081" alt="スクリーンショット 2019-12-08 22.18.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245174/f0bfbf22-2817-e6b6-906a-10b8a16d5503.png">

この原因を探りつつ削減を試みてみたので、そのログと解決方法を残します。

## 解決までの道のり

### そもそもの原因調査  

そもそもapp.jsのどの部分が肥大化しているのかを確認するために、[webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer)を用いて解析を行いました。

今回はLaravel-mixを用いてビルドを行なったのですが、webpack-bundle-analyzerをLaravelで使用しようとしたところ、動作がうまくいかなかったので調べたところ、[Laravel-mix用のもの](https://www.npmjs.com/package/laravel-mix-bundle-analyzer)があったため、こちらをインストールします。

```bash
npm install laravel-mix-bundle-analyzer --save-dev
```

次に、webpack.mix.jsに下記の記述を追加します。

```javascript:webpack.mix.js
const mix = require('laravel-mix');
require('laravel-mix-bundle-analyzer');

if (!mix.inProduction()) {
    mix.bundleAnalyzer();
}
```

mix.bundleAnalyzer部分で何も指定しない場合、デフォルトの設定となりますが、デフォルトだとビルド後に毎回webpack-bundle-analyzerの画面が表示されるため、私の場合はオプションに`{openAnalyzer: false}`を指定しました。

この状態でビルドを行うと127.0.0.0:8888でbundle sizeの状態を確認することができます。
自分が初回実行した際は以下のような構成となっていました。

![スクリーンショット 2019-12-08 22.42.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245174/247aa1cd-713d-e64d-201e-6771c3d77f56.png)

これをみると、大部分をvuetify.jsが占めていたため、これを解決すれば半分くらい直せそうな気がしてきました。

### Vuetify.jsを減らしてみる
次に、原因となっているVuetify.jsのサイズ削減を試みます。
Vuetifyの[公式ガイド](https://vuetifyjs.com/ja/guides/a-la-carte)に沿って作業を行いました。

#### import方法の変更
先ほどのガイドにあった通り、importをパッケージ全体からvuetify/libのインポートに変更します。

```javascript
import Vuetify from 'vuetify'
↓
import Vuetify from 'vuetify/lib'
```

この時点でビルドを行うと、下記のエーラが発生しました。

```bash
ERROR in ./node_modules/vuetify/lib/components/VRadioGroup/Vxxxxx.js
Module not found: Error: Can't resolve 'stylus-loader' in '/xxxxxxx'
```

stylus-loaderがcan't resolveとのことだったのでインストール

```bash
npm install stylus stylus-loader
```

再度ビルドを行い、結果を見ると、半分くらいのサイズに
<img width="1078" alt="スクリーンショット 2019-12-08 22.55.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245174/7e12e5f7-e8e2-45eb-3eb0-c92a8761a1ab.png">


ここで終わってもいいのですが、まだbigなのが気にくわないので、gzip化対応を行います。

#### gzip化対応
[こちらの記事](https://qiita.com/nittannittan/items/386f5e20478a28413429)を参考にgzip化を行います。
最終的なサイズは以下の通りとなりました。

<img width="1083" alt="スクリーンショット 2019-12-08 23.23.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245174/69458fae-727d-05ee-a865-bacc85b0a728.png">

最終的に971KiB -> 118KiBまで、約8倍の削減に成功しました！