[Code Quality] Lighthouse CI

2023-10-17 hit count image

Google Chromeが提供するLighthouse機能をローカルやCI環境で実行する方法について説明し、CI環境でLighthouseを使ってウェブページの性能を自動で測る方法について説明します。

概要

GoogleChromeブラウザはLighthouseと言う機能を提供してます。この機能を通じてウェブアプリやウェブページの性能を測ることができます。

Lighthouse CI - Google Chrome Lighthouse

Lighthouseはウェブアプリまたはウェブページを分析し、ウェブサイトの性能やベストプラクティス(Best practices)を確認することができるように手伝うツールです。

今回のブログポストではローカルまたはCI環境でLighthouseを実行する方法について説明します。

Lighthouse CI

Lighthouse CICI(Continuous Integration)環境でLighthouseの実行や結果を確認できるようにしてくれるツールです。

Lighthouse CIをローカルまたはCI環境で実行するためにはNodeJS16バージョン以上の環境が必要です。

Lighthouse CIインストール

NodeJS環境の上で次のコマンドを実行してLighthouse CIをインストールします。

npm install --save-dev @lhci/cli

package.jsonファイルがない場合、次のコマンドを実行してグローバル環境にLighthouse CIをインストールします。

npm install -g @lhci/cli

Lighthouse CI設定

Lighthouse CIを使うためにはLighthouseを設定する必要があります。プロジェクトのルートフォルダに.lighthouserc.jsファイルを生成して次のように修正します。

module.exports = {
  ci: {
    assert: {
      preset: 'lighthouse:recommended',
    },
  },
};

このように設定するとLighthouseが提供するおすすめ設定をそのまま使えます。

ターゲット設定

次はLighthouseが検査するターゲットを設定する必要があります。ターゲットの対象はスタティックファイルまたはURLを設定することができます。

スタティックファイル

スタティックファイルは開発中のウェブサイトやウェブページのビルド結果を検査する方法です。スタティックファイルを検査するためにはLighthouseの設定ファイルである.lighthouserc.jsファイルを開いて下記のように修正します。

module.exports = {
  ci: {
    collect: {
      staticDistDir: '_site/',
    },
    assert: {
      preset: 'lighthouse:recommended',
    },
  },
};

私はJekyllを使ってブログを管理しています。Jekyllbundle exec jekyll buildと言うコマンドを使ってMarkdownで作成したブログポストをHTMLふぁいるでビルドすることができます。このようにビルドした結果ファイルは_siteと言うフォルダへ生成されます。

このように生成されたスタティックファイルのフォルダをcollectstaticDistDirオプションに設定することで、Lighthosueが検査する対象を設定することができます。

特定URL設定

スタティックファイルを生成することができない場合、検査対象になるページのURLを入力してLighthouseを実行することができます。特定URLを検査するためにはLighthouseの設定ファイルである.lighthouserc.jsファイルを開いて下記のように修正します。

module.exports = {
  ci: {
    collect: {
      url: [
        // Korean
        'https://deku.posstree.com/ko/flutter/',
        'https://deku.posstree.com/ko/react/',
        'https://deku.posstree.com/ko/react-native/',
        // English
        'https://deku.posstree.com/en/flutter/',
        'https://deku.posstree.com/en/react/',
        'https://deku.posstree.com/en/react-native/',
        // Japanese
        'https://deku.posstree.com/flutter/',
        'https://deku.posstree.com/react/',
        'https://deku.posstree.com/react-native/'
      ]
    },
    assert: {
      preset: 'lighthouse:recommended',
    },
  },
};

このように設定すると、Lighthouseは設定されたURLを検査します。

サブフォルダの問題

staticDistDirを使ってフォルダを指定しましたが、指定したフォルダのサブフォルダにあるファイルは検査しない問題が発生しました。私はこの問題を解決するためsitemap.xmlを使いました。

JavaScriptsitemap.xmlファイルを読むためにxml-jsライブラリを使いました。

そしたら、xml-jsライブラリをインストールするため、次のコマンドを実行します。

npm install --save-dev xml-js

そして、.lighthouserc.jsファイルを開いて下記のように修正します。

const fs = require('fs');
const convert = require('xml-js');

const SITEMAP_PATH = './_site/sitemap.xml';
const SITE_URL = 'https://deku.posstree.com';

const data = fs.readFileSync(SITEMAP_PATH);
const result = convert.xml2json(data, { compact: true, spaces: 4 });
const json = JSON.parse(result);
const url = json.urlset.url.map((item) => item.loc._text.replace(SITE_URL, ''));

module.exports = {
  ci: {
    collect: {
      staticDistDir: './_site/',
      url: url,
    },
    assert: {
      preset: 'lighthouse:recommended',
    },
  },
};

SITEMAP_PATHSITE_URLを自分のプロジェクトに合わせて修正して使ってください。このようにファイルを修正して実行するとsitemap.xmlに作成されたURLを読んでSITE_URLを使って要らないURLの文字を消して、当該URLをLighthouseのオプションに設定してLighthouseが検査できるようにしました。

このように.lighthouserc.jsファイルを修正してLighthouseを実行すると、sitemap.xmlに書いてある全てのページがうまく検査されることが確認できます。

Lighthouse実行

