短期間でできるSPAのパフォーマンス改善（Code Splitting/動画排除/webP/テキスト圧縮）


Core Web Vitals導入のアナウンスがあって久しいですね。
[【Google】2021年5月からCore Web Vitalsがランキング要因になると発表！](https://digitalidentity.co.jp/blog/seo/algorithm/core-web-vitals.html#:~:text=Core%20Web%20Vitals%20%E5%B0%8E%E5%85%A5%E3%81%AE,%E3%82%B7%E3%82%B0%E3%83%8A%E3%83%AB%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82)

しかし、担当しているSPAのページの読み込みが、機能が徐々に増えたせいかなんとも遅い。
lighthouseで採点してみるとパフォーマンスが20点台です。Oh...
短時間でやれそうな施策を行い3,4日で70台まで数値を回復しましたので、「とにかく急ぎでスコアを上げたい！」という方はぜひチャレンジしてみてください。


## まずIE11を殺す
まずIE１１殺しを提案しました。
アナリティクスで確認したところ、IE11のシェアがほとんどなく、パフォーマンス向上を最優先に、という判断で採択していただきました。
これでやれる施策の枠が広がります。
もちろんポリフィル対応などでカバーできる部分もありますが、それをやる工数・そもそもIEのせいでデータ量増えた😣といったことがなくなりました。
やったぜ。

## 施策1: webP対応
[次世代画像形式のWebP、そしてAVIFへ](https://ics.media/entry/201001/)
**webP(ウェッピー)形式**は高い圧縮率にも関わらず劣化が少ない次世代フォーマットです。
![スクリーンショット 2020-12-29 11.25.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441432/ccd5cc66-1bd1-3bf6-0177-aa033a08400f.png)

ご覧の通り一部のブラウザには対応してないので注意です。例えばIEとIEとかIEとかですね。
IE以外でも古いバージョンのSafariは非対応なのでご注意ください。

もともと画像圧縮はgulpで行なっていましたので、今回は [gulp-webp](https://www.npmjs.com/package/gulp-webp)を使い、SPA内の静的画像を全てwebpに変換しました。


```js:gulpタスク
const webp = require('gulp-webp')

function webpConvert() {
  return gulp.src(paths.img)
    .pipe(webp())
    .pipe(gulp.dest(paths.img_build))

// (以下略)
}
```

webpにすることで、圧縮前は14.2MBだった画像が1.8 MBになりました。すごすぎる。
あとはソース内の `.jpeg` だったり `.png` だったりを `.webp` に置換してあげれば一丁あがりです。



### 計測結果
LightHouse(web)で計測したところ、上記によって

```
ページ1: 14 -> 34
ページ2: 22 -> 38
```
に上昇しました。
(表示速度はメモるの忘れてました、ごめんなさい🙏)


## 施策2: Code Splitting
SPAは一番最初にJS全体を読み込むので、大きなサイトほど初期表示が非常に時間がかかります。
buildした時もファイルサイズが大きすぎます!と警告が出てきてたりしたので、これは改善せねばなりません。
Code Splittingのやり方はいくつかあるのですが、今回は急ぎということもあってReactの `Lazyload`　を使って各ページ毎にまずは分割しました。

```react:Router
import React, { lazy, Suspense } from 'react'

const About = lazy(() => import ('./containers/About'))
const News = lazy(() => import ('./containers/News'))

const Router = () => (
  <>
    <App>
       <Suspense fallback={<Loading />}>
          <Switch>
            <Route exact path="/about" component={About} />
            <Route exact path="/about" component={News} />
```

[React公式 コード分割 React.lazy](https://ja.reactjs.org/docs/code-splitting.html#reactlazy)

上記により、buildするとルート毎のJSが吐き出されるようになります。
そして、実際に遷移した時に初めてそのルートのJSを読み込むようになります。
読み込みが終わるまでは `<Suspense>` で指定したfallbackが描画されます。

### 計測結果
なんと、あまり変化がありませんでした...

```
ページ1: 34 -> 35
ページ2: 38 -> 35
```

ですが、初回で読み込むJSは 1.6MB -> 800kBほどに減少したので、
ユーザビリティーが向上したことは間違いありません。
lighthouseの数値が絶対ではないのです🤖

## 施策3: 動画（youtube）重すぎ問題の改善
ページ1,ページ2両方ともページ内にyoutubeのiframeを埋め込んでいました。
ですが、測定したところ、これがかなりボトルネックになっていることに気がつきました。

そこでこの記事を見つけます。
[YouTube埋め込みが原因で重いホームページを高速表示させる方法](https://ka-holidayrefresh.com/youtube-site-speed/)

>動画を無くす。
>YouTube動画のサムネイルのみを取得する方法で、見た目はほとんど変わらず動画があるように見せます。

おお、目から鱗。
ということでディレクターさんに相談し、
**ページ1では動画を削除、ページ2ではyoutube風の画像を配置し、youtubeへリンクを飛ばす**ことにしました。

### 計測結果

```
ページ１ 35  -> 41
ページ2 35 -> 57
```

かなり効果ありました。やっぱり一本といえども、動画は重たいものですね。


## 施策4: JSコード圧縮
やらねばやらねばと思ってやっていなかったこちら。
テキストファイルをgzipで圧縮し配信する方法です。これによりリソースのダウンロード時間を削減できます。
今回は一番サイズの大きかったJSのみ対応していますが、HTMLやCSSもgzipで圧縮して配信できます。
また、webpackで圧縮 + apacheで配信設定という方法で行いました。

まずは  [compression-webpack-plugin](https://www.npmjs.com/package/compression-webpack-plugin)をnpmでinstallします。

```
$ npm i compression-webpack-plugin -D
```

webpack.configを下記のように調節するだけ。

```js:webpack.config.js
...
const CompressionPlugin = require('compression-webpack-plugin')

...
  plugins: [
    new CompressionPlugin({
      test: /\.js$/,
    })
  ]
```

これでビルドすると、各jsと圧縮された`.gz`のファイルがそれぞれ吐き出されます。

[gzip圧縮転送についてトコトン調べてみた](https://satoyan419.com/post/gzip-compression/)
こちらの記事を参考に、apacheも調整していただきました。

以下、記事内から抜粋

```
RewriteEngine on
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.+) $1.gz

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

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

800kB超えのコア部分のJSが 200KB台になりました。どんどん小さくなりますね。

### 計測結果

```
ページ1: 41 -> 79
ページ2:  57 -> 72
```
数値もかなり改善されました！

## 最終結果

```
ページ1: 14 -> 79
ページ2: 22 -> 72
```
## 所感

今回は短期間での取り組みでしたので細かい施策はできませんでしたが、もっとその辺やっていけばより読み込み速度を改善できそうです。
来年はなんとか緑台に...
また、スコアのみでなく読み込み速度も次回はメモして置こうと思います(･･;)