Open44

WebSpeedHackathon2023

Yuta IkeYuta Ike

とりあえずHomeからやっていく。
ぱっと見、画像が大量に読み込まれてるっぽいので画像の最適化から手をつけようかな。

Home

  • 画像サイズ・フォーマットの見直し
  • CLSを悪化させているアイキャッチ画像の見直し
    • 画像サイズ
    • プレイスホルダーの差し込み
Yuta IkeYuta Ike

ビルドが結構遅くてストレスなのでそこを先見た方が良いかもと思い調べる。あとエディタの環境設定を普段の設定にした。

  • ESLintは結構充実しているので、unused-importsのプラグインのみ追加
  • .vscode/settigns.jsonで保存時のフォーマットなどの設定を追加
Yuta IkeYuta Ike

ProductHeroImageの改善

  • ProductHeroImageの画像読み込みでCanvas系を削除:LCPが160くらいに改善
    • canvaskit-wasmを削除
  • aspect-ratioをCSS化:バンドルサイズが減るはず(他の部分の改善も必須)

あとでやる
aspect-ratioをCSS化
React.memoと_.isEqualの合わせ技を削除(ミュータブルなオブジェクト操作とかが行われていた場合壊れる原因になるので、あとで慎重に解決していきたい)

Yuta IkeYuta Ike

開発環境の改善

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

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

Yuta IkeYuta Ike

画像の改善

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

画像の改善

  • FVに入る画像にloading="eager"を、全ての画像にdecoding="async"を設定
    • 本当は<link>でpreloadとかやりたいけど、サーバー側の処理が絡むので今はやらない

そして今までLighthouseのスコアに変更が反映されてなかった疑惑が.....;;;
CLSとかちゃんと改善されてた。

Yuta IkeYuta Ike

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

Yuta IkeYuta Ike

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

Yuta IkeYuta Ike

サーバーが絡む部分は後回しにして、バンドルサイズの削減を先やってしまおう。明らかに大きすぎて、かなりボトルネックだ。

バンドルサイズの削減

https://zenn.dev/manalink_dev/articles/vite-bundle-analyzer を参考に、rollup-plugin-visualizerを導入する。
zip code大きすぎる....!

Yuta IkeYuta Ike

バンドルサイズ削減

  • zipcode-ja: 非同期読み込み
  • date-time-format-timezone: polyfillは最新版Chromeでは不要なので削除
  • react-icons: Treeshakeを聴かせるため、*でのimportを個別importに変更
  • core-js: 最新版Chromeでは不要だと思われるため削除(最新の文法を利用している可能性があるので、見つけ次第手動で修正)
  • lodash: 個別パッケージに分割

@js-temporalを外したいけど依存が大きくて後回し...

Yuta IkeYuta Ike

ビルド設定の見直し

  • cssTarget / cssMinify: デフォルト設定(minify有効化)に
  • target: Chromeのv110を設定

Yuta IkeYuta Ike

Topは大枠完了。
次はProductDetail

  • WidthRestrictionをCSS化
  • AspectRatioをCSS化
  • アバター画像をwebp化

Yuta IkeYuta Ike

再開ー
ProductDetailの続き

  • 動画をmp4 -> webmに変換
  • 動画のサムネイル生成処理を改善したい。今回はおそらく事前にサムネイルを生成しておけばいい(BEが絡むのであとでやる)
Yuta IkeYuta Ike
  • GetDeviceTypeをresizeイベントを監視する形に変更(hooksベース)
  • 細かなCSSの修正
    (中断 @ 16:30)
Yuta IkeYuta Ike

21:00 -

Orderページ

  • 初期

  • 認証系の条件分岐を改善

    • なぜかTBTが改善してる........? 認証周りで変な処理が入ってたのかな?
Yuta IkeYuta Ike

ページで完結する改善はやり切った感があるが、全体的にスコアが悪いので、パフォーマンスを計測しながらボトルネックを探す。

やはりindex.jsの読み込みがとても遅い。バンドルサイズも749.53 kBと大きいので、バンドルサイズをさらに削減したい

Yuta IkeYuta Ike

バンドルサイズ削減

  • Recoil / Temporal / zodが重い
    • Recoilはmodal stateのみに利用しているのでvaltioに置換
    • zodはメールアドレスなどの簡単なバリデーションのみの利用なので、自前で書き直す
      631.52 kBまで落ちたけど、まだまだ。

よくみるとlodashを個別パッケージに分割したはずなのにlodash-esがまだ重い気がする。TreeShakingが効いていない説がある。tsconfigがクラサバ共通なので、その辺ぽいな
formikが依存してた..

Yuta IkeYuta Ike

バンドルサイズ削減

Temporalを個別importできることを知った!

  • @js-temporal/polyfill: 個別インポートするように変更
  • formik: useStateで書き直し

421.16 kBまで削減!

正規表現の改善

  • パスワードチェックの正規表現をChatGPTに直してもらった
Yuta IkeYuta Ike

バンドルサイズ削減

  • モーダルをlazy import

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

初期ロードの削減

  • サムネイル用の画像をさらに圧縮
  • Gzipの導入
    • 今回はViteで事前に圧縮する形にした

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

Yuta IkeYuta Ike

Product detail

  • GraphQLのクエリ改善

before

after

Yuta IkeYuta Ike

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

Yuta IkeYuta Ike

3:00-

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

Yuta IkeYuta Ike

4:27 終了 15:00 再開

  • useSlideruseLayoutEffectを利用する形で修正
Yuta IkeYuta Ike
  • ProductDetailでSuspenseとFallbackを設定
    • LCPとCLSが軽減!

Yuta IkeYuta Ike
  • no-storeのキャッシュ設定を削除(適切なキャッシュ設定をしないといけない気がしつつ、ネットワーク依存(?)になってしまうのでキャッシュを使うのがありかよくわからない)

おそらくキャッシュを設定することでクライアントサイドの挙動が変わるので、そのためにキャッシュ設定を入れるのが適切そう

Yuta IkeYuta Ike

フォントの読み込み改善 (404)

  • フォントファイルの圧縮
  • フォールバックを設定し、LSを防止

before

after

Yuta IkeYuta Ike

16:00 終了 17:00 再開

  • react-helmet-asyncの導入: エラーが出てたので変更した
Yuta IkeYuta Ike

Orderページ

  • フォールバックの設定(LS防止)

before

after

Yuta IkeYuta Ike

18:20 終了 22:00 再開

GraphQL改善

  • サムネイルをバックエンド側で取得するように変更

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

最終結果(ローカル計測)

細切れだったけど、ほぼ2日間で、できることは大体できたと思う。これ以上はSSR or キャッシュの力を借りないと難しいのではないか。

Top

ProductDetail

Order

OrderComplete

404