Apache(Heroku)+laravel+vue.js環境下でgzip圧縮によるサイトパフォーマンス向上

# はじめに

どうも、@nittannittanです。

趣味でAndroid/iOS/Webアプリを作成しているアニメオタクです。

最近SPAとして開発をした[Webサービス](https://latest-anime.herokuapp.com/)の機能が増えてきたために初回アクセス時のjsロード時間が30秒ほどかかってしまうほど激遅になってしまったのでgzip圧縮で対応をしてみました。

初歩的な技術かもしれませんが、私の環境に完全に合致する記事が探せなかったので本記事を作成しました。

# 関係する技術

- PHP
- Laravel Mix
- Vue.js
- heroku
- compression-webpack-plugin

# 1. compression-webpack-pluginをインストール

```
npm install compression-webpack-plugin --save-dev
```

# 2. webpack.mix.jsにcompression-webpack-pluginの記述を追加

下記の２つの処理をwebpack.mix.jsに追加しmixでのapp.js生成時に同時にgzファイルを生成する。

```javascript
const CompressionPlugin = require('compression-webpack-plugin');
```

```javascript
mix.webpackConfig({
    plugins: [
      new CompressionPlugin({
        filename: '[path].gz[query]',
        algorithm: 'gzip',
        test: /\.js$|\.css$|\.html$|\.svg$/,
        threshold: 10240,
        minRatio: 0.8,
      })
    ]
  });
```

追加後は下記

```javascript

const mix = require('laravel-mix');
const CompressionPlugin = require('compression-webpack-plugin');//追加
/*
 |--------------------------------------------------------------------------
 | 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')
   //追加
   .webpackConfig({
    plugins: [
      new CompressionPlugin({
        filename: '[path].gz[query]',
        algorithm: 'gzip',
        test: /\.js$|\.css$|\.html$|\.svg$/,
        threshold: 10240,
        minRatio: 0.8,
      })
    ]
  });
   
if (mix.inProduction()) {
    mix.version();
}
```

# 3. ビルド

リリース用ビルドを実行する

```
npm run production
```

完了するとcssとjsのgzipファイルが生成されます。

![スクリーンショット 2019-01-06 10.00.46.png](https://qiita-image-store.s3.amazonaws.com/0/122308/e45b9de2-e91e-c5d9-fdbb-0c79854bd2d8.png)

1/3ほどになりましたね。やったぜ。

# 4. .htaccessにgzipをレスポンスで返却するように設定

gzipファイルを用意しただけではレスポンスでgzipを返してはくれません。
heroku上ではapacheを利用しているので、.htaccessにgzipの設定を追加します。

```conf
    # gzip対応
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteCond %{REQUEST_FILENAME}\.gz -s
    RewriteRule ^(.+) $1.gz

    <FilesMatch "\.css\.gz$">
        ForceType text/css
        AddEncoding x-gzip .gz
    </FilesMatch>
    <FilesMatch "\.js\.gz$">
        ForceType application/x-javascript
        AddEncoding x-gzip .gz
    </FilesMatch>

    Header append Vary Accept-Encoding env=!dont-vary
```

laravelはもともと.htaccessでindex.phpへのリダイレクトをコントロールしているため追加後は下記のようになります。

```conf
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

    # gzip対応
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteCond %{REQUEST_FILENAME}\.gz -s
    RewriteRule ^(.+) $1.gz

    <FilesMatch "\.css\.gz$">
        ForceType text/css
        AddEncoding x-gzip .gz
    </FilesMatch>
    <FilesMatch "\.js\.gz$">
        ForceType application/x-javascript
        AddEncoding x-gzip .gz
    </FilesMatch>

    Header append Vary Accept-Encoding env=!dont-vary
</IfModule>

```

今回の環境に不要なプロキシの設定も最後にありますが、各自で判断して記載してください。
ちなみに私は.htaccessに食わず嫌い的な苦手意識があるので参考サイトのほぼコピーです。。。

それを少し改善しようと思ったので下記を確認して少し理解はしておきました。

https://html-coding.co.jp/knowhow/tips/wp_modrewrite/
https://github.com/EC-CUBE/ec-cube/issues/1607

# 5. Heroku環境にデプロイして動作確認

普段と同じようにHerokuにgit pushを行ってリリースします。
その後ChromeのDevToolsでリクエストとレスポンスを確認します。

Content-Lengthもgzipファイルと同じサイズですし、Content-Encodingもx-gzipになっているので成功していそうですね。

<img width="600" alt="スクリーンショット 2019-01-06 10.26.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/122308/6135f6e3-2bff-34f5-bf16-f780abad4c36.png">

雰囲気で.htaccessをコピペして試したらうまく言っているようなのでうまく行き過ぎて不安は感じましたが.htaccessを再確認しても不明点や問題になりそうなものもないため良しとします。
間違いがあればご指摘していただけると嬉しいです。

# Laravel Mixについて

Laravelを仕事で使いそうという理由でLaravelを選択しせっかくだからSPAにしようということでドキュメントに従ってLaravel Mixを利用していますが、日本語の記事をあまり見かけないので流行っていないのかもと心配になりますね。ただとても簡単にwebpackの環境が導入できたのでLaravel Mixはとても気に入っています。簡単に使えるから特に迷うこともなくて記事が少ないというのもあるかもしれませんね。

# 開発しているWebサービス（LAR）について

[LAR](https://latest-anime.herokuapp.com/)は放送時期（クール）ごとにアニメを一覧で見ることができるサービスです。
ログイン不要で自由にアニメの一覧が作成できる「[おすすめアニメメーカー](https://latest-anime.herokuapp.com/recommend_maker)」やアニメのランキングが自由に作成できる「[アニメランキングメーカー](https://latest-anime.herokuapp.com/ranking_maker)」などの機能があります。

- 放送クールごとの一覧表示
- [おすすめアニメメーカー](https://latest-anime.herokuapp.com/recommend_maker)
- [アニメランキングメーカー](https://latest-anime.herokuapp.com/ranking_maker)
- お気に入り表示（ログイン後のみ）
- MY番組表表示（ログイン後のみ）

# 参考サイト

https://github.com/webpack-contrib/compression-webpack-plugin

https://murashun.jp/blog/20141223-01.html

https://hyper-text.org/archives/2012/11/webcontents_gzip.shtml

https://stackoverflow.com/questions/50136195/how-to-include-webpack-plugins-when-using-laravel-mix