Next.jsアプリのパフォーマンスを上げる(lighthouseの利用)

Next.js でシステム開発しています。

ログイン機能や記事を表示するなど、意気揚々と色々な機能を構築してたんです。
でもある日、気がついちゃいました。

スーパーリロード後 → 「読み込みちょっと遅くない……？」

そう思い、LightHouse で調べて見た結果が以下です。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87695/92aeb6a2-3aa7-3948-218f-486edf89e3b7.png)


あと一個７が付いてくれたら、パチスロではハッピーな数字ですが、Web アプリのパフォーマンとしてはいただけません。

## LightHouseってなに？

ウェブアプリの品質をチェックするためのツールで、Chromeの拡張ツール及びNodeでのCLIツールとして、Googleが提供をしています。

https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=ja

LightHouseでは、以下５つの項目別に１００点満点で点数が付けられます。

### Perfomance (パフォーマンス)

サイト内のスピードに関する評価です。
ページの読み込み速度や、ユーザーが操作することで発生するレスポンス速度。

### Accessbility (アクセシビリティ)

ユーザーや検索ロボットに対して、最適な作りになっているかどうかを確認します。

分かりやすい例で言えば、Imageタグにaltでテキストを入れていないと点数が下がります。

### Best Practices （ベストプラクティス）

HTTPSは使用されているか？脆弱性のあるAPIは使っていないか？等、技術的なチェックをしてくれます。

### SEO

これは字のごとく、Googleの検索ランキングに反映に影響がある記述が無いかをチェックするための項目です。


### PWA

ウェブサイトをPWA化するために必要な項目を、以下のチェックリストの内容で確認を行っています。

https://web.dev/pwa-checklist/

具体的には、
- どのブラウザでも動かくことができるのか？
- レスポンシブデザインになっているか？
等など。


## この記事のミッション

LightHouseの、Perfomance (パフォーマンス)を９０以上にする。

※ユーザーの操作感をアップさせたい！

## 記事の対象

- Next.Js で開発される方

注意点として、パフォーマンスの低下の原因は千差万別ですので、すべてのアプリ開発に当てはまるものではありません。


## パフォーマンス低下の原因と対策

### 原因 ①：Reduce unused JavaScript(使用していな JS の読み込み)

使用していないがダウンロードしている JS スクリプトが有り、私の場合は以下のような結果がでていました。

```
...pages/...js    サイズ   84.8 KiB  抑えられるはずサイズ 63.7 KiB
...chunks/...js   サイズ 1033.6 KiB  抑えられるはずサイズ 50.7 KiB
```

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87695/6ee3a80b-0238-4df4-7565-23aeb869289d.png)

chunks については、桁数が違いますね。

余計な JS を記載している自覚はなかったため、どこに無駄があるのかが把握できません。

以下ライブラリを使い、現状の JS を把握することにしました。

#### webpack-bundle-analyzer

公式の説明にあるように、Webpack でバンドルされる JS を視覚的に表示してくれるライブラリです。

> Visualize size of webpack output files with an interactive zoomable treemap.

https://github.com/webpack-contrib/webpack-bundle-analyzer

以下の方法で、インストールします。

```bash
npm install --save-dev webpack-bundle-analyzer
# or
yarn add -D webpack-bundle-analyzer
```

次に、 [ next.config.js ] に以下を追記しましょう。

```js
const BundleAnalyzerPlugin =
  require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

module.exports = {
  plugins: [new BundleAnalyzerPlugin()],
};
```

[ package.json ] に追記します。

```js
  "scripts": {
    // 省略
    "bundle-analyzer": "ANALYZE=true next build"
  },
```

#### ※ 既に [ next.config.js ] に、取り込んでいるライブラリがある場合。

複数プラグインを取り込む場合は、next-compose-plugins を使うと良いでしょう。

https://github.com/cyrilwanner/next-compose-plugins

以下は i18n と併用した例です。

まずは、next-compose-plugins をインストール。

```bash
npm install --save next-compose-plugins
# or
yarn add next-compose-plugins
```

[ next.config.js ] に以下を追記しましょう。

```js
/**
 * next-compose-plugins
 */
const withPlugins = require("next-compose-plugins");

/**
 * webpack-bundle-analyzer
 */
const withBundleAnalyzer = require("@next/bundle-analyzer")({
  enabled: process.env.ANALYZE === "true",
});

/**
 * i19n
 */
const i18n = {
  i18n: {
    locales: ["en", "ja"],
    defaultLocale: "ja",
  },
};

module.exports = withPlugins([withBundleAnalyzer({}), i18n]);
```

#### 準備ができたら、実行して確認

```
yarn bundle-analyzer
```

そうすると以下のような画面が表示されます。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87695/314a93e6-07dd-3879-8bc6-bfc9abde8ce5.png)

よく見ていると、[ highlight.js ] の 1.4MB 占領していました。


#### highlight.js の 読み込みを抑える。

[highlight.js](https://highlightjs.org/) は ソースコードをハイライトしてくれる便利なライブラリです。私は marked というライブラリ と併用しています。

https://highlightjs.org/

しかし、使用頻度が少ないプログラム言語まで含めてライブラリを読み込んでいるため、JS のサイズが膨れ上がっているようでした。

そのため以下のように、対応が必要な言語のみ読み込むことにしました。

```js
import marked from "marked";
import highlightjs from "highlight.js/lib/core";
import javascript from "highlight.js/lib/languages/javascript";
import ruby from "highlight.js/lib/languages/ruby";
import go from "highlight.js/lib/languages/go";

// -- コンポーネント内 --
highlightjs.registerLanguage("javascript", javascript);
highlightjs.registerLanguage("ruby", ruby);
highlightjs.registerLanguage("go", go);

marked.setOptions({
  highlight: function (code, lang) {
    return highlightjs.highlightAuto(code, [lang]).value;
  },
});
// ----
```

上記のように記載すると、LightHouseでの警告は解消されました。


### 原因 ②：Dynamic import を活用していなかった。

クライアント側で初めて描写されるコンポーネントは Dynamic import にしておくと読み込み時のパフォーマンスが上がります。

https://nextjs.org/docs/advanced-features/dynamic-import

```js
const DynamicComponent = dynamic(() =>
  import("../components/hello").then((mod) => mod.Hello)
);
```


## とりあえずなんと９０台へ。

正直まだ不安定感はいなめませんか、数字は随分とよくなりました。
まだまだ改善の予知はありそうです。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87695/7bc727e4-6b5f-41b9-45c3-c628aab3ee30.png)


またなにか分かり次第、追記いたいします。


## 参考サイト

以下、参考にさせていただいた記事です。
有難うございます。

https://t-yng.jp/post/nextjs-perf-improvement

https://tech.012grp.co.jp/entry/next_dynamicImport

https://stackoverflow.com/questions/61450165/reduce-js-execution-time-with-nextjs![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87695/dcf99469-23ab-1fb0-a6d6-6262a8f7f2fa.png)

## 変更履歴
(2021/10/7)

- タイトルを一部修正しました。
- LightHouseってなに？ を追加しました。
- 誤字脱字を一部修正しました。