やりたいこと
Pull Requestを出した時にVercelが自動生成するプレビューサイトのパフォーマンスを、lighthouseで自動計測すること
技術スタック
- Vercel
- GitHubActions
元コードの実装の流れ
基本的には以下の記事を参考にしつつ、一部修正する部分を紹介します。
まずは元のコードがどのように実装されているかをポイントごとに見ていきます。
コードを読めば理解できるという方は以下のリンクからご覧になってください。
読んでみて特に疑問点などなければこのパートはスキップしていただいて問題ありません。
完成したコードも下に掲載していますのでお急ぎの方はそちらをご覧ください。
ステップ1:トリガー
on:
issue_comment:
types: [edited]
まずこのワークフローが実行される時はPull Requestのコメントが編集された時です。
その理由は、Vercelのプレビュー生成のフローを見てみるとわかりやすいです。
-
コメントがつく
Pull Requestを出した際にまず最初にVercelがコメントをつけます。
ここからプレビューのビルドが開始されるというわけですね。
-
ビルドが完了する
ビルドが終わり次第先ほどのコメントが編集されて以下のようになります。
こうして完全なプレビューが見れるようになるというのが一連の流れです。
このようにPreviewが生成されるのですが、私たちがパフォーマンスを確認したいのはビルドが完了して完全な状態になった後のPreviewなので、Pull Requestを出し始めた瞬間に計測しにいっても意味がないわけです。
そのためビルドが完了し、Previewが完全な状態となった瞬間である、「Pull Requestのコメントが編集された時」にトリガーされる設定となっています。
ですが逆にコメントが編集された時ならいつでもトリガーされるのでその点には注意が必要です(コメントした人が誰かで条件分岐するなどの対策はありますが)
このトリガーはデフォルトブランチにコードが存在している時にしかトリガーされません。
作業ブランチから動作確認することができないので、毎回デフォルトブランチにマージして動作確認するようにしてください。
ステップ2:プレビューURLの取得
- name: Capture Vercel preview URL
id: vercel_preview_url
uses: aaron-binary/vercel-preview-url-action@v0.0.3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
次に重要となるのはプレビューURLの取得です。
方法は至ってシンプルで、先ほど登場したVercelの自動コメントを読み取ってリンクを抽出するというものです。
これに関しては1行書くだけで中身を意識する必要はありません。
ステップ3:lighthouseによるパフォーマンス計測
- name: Audit preview URL with Lighthouse
id: lighthouse_audit
uses: treosh/lighthouse-ci-action@v3
with:
urls: |
${{ steps.vercel_preview_url.outputs.vercel_preview_url }}
uploadArtifacts: true
temporaryPublicStorage: true
プレビューURLが取得できたら、そのURLを使っていよいよパフォーマンスの計測を行なっていきます。
これもライブラリにURLを渡すだけなので特筆することはありません。
残りのステップは文字の整形などなので割愛します。
修正箇所
以上が元コードの説明なのですが、現在(少なくとも僕の環境では)このコードは動作しません。
ここからは、そんな元コードを何点か修正して動作するようにしていきます。
使用するライブラリの修正
これは動作するために必須かと言われると微妙なんですが、ライブラリの修正を行います。
具体的には以下の通りです。
vercel-preview-url-actionに関してはライブラリそのものが変更されていることに注意してください。スター数やメンテナンスの頻度的にこちらが良いと判断しました。
バージョンは執筆当時のものですので適宜バージョンを変更してください
修正前 | 修正後 |
---|---|
actions/checkout@v2 | actions/checkout@v3 |
aaron-binary/vercel-preview-url-action@v0.0.3 | aaimio/vercel-preview-url-action@v2.2.0 |
marocchino/sticky-pull-request-comment@v1 | marocchino/sticky-pull-request-comment@v2 |
treosh/lighthouse-ci-action@v3 | treosh/lighthouse-ci-action@v10 |
secrets.GITHUB_TOKEN
の修正
コードの中でsecrets.GITHUB_TOKEN
という、GitHub APIにアクセスする際に必要なトークンを使用する箇所が何箇所かあるんですが、僕の場合これを変える必要がありました。
というのも、どうやらsecrets.GITHUB_TOKEN
では書き込み権限が付与されていないことがあるそうです。
つまり、URLの取得などのREADに関してはsecrets.GITHUB_TOKEN
で行えるが、コメントの追加などは行うことができないということです。
ということで、コメントの追加を行なっている箇所とスコアの整形を行なっている箇所の修正を行います。
まずは書き込み権限を持つトークンを発行しましょう。
- GitHubにアクセスし、Settings > Developer Settingsと進む
- サイドバーに表示されているPersonal access tokensを選択
- Tokens(classic)を選択し、Generate new token > Generate new token(classic)を押す
- Noteの欄に見分けが付く文言を入力(リポジトリ名とかが良いと思います)し、workflowにチェックを入れ、Generate tokenを押す
- リダイレクト後にトークンが表示されるのでコピー
ここまでできたらコピーしたトークンをリポジトリで使えるようにするために登録しましょう。
- リポジトリのSettingsからSecurity > Secrets and variables > Actionsと進む
- New repository secretを押す
- シークレット名(今回の場合は
SECRET_TOKEN
)と先ほどコピーしたトークンを入力しAdd secret
これで準備は完了したので、secrets.GITHUB_TOKEN
をsecrets.SECRET_TOKEN
に修正すれば完了です!
Vercelのリダイレクトによるスコアの低下を解消
バージョンを上げてトークンを登録すれば一旦動くようにはなると思うんですが、やけにスコアが低く表示される気がしました。
そこでlighthouseの結果をみるとこんな表示が,,,
どうやらプレビューURLは別のURLへとリダイレクトされて表示されているようです。
実際に確認してみると元URLが
https:// vercel.live/open-feedback/[リポジトリ名]-git-[ブランチ名]-[ユーザー名].vercel.app?via=pr-comment-visit-preview-link&passThrough=1
なのに対し、プレビューURLは
https://[リポジトリ名]-git-[ブランチ名]-[ユーザー名].vercel.app/
と表示されていました。
ということでlighthouseで計測するURLをリダイレクト後のものに修正します。
方法は至って簡単で、「元URLにアクセスして、リダイレクトで最終的にたどり着いたURLを取得する」と言った方法です。
下のコードを「Capture Vercel preview URL」と、「Audit preview URL with Lighthouse」の間のステップに追加してください。
- name: Capture Redirected URL
id: get_redirected_url
run: |
PREVIEW_URL="${{ steps.capture_preview_url.outputs.vercel_preview_url }}"
REDIRECTED_URL=$(curl -Ls -o /dev/null -w %{url_effective} "$PREVIEW_URL")
echo "REDIRECTED_URL=$REDIRECTED_URL" >> "$GITHUB_OUTPUT"
加えて、リダイレクト後のURLで計測するように「Audit preview URL with Lighthouse」のコードを以下の様に修正してください
- name: Audit preview URL with Lighthouse
id: lighthouse_audit
uses: treosh/lighthouse-ci-action@v10
# 環境変数からリダイレクト後のURLを取得する
env:
REDIRECTED_URL: ${{ steps.get_redirected_url.outputs.REDIRECTED_URL }}
with:
urls: |
# リダイレクト後のURLを使う
$REDIRECTED_URL
uploadArtifacts: true
temporaryPublicStorage: true
以上のことをすればリダイレクト先のURLで計測してくれるようになっているはずです。
実装のステップ
かなり断片的に紹介してしまったので改めて全体的な実装の流れです。
- .github/workflowsディレクトリにymlファイルを追加(今回であればcheck-lighthouse-score.ymlなど)
- そのymlファイルに今までのコードを格納
- デフォルトブランチにそのコードをマージ
- 適当にPull Requestを出してみて、計測がなされることを確認
課題点
最後に、現状できていない課題点です。
- SSGに弱い
- 現状プレビューのURLが毎回異なるので、キャッシュを用いるサイトだとどうしてもパフォーマンスが低く出てしまいます。
- できればURLを固定できたら良いなと考えています
- モバイルでしか計測できない
- lighthouseのデフォルト設定がモバイルなのか、現状だとモバイルの設定で計測しています
- できれば両方もしくは切り替えができるようにして計測したいと考えています。
- 誰のコメントでもトリガーされてしまう
- 本来ユーザーで条件分岐するのがベストなんですが、現状だと全てのコメントに対してトリガーされているのでそれを修正したいです。
完成コード
先ほどあげた修正点以外にも日本語化をしたり多少のマイナーチェンジをしています。
このコードをコピペしてもらえれば一旦動くと思われます。
name: PRのLighthouseスコアチェック
on:
issue_comment:
types: [edited]
jobs:
lighthouse:
runs-on: ubuntu-latest
name: Lighthouse分析と結果コメント投稿
steps:
- name: チェックアウト
uses: actions/checkout@v3
- name: プレビューURLを取得
id: capture_preview_url
uses: aaimio/vercel-preview-url-action@v2.2.0
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: リダイレクト後のURLを取得
id: get_redirected_url
run: |
PREVIEW_URL="${{ steps.capture_preview_url.outputs.vercel_preview_url }}"
REDIRECTED_URL=$(curl -Ls -o /dev/null -w %{url_effective} "$PREVIEW_URL")
echo "REDIRECTED_URL=$REDIRECTED_URL" >> "$GITHUB_OUTPUT"
- name: コメントを追加
id: loading_comment_to_pr
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.SECRET_TOKEN }}
number: ${{ github.event.issue.number }}
header: lighthouse
message: |
Lighthouseで分析中...
- name: Lighthouseでページを分析
id: lighthouse_audit
uses: treosh/lighthouse-ci-action@v10
env:
REDIRECTED_URL: ${{ steps.get_redirected_url.outputs.REDIRECTED_URL }}
with:
urls: |
$REDIRECTED_URL
uploadArtifacts: true
temporaryPublicStorage: true
- name: スコアを整形する
id: format_lighthouse_score
uses: actions/github-script@v3
with:
github-token: ${{secrets.SECRET_TOKEN}}
script: |
const result = ${{ steps.lighthouse_audit.outputs.manifest }}[0].summary
const links = ${{ steps.lighthouse_audit.outputs.links }}
const formatResult = (res) => Math.round((res * 100))
Object.keys(result).forEach(key => result[key] = formatResult(result[key]))
const score = res => res >= 90 ? '🟢' : res >= 50 ? '🟠' : '🔴'
const comment = [
`[Lighthouse分析結果](${Object.values(links)[0]}):`,
'| 項目 | スコア |',
'| --- | --- |',
`| ${score(result.performance)} パフォーマンス | ${result.performance} |`,
`| ${score(result.accessibility)} アクセシビリティ | ${result.accessibility} |`,
`| ${score(result['best-practices'])} ベストプラクティス | ${result['best-practices']} |`,
`| ${score(result.seo)} SEO | ${result.seo} |`,
`| ${score(result.pwa)} PWA | ${result.pwa} |`,
' ',
`*分析したURL: [${Object.keys(links)[0]}](${Object.keys(links)[0]})*`
].join('\n')
core.setOutput("comment", comment);
- name: Lighthouse結果をコメント
id: comment_to_pr
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.SECRET_TOKEN }}
number: ${{ github.event.issue.number }}
header: lighthouse
message: |
${{ steps.format_lighthouse_score.outputs.comment }}