Lighthouse CIサーバーを構築する

*この記事は韓国語から翻訳したものです。不十分な部分があれば、いつでもフィードバックをいただければありがたいです！ ([オリジナル記事](https://blog.chungjungsoo.dev/dev-posts/lighthouse-ci-server/), 同じく私が作成しました。)*


バスハニャーンプロジェクトにLighthouse CIを導入し、Lighthouse CIサーバーを構築してみました。


## 導入背景 

バスハニャーンサービスを開発する時、私たちのチームはいつもより速く、よりユーザーフレンドリーなサービスを作るために様々な試みと[努力](https://qiita.com/ChungJungSoo/items/7522e0023d7e2b191cad)をします。その中で気にする指標の一つがGoogleが提供するLighthouseです。しかし、この指標はデバイスによって、特にパフォーマンスの部分でスコアが異なる場合があり、開発者が毎回修正して直接テストを回さなくてはならないという不便さがあります。 そこで今回、PRが発生したときに自動的にLighthouseの結果を生成してくれるLighthouse CIを導入することになりました。


## Lighthouseとは？

Lighthouseはウェブページの品質を測定し、改善するためのオープンソースツールです。ウェブサイトのパフォーマンス、アクセシビリティ、検索エンジン最適化（SEO）、ベストプラクティス、プログレッシブウェブアプリ（PWA）の基準を監査します。Lighthouseは、ウェブページのパフォーマンスと品質を向上させるためにできることについての洞察を提供するレポートを生成します。デフォルトでは、LighthouseはChrome DevToolsパネルで利用できます。

> Google Lighthouseは、Googleが開発したオープンソースツールで、ウェブページのパフォーマンス、アクセシビリティ、ベストプラクティス、SEO、PWAを測定するためにウェブページを監査します。 ウェブページのパフォーマンスと、その品質を改善するために何ができるのかについての洞察を提供するレポートを生成します。


![lighthouse-devtools.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/1e7ca9fb-4d57-026e-34eb-f4001021cbbe.png)


## Lighthouse CI

Lighthouse CIはLighthouseの結果をCLIで実行し、その結果をパイプラインに接続して保存し、保存された結果を比較できるようにするサービスです。
私たちはこのサービスをメインリポジトリに接続して、PRが生成されるたびにLighthouseの結果を生成、保存、比較し、結果を表示するサービスを構築する予定です。


![hybus-workflow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/1652f7d5-3ed7-7e12-696f-707cc56cc543.png)


## Lighthouse CIを設定する

Lighthouse CIはGitHub Actionsで構築する予定です。特別な環境を構築する必要なくCLIで実行することができるので簡単に構築することができます。

まず、Lighthouse設定ファイルを生成します。プロジェクトのルートフォルダに`lighthouserc.js`ファイルを生成して下記のように設定します。


```js
module.exports = {
  ci: {
    collect: {
      staticDistDir: './dist',
      url: 'http://localhost/index.html',
      numberOfRuns: 5,
    },
    upload: {
      target: 'temporary-public-storage',
      githubAppToken: process.env.LHCI_GITHUB_APP_TOKEN,
    },
  },
}
```


`staticDistDir` はビルドされたファイルが保存されるフォルダを指定します。私たちのプロジェクトはビルド時に `dist` フォルダに保存され、次のように設定しました。`upload` はLighthouseの結果を保存する場所を指定します。`temporary-public-storage` はGoogleが提供する一時的なストレージを使うというオプションです。

GitHub App TokenはGitHubでStatus Checkを表示するため必要なGitHub Appのトークンです。[ここ](https://github.com/GoogleChrome/lighthouse-ci/blob/main/docs/getting-started.md#github-app-method-recommended)を参考してアプリをインストールした後、アプリのインストール完了ページで出てくるトークンを使います。


もっと詳しい設定方法は[ここ](https://github.com/GoogleChrome/lighthouse-ci/blob/main/docs/configuration.md)で確認することができます。



次はGitHub Actionsでworkflowを設定します。`.github/workflows/lighthouse.yml` ファイルを生成して下記のように設定します。

```yml
name: Lighthouse CI
on: [pull_request]
jobs:
  lhci:
    name: Generate Lighthouse Report
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v3
      - name: NodeJS Setup
        uses: actions/setup-node@v3
        with:
            node-version: 16
      - name: Check dependencies & build
        run: |
          yarn install
          yarn build
      - name: Run Lighthouse CI
        id: step_lhci
        run: yarn dlx @lhci/cli autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
```


私たちのサービスはyarnパッケージマネージャを使ってるので `yarn` を使いました。 もし、npmを使ってるなら `npm` に変更すればいいです。 また、yarn v1.x を使ってるなら `yarn global add @lhci/cli` を使えばいいです。

これで基本的なCI構築は終わりました。PRを生成するたびにGoogleが提供する一時的なリポジトリに結果が保存され、一定期間その結果を確認することができます。


## Lighthouseサーバーを構築する

上で言及したようにこのまま構築を完了すると、Googleが提供する一時ストレージに結果が保存され、一定期間、その結果を確認することができます。しかし、私たちはこの結果データを私たちが持っていたかったし、過去の記録も有効期限なしで持っていたかったので、私たちが所有するLightHouse CIサーバーを構築してみました。ガイドは[ここ](https://github.com/GoogleChrome/lighthouse-ci/blob/main/docs/getting-started.md#the-lighthouse-ci-server)を参考にしました。

まず、Lighthouse CIサーバーを構築するためには、インターネットが接続されていて、Node v16以上がインストールされている必要があります。 また、SQLite、MySQL、PostgreSQLのいずれかのデータベースストレージが必要です。

バスハニャーンは無報酬の非営利団体なので、運営コスト削減のために有料サーバーを構築することはできるだけ控える必要があります。 そのため、私たちは無料でデータベースサーバーを作ることができる[Cloudtype](https://cloudtype.io/)を使用しました。


![cloudtype-postgresql.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/3858e57e-b940-fa42-811f-ee7dbd8b0a6a.png)


サーバーはnodeが動いてインターネットが繋がっていればどんなサービスでも構いません。 DBサーバーを別に分離したため、Static page提供サービスでも十分に構築が可能です。私たちはプラットフォームを統一するため、同じようにCloudtypeを使いました。

```js
const {createServer} = require('@lhci/server');

console.log('Starting server...');
createServer({
  port: 3000,
  storage: {
    storageMethod: 'sql',
    sqlDialect: 'postgres',
    sqlConnectionUrl: process.env.DATABASE_URL
  },
  basicAuth: {
    username: process.env.AUTH_USERNAME,
    password: process.env.AUTH_PASSWORD
  }
}).then(({port}) => console.log('LHCI listening on port', port));
```

上のように `server.js` ファイルを生成して配布します。ここで、`sqlConnectionUrl`にはデータベースのアドレスを入れる必要があります。 私たちはクラウドサービスを使ったので、`DATABASE_URL`という環境変数を別に設定しておきました。もし、他のサービスを使う場合は、そのサービスの環境変数を参考してください。

`basicAuth` にはユーザー認証のための情報が入ります。私たちはこのサービスを関係者のみ閲覧できるようにするためユーザー認証を追加しました。もし、外部にもCIサーバーを公開する場合は、このオプションを削除してください。同様にIDと非番号は環境変数で設定しました。

ドメイン接続後、サービスに接続すると、下記のようにユーザー認証を要求します。


![lighthouse-auth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/de5ea6c2-ec10-7ac9-0f1e-42510df6fc17.png)



ログインしたら次のような画面が表示されます。これでLighthouse CIサーバーの構築が完了しました。


![lighthouse-first-start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/41ba05ce-a7cd-fb52-0dbc-83b639dbfd32.png)


## GitHub ActionsとLighthouse CIサーバーを接続する方法

先ほど上でGitHub Actionsを使って構築したLighthouse CIは、PRを生成した後、自動でLighthouseの検査をした後、Googleの一時ストレージに結果が保存されるように設定しました。 今回は検査結果を先ほど構築した私たちのLighthouse CIサーバーに保存するように設定してみます。

先ほど生成した `lighthouserc.js` ファイルを下記のように修正します。

```js
module.exports = {
  ci: {
    collect: {
      staticDistDir: './dist',
      url: 'http://localhost/index.html',
      numberOfRuns: 5,
    },
    upload: {
      target: 'lhci',
      serverBaseUrl: 'https://lighthouse.hybus.app',
      token: process.env.LHCI_TOKEN,
      githubAppToken: process.env.LHCI_GITHUB_APP_TOKEN,
      basicAuth: {
        username: process.env.LHCI_USERNAME,
        password: process.env.LHCI_PASSWORD,
      },
    },
  },
}
```


`target`を変更することで、私たちが構築したLighthouse CIサーバーに保存するように設定しました。`serverBaseUrl` には私たちが構築したLighthouse CIサーバーのアドレスが入ります。

`token` はLighthouse CIサーバーへアクセスするためのトークンです。 このトークンはローカルで `lhci wizard` を使ってプロジェクトを追加しながら生成することができます。下記のように `lhci wizard` を実行します。


![lhci-wizard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/baf0806c-1aad-eedd-7664-0ce66c8b11a3.png)


`lhci wizard` を実行したら上のような画面が表示されます。上のトークン欄にはbuild tokenを入力します。

上で追加した環境変数をGitHub Actionsで使えるように実行環境に環境変数を追加します。下記のように`env`に環境変数を追加します。


```yml
name: Lighthouse CI
on: [pull_request]
jobs:
  lhci:
    name: Generate Lighthouse Report
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v3
      - name: NodeJS Setup
        uses: actions/setup-node@v3
        with:
            node-version: 16
      - name: Check dependencies & build
        run: |
          yarn install
          yarn build
      - name: Run Lighthouse CI
        id: step_lhci
        run: yarn dlx @lhci/cli autorun
        env:
          LHCI_TOKEN: ${{ secrets.LHCI_TOKEN }}
          LHCI_USERNAME: ${{ secrets.LHCI_USERNAME }}
          LHCI_PASSWORD: ${{ secrets.LHCI_PASSWORD }}
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
      - name: Post Link to Lighthouse Report
        uses: thollander/actions-comment-pull-request@v2
        with:
          comment_tag: lighthouse
          message: |
            Check out your Lighthouse Report: https://lighthouse.hybus.app/app/projects/hybus-genesis-production
          mode: recreate
```

さらに、Lighthouseの結果が生成されたら、生成された結果を確認できるようにLighthouseのリンクをPRにコメントで残す機能を追加しました。


## 結果

設定を終わったら、PRを開いたら、下記のようにLighthouse CIが自動で実行されることが確認できます。


![github-status-check.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/039ce73f-c8b5-62b0-d685-cfe7550bbbe6.png)


また、Lighthouse CIサーバーに接続して結果を確認することができます。


![lighthouse-ci-result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/da3c19e5-039f-4184-e26a-d36051ced981.png)


既存のChrome DevToolsで使ってたUIで確認したい場合は「jump straight to the Lighthouse report」をクリックします。このボタンをクリックすると、Googleが提供してるLighthouse結果ビューアーで結果を確認することができます。


![lighthouse-viewer-result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896189/a986f7ce-629c-3483-ce3b-be15a84d8821.png)


cf) 当時、Lighthouse CIサーバーでroot urlからアクセスしなかった時、Web UIが壊れる問題があります。このエラーについてGitHubに[Issue](https://github.com/GoogleChrome/lighthouse-ci/issues/893)を残しました。現在は解決済みです。