kaa_a_zu’s blog

月ごとのレポートや技術的な内容を発信していきます

CA主催のスピードハッカソン に参加してきた話

本日、2021年2月6日から2日に渡って開催された、サイバーエージェント主催の スピードハッカソン に参加しました。そろそろパフォーマンス改善得意になりたい!って気持ちで臨みました。

尚、開発時にメモしていたことを簡潔に書くので、チューニングの詳細を知りたい部分があったらカーーズへのリプやコメントをください。

スピードハッカソンとは

既存の架空SNSのパフォーマンス改善を行うハッカソンで、順位決定のスコア測定にはLightHouseが使用されています。利用されていたメインな技術を載せておきます。

  • React
  • TailWind
  • Express(APIサーバー)
  • SQLite

ハッカソンのルール

①複数ページのパフォーマンスを上げる

Chrome最新版での動作確認を行う

③見た目を変更することはNG

④挙動を変更することはNG 

⑤サーバーは自分で用意する(サーバーサイドについてもチューニングできる)

参加する前に

実は今回はやろうとしていたことが2つありました。

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をみながら....

  • lodashlodash-es に置き換え(tree-shakingの目的)
  • jQuery を削除(ajax とかを fetch に)
  • momentdayjs に置き換え

webpack について

  • mode: 'production' を付与して、圧縮やTreeShaking, Split
  • babel-loaderchrome最新版のためだけにカスタマイズ

APIサーバーについて

  • Cache が聞いていなかったので max-age, no-store 付与

やれなかったこと

  • imgwidth/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 によるルーティング変えました。ImageLinkタグをNext.jsのものに置き換えました。

ここまでやって断念しました。

後でやればいいやと思っていた、TailWind のデザインが なぜか上手く反映されない。。。。。。。。。。。。。。デザインがすっごい崩れるという問題にぶつかりました。TailWindは初見だったし、「分からん」ってなってしまいました。

諦めた時に打ったcommit ↓

f:id:kaa_a_zu:20210207182219p:plain

結果

レギュレーション違反

時間がなくて、焦っていました。最後の方で必死に色々と触っていたため、挙動の確認をしていませんでした。 残り5分で挙動確認をしたところ、サインインができなくなっていました。ログインが出来ず、呟けないSNSは、新しいですね。 途中優勝するんじゃないか?とか思ってたので、最も情けない結果ですね。

考察

  • Next.js に移行する時に行ったインフラの構築に何気に時間がかかりました。インフラの勉強をしなくてはいけないなと思いました。
  • webpack への知識まだまだだなーと思いました。こういう時ってどう書けば良いんだろうとか結構ググりました。
  • 時間管理能力の不足、もしくは最新の技術(TailWindのCSSの当て方とか)を触っておくべきだったなと思いました。

感想

Webフロントに入門した頃の、過去の自分と比べると成長を感じれました。「何をすればいいか分からない」ではなく「しないといけないことがいっぱいあって時間がない」と思えたのは凄くよかったです。1日目はフルで参加できたのですが、ご飯を食べることも忘れるくらい熱中していました。また、やりたかったけどできなかったことに挑戦する機会、新たな学びを得れる機会を半ば強制的に作れたのはよかったです。

改めて、最高のイベントでした!運営のサイバーエージェントのみなさま、ありがとうございました。ここについて、詳細が欲しいという内容がありましたら、コメントください🙏