Lighthouseを使うための全ての設定が終わりました。次はLighthouseを実行するためpackage.jsonファイルを開いて下記のように実行スクリプトを追加します。

{
  "scripts": {
    "lighthouse": "lhci autorun"
  },
  "devDependencies": {
    "@lhci/cli": "^0.11.0"
  }
}

その後、次のコマンドを実行してLighthouseを実行します。

npm run lighthouse

package.jsonファイルがない場合、 Lighthouseコマンドを直接実行します。

lhci autorun
# npx lhci autorun

問題なく実行されたら.lighthouseciフォルダが生成されてLighthouseの結果が保存されることが確認できます。また、ターミナルでは次のようにLighthouseの結果が表示されることが確認できます。

...
  ✘  viewport failure for minScore assertion
       Does not have a `<meta name="viewport">` tag with `width` or `initial-scale`
       https://web.dev/viewport/

        expected: >=0.9
           found: 0
      all values: 0, 0, 0

このターミナル結果を見ながら問題を修正するか、.lighthouseciフォルダ中に生成された結果ファイル(.html)をブラウザで開いて問題を確認して修正することができます。

CI環境で実行

このように設定したLighthosueCI環境で実行して性能を測ることができます。

GitHub Actions

GitHub ActionsLighthouseを実行する方法について説明します。GitHub Actionsを使ってLighthouseを実行するためには.github/workflows/ci.ymlファイルを生成して次のように修正します。

name: CI
on: [push]
jobs:
  lighthouseci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16
      - run: npm install
      - run: npm run lighthouse

package.jsonファイルがない場合npm install部分とnpm run lighthouse部分を次のように修正します。

- run: npm install -g @lhci/cli
- run: lhci autorun

もし、スタティックファイルを検査するようにLighthouseを設定した場合、npm run lighthouseまたはlhci autorunコマンドを実行する前に必ずスタティックファイルを生成するコマンドを追加してください。

GitLab CI

GitLab CILighthosueを実行するためには.gitlab-ci.ymlファイルを作って次のように修正します。

lighthouse:
  image: node:16-slim
  script:
    - apt-get update
    - apt-get install -y libgtk-3.0 libgbm-dev libnss3 libatk-bridge2.0-0 libasound2
    - npm install --global npm@latest
    - npm install
    - npm run lighthouse
  only:
    refs:
      - merge_requests

package.jsonファイルがない場合npm install部分とnpm run lighthouse部分を次のように修正します。

- npm install -g @lhci/cli
- lhci autorun

もし、ステティックファイルを検査するようにLighthouseを設定した場合、npm run lighthouseまたはlhci autorunコマンドを実行する前に必ずステティックファイルを生成するコマンドを追加してください。

Basic authentication

Lighthouseを使ってURLでWebページを検査するように設定した場合、Basic authenticationが設定されたWebページを検査する場合があります。

Lighthouseを使ってBasic authenticationが設定されたウェブページを検査するためにはいくつか設定を追加する必要があります。まず、次のコマンドを使ってpuppeteerをインストールします。

npm install --save-dev puppeteer

その後、プロジェクトのルートフォルダにpuppeteerScript.jsファイルを生成して次のように修正します。

const BASIC_AUTH_USER_NAME = process.env.BASIC_AUTH_USER_NAME;
const BASIC_AUTH_PASSWORD = process.env.BASIC_AUTH_PASSWORD;

async function main(browser, { url }) {
  const page = await browser.newPage();
  await page.authenticate({
    username: BASIC_AUTH_USER_NAME,
    password: BASIC_AUTH_PASSWORD,
  });
  await page.goto(url);
}

module.exports = main;

環境変数のBASIC_AUTH_USER_NAMEBASIC_AUTH_PASSWORDBasic authenticationのIDとパスワードを保存します。その後、.lighthouserc.jsファイルを開いて下記のようにpuppeteerを設定します。

module.exports = {
  ci: {
    collect: {
      url: [
        // Korean
        'https://deku.posstree.com/ko/flutter/',
        'https://deku.posstree.com/ko/react/',
        'https://deku.posstree.com/ko/react-native/',
        // English
        'https://deku.posstree.com/en/flutter/',
        'https://deku.posstree.com/en/react/',
        'https://deku.posstree.com/en/react-native/',
        // Japanese
        'https://deku.posstree.com/flutter/',
        'https://deku.posstree.com/react/',
        'https://deku.posstree.com/react-native/'
      ]
    },
    puppeteerScript: './puppeteerScript.js',
    puppeteerLaunchOptions: {
      defaultViewport: null,
      args: ['--no-sandbox'],
      headless: true,
    },
    assert: {
      preset: 'lighthouse:recommended',
    },
  },
};

このように修正した後、Lighthouseを実行すると問題なくBasic authenticationが設定されたウェブページがうまく検査できることが確認できます。

完了

これでLighthouse CIを使ってローカルやCI環境でLighthouseを実行する方法についてみてみました。早いウェブページまたはウェブアプリはユーザの経験(UX)に大きな影響を与します。また、Lighthouseで測れる項目はSEOにも大きな影響を与えるので、皆さんもLighthouseを使って開発してるウェブページやウェブアプリの性能を改善してみてください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts