Nuxt.jsのSPAサイトにLighthouse CIをCircleCIで実行する

# はじめに

Webサイトの品質を計測するツールとして知られるLighthouseは、Chromeのdevtoolsや[Chromeエクステンション](https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=en)などから利用可能ですが、今では [Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci) によってCIからも利用できるようになりました。つまり、GitHubにコードをpushする度にCI上でLighthouseのチェックが行われ、スコアリングや改善可能な箇所を事前に知ることが可能であることを意味します。

そこでこの記事では、 **「Nuxt.jsで構築したSPAのサイトに対してCircleCIでLighthouse CIのチェック処理を実施する」** という環境を構築する手順について説明します。

なお、使用するフレームワークがNuxt.jsでなくてもほぼ同じ手順で環境構築は可能なはずなので、Nuxt.jsと記述している部分は他フレームワークに読み替えてもらっても大きな支障はありません。

## 前提
この記事は、既に以下の知識があることを前提とし、詳細は説明は省いています。

- GitHubレポジトリのセットアップ方法
- CircleCIのセットアップ方法
- Nuxt.jsによるSPAサイトの構築方法

また、この記事で紹介するコード、およびセットアップ内容は、[GitHubレポジトリ](https://github.com/Tsuyoshi84/nuxt-lighthouse-sample) で公開しています。

# セットアップ

## Nuxt.jsサイトの構築

まずは簡単なNuxt.jsのサイトを構築してみます。仮に、以下のようなページを持つように構成してみましょう。
(なお、Nuxt.jsのサイト構築は、[公式サイトのInstall方法](https://nuxtjs.org/guide/installation/) に従って行うものとし、ここでは詳細を割愛します。)

| ページ | パス|
|---|---|
| Home | `/` |
| About | `/about` |
| Contact | `/contact` |

Nuxt.jsのプロジェクトを構築後、適切なGitHubレポジトリにソースコードをpushしてください。

## Lighthouse CIのセットアップ

Nuxt.jsによるプロジェクトを構築したら、続いてLighthouse CIのセットアップをします。

### `@lhci/cli` のインストール

以下のコマンドを実行して `@lhci/cli` をNuxt.jsのプロジェクトにインストールします。

```sh
$ yarn add -D @lhci/cli
```

### scriptの追加

`package.json` の `scripts` に以下のようなスクリプトを追加します。

```json:package.json
{
  "scripts": {
    "lhci": "lhci autorun"
  }
}
```

### 設定ファイルの配置

続いて、Lighthouse CI用の設定ファイルを作成します。プロジェクトのルートディレクトリ直下に `.lighthouserc.json` という名前のファイルを配置し、以下内容を記述してください。


```json:.lighthouserc.json
{
  "ci": {
    "collect": {
      "numberOfRuns": 1,
      "startServerCommand": "yarn start",
      "url": [
        "http://localhost:3000/",
        "http://localhost:3000/about",
        "http://localhost:3000/contact"
      ]
    },
    "assert": {
      "preset": "lighthouse:no-pwa",
      "assertions": {
        "offscreen-images": "off",
        "uses-webp-images": "off",
        "uses-http2": "off"
      }
    },
    "upload": {
      "target": "temporary-public-storage"
    }
  }
}
```

- _注1) このサンプルプロジェクトではPWAを使用しないため、 `lighthouse:no-pwa` のプリセットを使用しています。Lighthouse CIはいくつかの [プリセット](https://github.com/GoogleChrome/lighthouse-ci/blob/28ba17417e76996aaf8d6cf50917e2a04b5a7d0c/docs/assertions.md#presets) を用意しているので、利用対象するプロジェクトに応じて適切なものを選択してください_
- _注2) `assertions` ではLighthose CIのルールを個別に設定しています。 [allのプリセット](https://github.com/GoogleChrome/lighthouse-ci/blob/40b46eeb9c273365ed950d10f11e6b51f2bcb46c/packages/utils/src/presets/all.js) から全てのasertionを確認することができるので、必要に応じて設定を変更してください_

### Lighthouse アプリの許可

GitHubでPull Requestを作成した際、以下のようなLighthouseのステータスを表示させるためには、Lighthouse CIのアプリを許可する必要があります。 
<img width="500" alt="Lighthouse status" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/0197ccf4-9be4-6319-6a9e-5657d7bce546.png">

[ドキュメントに記載](https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/getting-started.md#github-app-method-recommended) があるように、 [Lighthouse CI アプリ](https://github.com/apps/lighthouse-ci) のページからアプリをインストールして、GitHubレポジトリへのアクセス許可を与えます。

<img width="500" alt="Lighthouse CI App" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/eccf59b6-eebb-2e47-185f-a6a1c3cb0e69.png">

インストールをすると、以下のようなLighthouse CIのトークンが発行されるので、安全な場所に保管しておきます。
(このトークンは、後のCircleCIのセットアップで使用します)

<img width="500" alt="lighthousetoken.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/bb91c1af-6432-ebe4-cb70-f48911ccd78a.png">


## CircleCIのセットアップ

最後に、CircleCIのセットアップを行います。

### 設定ファイルの配置

CircleCIのconfigファイルを `.circleci` ディレクトリの中に配置してください。Lighthouse CIをCircleCIから実行させるため、設定は以下のように行います。

```yml:.circleci/config.yml
version: 2.1

commands:
  restore_npm_cache:
    description: "Restore npm cache"
    steps:
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
            - v1-dependencies-
  save_npm_cache:
    description: "Save npm cache"
    steps:
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}

jobs:
  lighthouse:
    docker:
      - image: circleci/node:12.3-browsers
    working_directory: ~/repo
    steps:
      - checkout
      - restore_npm_cache
      - run: yarn install
      - save_npm_cache
      - run: yarn build
      - run:
          name: lhci autorun
          command: yarn lhci || echo "LHCI failed!"

workflows:
  version: 2
  build:
    jobs:
      - lighthouse
```

### CircleCIプロジェクトのセットアップ

上記のconfigファイルをGitHubレポジトリにpushしたら、次にCircleCIをセットアップします。CircleCIプロジェクトの設定は [公式ドキュメント](https://circleci.com/docs/2.0/enable-checks) に従って実施するものとし、ここでは詳細を割愛します。

### 環境変数の設定

先の手順で生成したGitHubのアクセストークンをCircleCIに登録します。CircleCIのプロジェクト設定を開いて `Environment Variables` を選択し、 `LHCI_GITHUB_APP_TOKEN` という環境変数名でトークンを設定してください。

<img width="718" alt="circleci_environment.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/c0bd889d-1de7-1e5a-41f0-534aa499d435.png">


# CIの実行

ここまでの作業で、セットアップが完了しました。適当なPRを作って、CircleCIによるチェック処理を実行させてみましょう。以下のようにLighthouse CIのステータスがGitHubのPRに表示されれば成功です。

<img width="718" alt="circleci_environment.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/aa1116e0-ded5-8b7f-e5cd-2bea614f8032.png">

ステータスに表示される `Details` リンクをクリックすると、Lighthouseのレポートをブラウザから確認することができます。

<img width="500" alt="lighthouse_result.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/0176dc27-c2c2-2b5e-75b0-1a35c9d3140a.png">

- _注1) デフォルトのホスト先(Google Cloud)を使用している場合、上記のLighthouseレポートは7日後に自動的に削除されます_
- _注2) デフォルトの設定では、Lighthouse CIのレポートがホストされるのはパブリックな場所であり、URLさえわかれば誰でもアクセスは可能です。アクセス制限などをして適切に管理したい場合は、 [ドキュメント](https://github.com/GoogleChrome/lighthouse-ci/blob/master/docs/getting-started.md#the-lighthouse-ci-server) を参考にして環境を構築する必要があります。_

# 最後に

以上でCircleCIによるLighthose CIの実行環境が構築できました。これによって、サイトの品質を落とすようなコードが混入していないかのチェックがマージ前に可能となるので、有用なツールではないかと思います。

また、Lighthouse CIは他のCIでも利用可能であるため、TravisCIや[GitHub Actions](https://tech.smartshopping.co.jp/Lighthouse%20CI) でも使うことができます。自分が利用するCIに応じて、それらの環境構築方法をチェックしてみると良いでしょう。

# 参考

- [GoogleChrome/lighthouse-ci](https://github.com/GoogleChrome/lighthouse-ci)