CA主催のスピードハッカソン に参加してきた話
本日、2021年2月6日から2日に渡って開催された、サイバーエージェント主催の スピードハッカソン に参加しました。そろそろパフォーマンス改善得意になりたい!って気持ちで臨みました。
尚、開発時にメモしていたことを簡潔に書くので、チューニングの詳細を知りたい部分があったらカーーズへのリプやコメントをください。
スピードハッカソンとは
既存の架空SNSのパフォーマンス改善を行うハッカソンで、順位決定のスコア測定にはLightHouseが使用されています。利用されていたメインな技術を載せておきます。
ハッカソンのルール
①複数ページのパフォーマンスを上げる
②Chrome最新版での動作確認を行う
③見た目を変更することはNG
④挙動を変更することはNG
⑤サーバーは自分で用意する(サーバーサイドについてもチューニングできる)
参加する前に
実は今回はやろうとしていたことが2つありました。
明日のCAスピードハッカソン では2つの「やってみたかったけど、今まで出来ていなかったこと」をする。失敗したら惨敗だし、成功したら結構良い結果になるかも。どんな問題か分からないから挑戦すらできないかもしれない内容だけど、楽しみ。
— かーーず🏎️ (@kaa_a_zu) 2021年2月5日
1つ目は、NextJS(SSG) × Vervel(主にエッジCDN目的)です。最近業務でこのような構成を触っているのですが、実際に自分で作ったものではないので、パフォーマンスにこだわりながら構成をしたいなというモチベーションがありました。
2つ目は、WASMの利用です。最近Rustに少しだけはまっていて、WASMを用いてなんちゃってな(非実用的な)計算などをしていました。これらを、本番で使える部分を探していたところでした。
行ったパフォーマンスチューニング
羅列します。後で詳細を書くかもしれません。
ローカルのリソースについて
- 画像(png,jpg)をWebPに変換
- 画像を圧縮
- 動画(mp4, gif)をWebMに変換
- 音声(mp3)を圧縮
- 利用していないフォントを削除
動的にアップロードするリソースについて
POST
時にサーバー側で圧縮と変換を行う
ネットワークタブを見ながら....
- フォントを
rel=preload
で読み込む優先順位を上げる - スクリプトファイルを
defer
で実行 - FetchAPIに
limit, offset
を指定して、必要な分だけ読み取る - スクリプトを分割して 必要な時にだけ読み取る(
dynamic-import
)
プロファイルをみながら....
- addEventListnerに
{passive: true}
を明示 - 無駄に計算をしている、ループを回している処理を削除
利用度カバレッジとかを見ながら
- 無駄なCSSを探して削除
tailwind
を中で使っていたが TreeShakingのためにpurge
設定- cssnanoを利用
- 無駄なJSを探して削除
webpack analyzerをみながら....
lodash
をlodash-es
に置き換え(tree-shakingの目的)jQuery
を削除(ajax
とかをfetch
に)moment
をdayjs
に置き換え
webpack について
mode: 'production'
を付与して、圧縮やTreeShaking, Splitbabel-loader
を chrome最新版のためだけにカスタマイズ
APIサーバーについて
- Cache が聞いていなかったので
max-age, no-store
付与
やれなかったこと
img
にwidth/height
の指定- 画像
Lagyloading
- http2(これは証明書とかの問題で)
- 静的ファイルをNginxとかから配信(リバースプロキシ) ※デフォルトでは Express を用いていた
- express を fastify に置き換え
node-helmet
を削除して、手動で記述
やってたけど途中で諦めたこと
冒頭でもお伝えしたように、Next.js(SSG) × Vervel
の環境を作ろうと思いました。デフォルトではHeroku
の環境だったので、移行をしなくてはいけませんでした。また、コードは React(react-router)
で書かれていたため、Next.js
に移行する必要がありました。
- APIサーバーを用意
DBがSQliteを利用していたため、Vercel
のようなファンクションごとにインスタンスがたつ環境ではデータを保持することができません。別のDBに置き換えることも考えたのですが、APIサーバーを別途用意する方が楽そうだったので、Heroku
で用意をしました。(ここら辺から生き地獄が始まります)
- CORS設定
APIサーバーを別途用意したため、CORSの設定をする必要がありました(数行書くだけ)
- ログインユーザー管理方法をJWTに変更
ドメインを跨がないといけないため既存のSessionでの管理はできなくなりました。今回は jsonwebtoken
というライブラリを用いてJWT管理をしました。何気めんどくさかった。
「よっしゃドメインまたいだAPI通信もできるようになったし、あとはやるだけだ。」と思って頑張ってやっていた自分を褒めてあげたいです。ちなみにこの時、SSG, CDN, Nextによる最適化 が目前だったため、圧倒的な優勝を想像していました。
- NextJSへの移行
SSRが行われているため、サーバーサイドでは機能しないようなコードがいくつかあったので修正をしました。react-router
からpages
によるルーティング変えました。Image
やLink
タグをNext.js
のものに置き換えました。
ここまでやって断念しました。
後でやればいいやと思っていた、TailWind のデザインが なぜか上手く反映されない。。。。。。。。。。。。。。デザインがすっごい崩れるという問題にぶつかりました。TailWindは初見だったし、「分からん」ってなってしまいました。
Vercel のエッジキャッシュ (SSG)利用しようとしてたけど、tailwind x Next.js(ssg) への移行でめっちゃ時間とかした。
— かーーず🏎️ (@kaa_a_zu) 2021年2月7日
やったこと
- APIサーバー作成(corsとかも)
- セッションでのユーザー管理からjwtに変更
- Next移行
結果デザインクッソ崩れた。普通にチューニング始める
#WebSpeedHackathon
諦めた時に打ったcommit ↓
結果
レギュレーション違反
時間がなくて、焦っていました。最後の方で必死に色々と触っていたため、挙動の確認をしていませんでした。 残り5分で挙動確認をしたところ、サインインができなくなっていました。ログインが出来ず、呟けないSNSは、新しいですね。 途中優勝するんじゃないか?とか思ってたので、最も情けない結果ですね。
考察
Next.js
に移行する時に行ったインフラの構築に何気に時間がかかりました。インフラの勉強をしなくてはいけないなと思いました。webpack
への知識まだまだだなーと思いました。こういう時ってどう書けば良いんだろうとか結構ググりました。- 時間管理能力の不足、もしくは最新の技術(TailWindのCSSの当て方とか)を触っておくべきだったなと思いました。
感想
Webフロントに入門した頃の、過去の自分と比べると成長を感じれました。「何をすればいいか分からない」ではなく「しないといけないことがいっぱいあって時間がない」と思えたのは凄くよかったです。1日目はフルで参加できたのですが、ご飯を食べることも忘れるくらい熱中していました。また、やりたかったけどできなかったことに挑戦する機会、新たな学びを得れる機会を半ば強制的に作れたのはよかったです。
改めて、最高のイベントでした!運営のサイバーエージェントのみなさま、ありがとうございました。ここについて、詳細が欲しいという内容がありましたら、コメントください🙏