参加者や運営のコンテキスわかってる人向けの雑な版。 真面目なのは後で書く、かも。気分次第
https://www.cyberagent.co.jp/careers/students/career_event/detail/id=31182
https://github.com/CyberAgentHack/web-speed-hackathon-2025
真面目な解説書いた
https://zenn.dev/mizchi/scraps/6407ec626b9673
365/1200点で暫定12位だったが、最後のレギュレーションチェックで落ちた。
12: mizchi サイドバーの各ボタン(リンク)にアイコンが表示されていない
というかスコア300を超えた上位20人のうち、レギュレーションにパスしたのか一人で、そのまま優勝という結果。
fetch
を上書きして雑にAPIのメトリクスをとる- DevTools の Performance でCPUブロッキングを監視
- 重すぎるので、CPU/Networkをスロットリングする Lighthouse は出番なかった
- 初日は思いつきで壊してもいいから色々試す
- 二日目はまずVRT環境を通して、VRTが通る範囲で初日に作ったパッチを段階的に当てていった
SSR化時に hydration 前のログインボタンを押してしまいVRTが落ちる。のに気づくのに二日目の半分を使ってしまった。
disabled={!mounted}
なコードを入れて解決したが、デバッグが大変だった。
二日目は手元でVRTを通ることを確認し続けたが、途中でアイコンフォントが落ちたのが pixeldiff 上は 3% に収まってしまい、検知されなかった。
そもそも運営側が Macbook 想定なのか、 playwright の Snapshot がない状態から始まった。Windows 環境でスナップショットを自前で作るところからはじめた。
# 開発環境のWSLとは別にWindows上で環境構築をする
# git clone
$ pnpm install
$ cd workspaces/test
$ pnpm playwright test
Running 12 tests using 8 workers
✓ 1 …src\auth.test.ts:12:7 › 認証 › 新規会員登録 -> ログアウト -> ログイン (21.9s) ✓ 2 [Desktop Chrome] › src\full-page.test.ts:125:9 › 全画面 › トップページ (31.2s)
✓ 3 …sktop Chrome] › src\full-page.test.ts:125:9 › 全画面 › シリーズページ (21.9s)
✓ 4 …test.ts:125:9 › 全画面 › エピソードページ (プレミアム - 無料ユーザー) (22.2s)
✓ 5 …rome] › src\full-page.test.ts:125:9 › 全画面 › エピソードページ (無料) (1.6m)
✓ 6 …ts:125:9 › 全画面 › エピソードページ (プレミアム - プレミアムユーザー) (1.7m)
✓ 7 …Chrome] › src\full-page.test.ts:125:9 › 全画面 › プログラム(放送中) (31.1s)
✓ 8 …Chrome] › src\full-page.test.ts:125:9 › 全画面 › プログラム(放送前) (23.4s)
✓ 9 …Chrome] › src\full-page.test.ts:125:9 › 全画面 › プログラム(放送後) (18.3s)
✓ 10 [Desktop Chrome] › src\full-page.test.ts:125:9 › 全画面 › 番組表 (2.9m)
✓ 11 [Desktop Chrome] › src\full-page.test.ts:125:9 › 全画面 › 404 (7.0s)
✓ 12 …t.ts:13:7 › サービストップ › サイドバーにロゴ画像が表示されていること (4.1s)
Slow test file: [Desktop Chrome] › src\auth.test.ts (21.9s)
Consider running tests from slow files in parallel, see https://playwright.dev/docs/test-parallel.
12 passed (3.3m)
(-linux
のスナップショットがあるとよかった。Dockerならlinuxのスナップショットをテストできるが、さすがに -darwin
は作れない)
一度走らせれば workspaces/test/src/*.snapshots
以下にその環境のスナップショットが生成される。
目視でスナップショットを確認して、以降そのスナップショットが通ることを前提に進めたが、正直ここの環境差による不安は拭えなかった。フォントは NotoSans JP だが、ホスト環境のレンダラーの差が大きく感じる。
全画面 › 番組表 (2.9m)
がとにかく重い。WSL(Ubuntu)だと耐えられないので、Windowsホストで playwright のランナーだけセットアップした。
実際の開発サーバーは WSL Ubuntu で localhost:8000 を立てて、ホストの playwright 接続した。
- 意図的な遅延処理を取り除く
- 初手で webpack => rspack 化(swc化と合わせて手元のビルド速度が5倍に)
- ついでに Chunk 化
- ffmpeg-wasm をオフロード
- ffmpegで事前にサムネを作っておくのが想定解とのことだが、この複雑度でそこを追跡するのは無理
- Drizzle にインデックスを張る (LCP 3500=>1300)
- React Router を SSR に移行 (CLS 0点=>25点)
- unocss から CSS を静的に抽出 (同上)
- 結果的にはここでミスってアイコンが落ちた
- aspect-ratio を監視する系の処理を
:hover
やmousemove
/mouseleave
で書き直した - hls.js / video.js / shaka playwer を分離 (TBT 満点)
- JS読み込みでCPUブロッキングを起こしていた
- 結果的には Chrome で動けばいいので、どれか一つでよかったらしい
- svgの中にbase64でフォントがインライン化されたsvgフォントが混ざってるので、スクショで置き換え
- まじめにfonttoolでサブセットフォントをやろうとしたが間に合わなかった
- 動画周りを stream 化して回る
たぶん、SSR化して CLS から高速化する路線と、 静的 SPA でデータを API経由にしてLCPから高める路線がある。
自分はSSRからいったのでトップ画面で CLS/TBT が満点になったが、FCP/LCP がなかなか点が上がらなかった。
- SSR hydration data が 3.2MB あり、転送量と JSON.parse でブロッキング
- サブセットフォントをスクショじゃなく普通に作りたかった
- react-ellipsis-component に問題があるのはわかっていたが、 VRT をパスする精度で書き直すのは、短期間では無理。
- drizzle の最適化が甘かった(3500ms=>400~1300msまでは縮めたが、合計400msぐらいまでは縮むらしい)
- 認証の ReDOS は気付けなかった。サーバーのプロファイルも見ればよかった
- クライアントサイドで drizzle-schema (zod) を参照したり、 typebox がランタイムで悪さしてることは気付いたが、追う時間がなかった
- 動画周りは全然わからん。非標準の独自実装のエンコーダが多くて辛そう。
とにかく使うライブラリの量が膨大で、事前に抑えるのは無理なのでその場で調査する能力を問われたのが面白かった。
初手 rspack でビルドは速くなったのだが、以降 rspack について調べないと先に進めない呪いにかかった。
vite 化するとそれだけで時間掛かっておそらく期間中に間に合わなくなるので、webpack の互換性が高いrspack にいったのは間違いではなかった、と思う。
- お疲れ様でした。サーバー、クライアント、静的解析、全部込みで面白かったです。
- とにかく作問と納得いくテスト手法が大変(E2E)で、大変だったと思います
- 静的解析でいける範囲はともかく、アプリケーション層の書き換えコストの見積もりが低すぎる気がしました。
- VRT や workspaces/test の通し方の周知が足りない気がしました。最終的に19/20がレギュレーション落ちたので...