WebSpeedHackathon2023

とりあえずHomeからやっていく。
ぱっと見、画像が大量に読み込まれてるっぽいので画像の最適化から手をつけようかな。
Home
- 画像サイズ・フォーマットの見直し
- CLSを悪化させているアイキャッチ画像の見直し
- 画像サイズ
- プレイスホルダーの差し込み

- トップページがBase64になってるの怪しい

ビルドが結構遅くてストレスなのでそこを先見た方が良いかもと思い調べる。あとエディタの環境設定を普段の設定にした。
- ESLintは結構充実しているので、
unused-imports
のプラグインのみ追加 -
.vscode/settigns.json
で保存時のフォーマットなどの設定を追加

初期Lighthouse

ProductHeroImageの改善
- ProductHeroImageの画像読み込みでCanvas系を削除:LCPが160くらいに改善
- canvaskit-wasmを削除
- aspect-ratioをCSS化:バンドルサイズが減るはず(他の部分の改善も必須)
あとでやる
aspect-ratioをCSS化
React.memoと_.isEqualの合わせ技を削除(ミュータブルなオブジェクト操作とかが行われていた場合壊れる原因になるので、あとで慎重に解決していきたい)

開発環境の改善
- 開発サーバを
vite build --watch
で起動していたので、vite
でホットリロードが効くように変更!

comment
window.Temporal.Now.plainTimeISO().hour
Temporal使ってる!すげ

画像の改善
- 画像をjpg -> webpに変更。時々1MB超えの画像が含まれていたので、10分の1くらいには圧縮されている。
- HOMEのスコアはLCPがかなり減少
- レイアウトシフトが増えているのは画像の読み込み順が変更された影響かな。今は気にしなくて良さそう

画像の改善
- FVに入る画像にloading="eager"を、全ての画像にdecoding="async"を設定
- 本当は
<link>
でpreloadとかやりたいけど、サーバー側の処理が絡むので今はやらない
- 本当は
そして今までLighthouseのスコアに変更が反映されてなかった疑惑が.....;;;
CLSとかちゃんと改善されてた。

これ以上改善できるとこあんまりないのに何で赤なんだ?と思ったら開発ビルドでした......休憩して再計測します.......

再開!

Productionビルド。思ったより開発ビルドと変わらなかった

サーバーが絡む部分は後回しにして、バンドルサイズの削減を先やってしまおう。明らかに大きすぎて、かなりボトルネックだ。
バンドルサイズの削減
https://zenn.dev/manalink_dev/articles/vite-bundle-analyzer を参考に、rollup-plugin-visualizerを導入する。
zip code大きすぎる....!

バンドルサイズ削減
-
zipcode-ja
: 非同期読み込み -
date-time-format-timezone
: polyfillは最新版Chromeでは不要なので削除 -
react-icons
: Treeshakeを聴かせるため、*
でのimportを個別importに変更 -
core-js
: 最新版Chromeでは不要だと思われるため削除(最新の文法を利用している可能性があるので、見つけ次第手動で修正) -
lodash
: 個別パッケージに分割
@js-temporal
を外したいけど依存が大きくて後回し...

ビルド設定の見直し
-
cssTarget
/cssMinify
: デフォルト設定(minify有効化)に -
target
: Chromeのv110を設定

画像の最適化
- ロゴ画像を圧縮

コード分割

Topは大枠完了。
次はProductDetail
- WidthRestrictionをCSS化
- AspectRatioをCSS化
- アバター画像をwebp化

再開ー
ProductDetailの続き
- 動画をmp4 -> webmに変換
- 動画のサムネイル生成処理を改善したい。今回はおそらく事前にサムネイルを生成しておけばいい(BEが絡むのであとでやる)

- GetDeviceTypeをresizeイベントを監視する形に変更(hooksベース)
- 細かなCSSの修正
(中断 @ 16:30)

19:00-19:40
- 画像および動画のサムネイルを事前生成
TBTが緑に!

