🌟

Web Speed Hackathon 2022 を勝手に開催する

2022/08/18に公開

CyberAgentのWeb Speed Hackathon 2022 の仕組みが素晴しいと思ったので(特にGitHub Actionsで自動化されたLeaderboardの部分)、自分の環境で遊ぶための方法を書きます。

https://github.com/CyberAgentHack/web-speed-hackathon-2022

Web Speed Hackathonとは

たぶんフロントエンド版のISUCONのようなイベントです。

参加者は自分でHeroku等にデプロイしたURLを記載したGitHub Issueを投稿し、BOTが返すGoogle Lighthouseの結果を元に算出されたスコアを競います。

ウェブアプリケーションを遅くするための逆プラクティスがあてられているのはISUCONと同様で。
無料で使えるHerokuにデプロイできるかつ(インフラやバックエンド実装で工夫することも可能ですが)基本的にフロントエンドエンジニアのスキルの範囲内でスコアがアップするような設問になっているのが良いと思いました。

Leaderboardの仕組み

https://github.com/CyberAgentHack/web-speed-hackathon-2022-leaderboard

  1. GitHub Issuesに申請が来たらRequestを実行
  2. Scoringに処理を引き継ぎ、画面差分チェック(VRT)とスコアリングを実行
  3. 結果をIssueにコメントする
  4. Leaderboardが自動で更新される

セットアップ

まず CyberAgentHack/web-speed-hackathon-2022-leaderboard をforkします。

そのままだと、開催期間外になっていてスコアラーが動作しないのでコメントアウトしてしまいます。

--- a/.github/workflows/scoring.yml
+++ b/.github/workflows/scoring.yml
@@ -39,15 +39,7 @@ jobs:
         with:
           result-encoding: string
           script: |
-            const payload = require('/tmp/payload.json');
-
-            const startAt = new Date('2022-08-04T18:00:00.000+09:00');
-            const endAt = new Date('2022-08-05T20:00:00.000+09:00');
-            const requestedAt = new Date(payload.request_time);
-
-            if (requestedAt < startAt || endAt < requestedAt) {
-              return 'closed';
-            }
+            // force oneced for debugging
             return 'opened';
   vrt:
     runs-on: ubuntu-20.04

https://github.com/laiso/web-speed-hackathon-2022-leaderboard/commit/fcacaadd393f343909de1bfedac143d1efd6b286

計測URLの指定

Lighthouseスコアを出すpathの一覧をWSH_SCORING_TARGET_PATHSという値をActionで読み込めるように/settings/secrets/actions からsecretをセットします。

["/2022-08-03","/races/00554e5d-24bb-4839-a9b0-9295c6026ff8/race-card","/races/7c6f9e84-c59d-4210-87c2-151e866cee43/odds","/races/4ec52cb6-9e1d-4f2b-8efe-4c267c6ce4da/odds","/races/931e5cdc-43b8-4545-9479-a10881334331/result"]

これは既存の実行結果のActionから取得してきました。

アプリケーションの修正

https://github.com/CyberAgentHack/web-speed-hackathon-2022

上記リポジトリのソースコードを取得して自分でHerokuにデプロイします。

スコア算出

自分でforkした web-speed-hackathon-2022-leaderboard リポジトリのIssueを作成するとフォーム形式になっており、前述の自分でデプロイしたURLを入力できます。

Issueを作成するとGitHub Actionsが実行されスコアリングが成功するとコメントが付きます。

あとはこのスコアを改善するという流れになります。

Tips: VRTをローカルで実行

画面差分チェック(VRT)をGitHub Actions上で毎回実行すると時間がかかるのでローカルで走らせればフィードバックループが早まるのではないかと考えました。

VRTの仕組みはpuppeteerで画面をキャプチャしてreg-cliでdiffというものです。なのでローカルで開発しているアプリケーションに

yarn vrt:capture --url http://localhost:3000/ && yarn vrt:detect

とすればこのチェックを動かすことができます。

環境差異への対応

ただGitHub ActionsのLinux環境で取得されたスクリーンショットと自分のmacOSのローカル環境で取得した画像では何も変更しないでも差分がありました。

システムのフォントやレンダリングのAPIの差異があるので差分がでるのはしかたがないので、これを修正するためにmacOS側で正のデータを一度撮って、逆に期待値側のファイルへ上書きすることにしました。

yarn vrt:capture --url http://localhost:3000/ 
cp -a scripts/vrt/tmp/actual scripts/vrt/expected

デメリットとしてはGitHub Actionsでのみ失敗することに気付けなさそうですが、実験している限り今のところ発生してないです。

実行時間の短縮

ページごとのキャプチャを待たずに呼び出して完了時間を短縮する。

--- a/scripts/vrt/src/index.ts
+++ b/scripts/vrt/src/index.ts
@@ -35,7 +35,7 @@ async function main() {
   await fs.ensureDir(exportPath);
 
   for (const viewport of viewportList) {
-    for (const page of pageList) {
+    pageList.forEach(async (page) => {
       const url = new URL(page.path, baseUrl).href;
       const buffer = await captureScreenshot({
         url,

https://github.com/laiso/web-speed-hackathon-2022-leaderboard/commit/1468228ed1253b975399388421734dc6d22cfab0

puppeteerプロセスの呼び出しスパンが短かくなっているからなのか、動作時のメモリ使用量が増加しました。

Discussion