Lighthouse CIをGitHub Actionsで実行してみた

2025.09.19 09:00
2025.09.29 10:13
Lighthouse CIをGitHub Actionsで実行してみた

最近、手元で Lighthouse(LHCI)を回すのに慣れてきたので、GitHub Actionsで自動実行にしてみました。pushのたびに速度やアクセシビリティが落ちてないか分かるのが最高。メモ残します。

やること

  • PRや定期バッチで Lighthouse を自動計測
  • HTMLレポートは Actions の Artifacts に保存(ダウンロード可)
  • Run の Summary に スコア一覧(Perf/Acc/SEO) を自動出力

1. lighthouserc.json を置く

ルートに保存。URLは自分のサイトに置き換えてください。

{
  "ci": {
    "collect": {
      "url": [
        "https://example.com/",
        "https://example.com/about/"
      ],
      "numberOfRuns": 3,
      "settings": { "preset": "desktop" }
    },
    "assert": {
      "assertions": {
        "categories:performance": ["warn", { "minScore": 0.8 }],
        "categories:accessibility": ["warn", { "minScore": 0.9 }],
        "categories:seo": ["warn", { "minScore": 0.9 }]
      }
    },
    "upload": { "target": "filesystem", "outputDir": "lhci_reports" }
  }
}

2. GitHub Actions用のYAMLを作成する

name: Lighthouse CI

on:
  workflow_dispatch:         # 手動実行
  pull_request:              # PRで自動実行(任意)
    types: [opened, synchronize, reopened, ready_for_review]
    branches: [main]
  schedule:
    - cron: '0 0 * * 1'      # 毎週月曜 09:00 JST 相当

jobs:
  lhci:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with: { node-version: '20' }

      # ロックファイルがあるなら npm ci、無いなら npx直実行が楽
      - name: Install (with lockfile)
        run: |
          if [ -f package-lock.json ]; then
            npm ci
          else
            echo "No package-lock.json; skip npm ci"
          fi

      - name: Run LHCI
        run: |
          if command -v lhci >/dev/null 2>&1; then
            lhci autorun
          else
            npx @lhci/cli@0.13.0 autorun
          fi

      # Runサマリにスコア一覧を出す(ダウンロード前に俯瞰)
      - name: Summarize Lighthouse scores
        if: always()
        run: |
          echo "### Lighthouse Summary" >> $GITHUB_STEP_SUMMARY
          if ls lhci_reports/*.report.json >/dev/null 2>&1; then
            for f in lhci_reports/*.report.json; do
              url=$(jq -r '.requestedUrl' "$f")
              perf=$(jq -r '.categories.performance.score // "N/A"' "$f")
              acc=$(jq -r '.categories.accessibility.score // "N/A"' "$f")
              seo=$(jq -r '.categories.seo.score // "N/A"' "$f")
              printf -- "- %s: Perf %s / Acc %s / SEO %s\n" "$url" "$perf" "$acc" "$seo" >> $GITHUB_STEP_SUMMARY
            done
          else
            echo "- No report JSON files found in lhci_reports" >> $GITHUB_STEP_SUMMARY
          fi

      # HTML/JSONレポートをArtifactsへ
      - name: Upload reports (artifact)
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: lhci-reports-${{ github.run_number }}
          path: lhci_reports
          retention-days: 30

3. 結果を活用する

GitHubActionsでは「Artifact」というファイルを保存できる機能があります。今回はそこに出力されたレポートを保存して、ダウンロードできるようにしています。

job画面の赤線の部分のURLをクリックすると今回のレポートがダウンロードできます。
すごく便利ですね!!

その他に、summaryページでも見られるようにしてみました。

4. デスクトップとモバイルを両方出す

上記はデスクトップタイプのレポートだけでしたが、モバイルを出すこともできるみたいです。
両方出す場合はこんな感じです。

name: Lighthouse CI

on:
  workflow_dispatch:         # 手動実行
  pull_request:              # PRで自動実行(不要なら消してください)
    types: [opened, synchronize, reopened, ready_for_review]
    branches: [main]
  schedule:                  # 定期実行(不要なら消してください)
    - cron: '0 0 * * 1'      # 毎週月曜 09:00 JST 相当

jobs:
  lhci:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        preset: [desktop, mobile]  # 並列で2種類計測

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with: { node-version: '20' }

      # ロックファイルがあるときだけ npm ci(無ければスキップして npx 実行)
      - name: Install (with lockfile)
        run: |
          if [ -f package-lock.json ]; then
            npm ci
          else
            echo "No package-lock.json; skip npm ci"
          fi

      - name: Run LHCI
        run: |
          if command -v lhci >/dev/null 2>&1; then
            lhci autorun
          else
            npx @lhci/cli@0.13.0 autorun
          fi
        env:
          # lighthouserc.json の collect.settings.preset を上書き
          LHCI_COLLECT_SETTINGS__PRESET: ${{ matrix.preset }}

      # Runサマリにスコア一覧を出力
      - name: Summarize Lighthouse scores
        if: always()
        run: |
          echo "### Lighthouse Summary (${{ matrix.preset }})" >> $GITHUB_STEP_SUMMARY
          if ls lhci_reports/*.report.json >/dev/null 2>&1; then
            for f in lhci_reports/*.report.json; do
              url=$(jq -r '.requestedUrl' "$f")
              perf=$(jq -r '.categories.performance.score // "N/A"' "$f")
              acc=$(jq -r '.categories.accessibility.score // "N/A"' "$f")
              seo=$(jq -r '.categories.seo.score // "N/A"' "$f")
              printf -- "- %s: Perf %s / Acc %s / SEO %s\n" "$url" "$perf" "$acc" "$seo" >> $GITHUB_STEP_SUMMARY
            done
          else
            echo "- No report JSON files found in lhci_reports" >> $GITHUB_STEP_SUMMARY
          fi

      # HTML/JSONレポートをArtifactsへ(preset別に保存)
      - name: Upload reports (artifact)
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: lhci-reports-${{ matrix.preset }}-${{ github.run_number }}
          path: lhci_reports
          retention-days: 30

presetに「desktop」と「 mobile」を2つ指定するんですね。

5. しきい値の運用

解析した値によって挙動を変えることもできるみたいです。たとえば「warn」にすれば警告メッセージがでるだけだけど「error」にすればCIのジョブ自体が落ちるようにもできると。

"assert": {
  "assertions": {
    "categories:performance": ["error", { "minScore": 0.85 }],
    "categories:accessibility": ["warn", { "minScore": 0.9 }],
    "categories:seo": ["warn", { "minScore": 0.9 }]
  }
}

これならジョブが落ちるのでサイトの異常がすぐにわかりますね。

まとめ

GitHubActionsっていろんなことができるんですね、、!

まずは warn運用 → 慣れたら errorでブロック に段階的にするのがよさそう。
さらにArtifacts と Summary をセットにすると、確認が楽ですね。

LighthouseはCIで自動化してこそ真価を発揮しそうですね。

今回は以上です!