21:00 -
Orderページ
-
初期
-
認証系の条件分岐を改善
- なぜかTBTが改善してる........? 認証周りで変な処理が入ってたのかな?
- なぜかTBTが改善してる........? 認証周りで変な処理が入ってたのかな?

ページで完結する改善はやり切った感があるが、全体的にスコアが悪いので、パフォーマンスを計測しながらボトルネックを探す。
やはりindex.jsの読み込みがとても遅い。バンドルサイズも749.53 kBと大きいので、バンドルサイズをさらに削減したい

バンドルサイズ削減
- Recoil / Temporal / zodが重い
- Recoilはmodal stateのみに利用しているのでvaltioに置換
- zodはメールアドレスなどの簡単なバリデーションのみの利用なので、自前で書き直す
631.52 kBまで落ちたけど、まだまだ。
よくみるとlodashを個別パッケージに分割したはずなのにlodash-esがまだ重い気がする。TreeShakingが効いていない説がある。tsconfigがクラサバ共通なので、その辺ぽいな
formikが依存してた..

バンドルサイズ削減
Temporalを個別importできることを知った!
- @js-temporal/polyfill: 個別インポートするように変更
- formik: useStateで書き直し
421.16 kBまで削減!
正規表現の改善
- パスワードチェックの正規表現をChatGPTに直してもらった

バンドルサイズ削減
- モーダルをlazy import

- CLSがだいぶ改善している。
- FCPとLCPはおそらくロード時間が遅いことに起因しているはず。
- TBTはjsのサイズがまだ大きいのかなー.

初期ロードの削減
- サムネイル用の画像をさらに圧縮
- Gzipの導入
- 今回はViteで事前に圧縮する形にした

- GraphQLのフィールドを削減
- ファーストビューの判定を厳格化(スライダーの順番も考慮に入れた)

Product detail
- GraphQLのクエリ改善
before
after

- GraphQLのクエリを修正

GraphQLサーバー側の修正に入る、一旦休憩(1:27)

3:00-
- GraphQLで、FVに当たる要素だけ先行してフェッチ
- 各コンポーネント内でフェッチを行うように変更し、プレイスホルダーを設定

- srcset属性で、画像の出しわけ
- setimmediateを削除

4:27 終了 15:00 再開
-
useSlider
をuseLayoutEffect
を利用する形で修正

- ProductDetailでSuspenseとFallbackを設定
- LCPとCLSが軽減!
- LCPとCLSが軽減!

-
no-store
のキャッシュ設定を削除(適切なキャッシュ設定をしないといけない気がしつつ、ネットワーク依存(?)になってしまうのでキャッシュを使うのがありかよくわからない)
↓
おそらくキャッシュを設定することでクライアントサイドの挙動が変わるので、そのためにキャッシュ設定を入れるのが適切そう

フォントの読み込み改善 (404)
- フォントファイルの圧縮
- フォールバックを設定し、LSを防止
before
after

16:00 終了 17:00 再開
- react-helmet-asyncの導入: エラーが出てたので変更した

Orderページ
- フォールバックの設定(LS防止)
before
after

18:20 終了 22:00 再開
GraphQL改善
- サムネイルをバックエンド側で取得するように変更

- Zipcode改善
- いくつか検討したが、JSONファイルを分割し配信する
- 郵便番号の上6ケタをベースに
XXXXXX.json
ファイルに分割 - ユーザーが6桁入力するごとにjsonファイルをフェッチし、7桁目の入力でサジェストを出す
- JSONファイルは1kB未満なので、妥協
- 郵便番号の上6ケタをベースに
- ボツ案
- 上記の
XXXXXX.json
または全JSONファイルをgzip化して配信 → wasmでデコード- 繰り返しが少なくgzip化してもファイルサイズがあまり減らないためなし
- バックエンド側でzipcodeJaを読み出し、住所を返す
- 結局JSONを返すことになるので、静的ファイルとして配信した方が早いだろうと予想
- 上記の
- いくつか検討したが、JSONファイルを分割し配信する

最終結果(ローカル計測)
細切れだったけど、ほぼ2日間で、できることは大体できたと思う。これ以上はSSR or キャッシュの力を借りないと難しいのではないか。