Cloudflare Worker のバンドル削減2日目、外部HTML化で287KiB空けて miller-viewer 島は予測の1割だった
朝いちで聞いたのは、昨日の積み残しは何か、だった。数字が合っていない気がしていた。
返ってきた答えは想像より悪い。教科書の講座は13章あって、変換が終わっているのは ch01 だけ。残り11章は手つかず。しかもその ch01 のコミットはローカルブランチに残ったままで、push もマージもデプロイもしていない。前日に走らせた切り分け調査(DD)が「このファミリで −269.8 KiB」と見積もっていた本命は、まだ1バイトも取れていなかった。
そのまま11章の変換に入った。
3章だけ、図の見た目が変わった
dry-run は11章すべて通過した。島78個、焼き込む図81個。変換11件も成功して、.vue を消してホスト経由に切り替えても SSR は保てている。
比較で止まった。11章のうち8章はピクセル一致だった。ch04、ch05、ch06 の3章だけ、図の md5 が変換前と違う。
最初はアニメーションのタイミング差を疑った。図の transition は状態変化のためのもので、採取のタイミングでずれる種類ではない。そう分かって、その線は消えた。次に CSS の衝突を疑った。1ページに複数の図の CSS をまとめて焼き込むので、セレクタの接頭辞が共有されていれば、後から定義した図のスタイルが前の図に効いてしまう。
当たった。不一致の図はすべて .pl-figure-wrap という接頭辞を共有していて、一致した2つだけが .mm- と .tax- という固有の接頭辞を持っていた。<style scoped> を素の CSS に落とした結果、同名のセレクタが1枚のページに同居して、最後の定義が全部の図に効いていた。
他の章でも規則性を確かめさせた。ch05 は .cf-* を共有する4図のうち、最後に定義される CfFcf だけが一致。ch06 は .an-* を共有する3図のうち、最後の AnDupont だけが一致。「最後の定義が勝つ」で全部説明がつく。
図ごとに CSS を名前空間化する形にコンバータを直させた。ch01 だけ古い生成規則で作られているのは気持ちが悪いので、.vue を git から復元して12章まとめて作り直した。
HTML は名前空間化のぶん1.2〜1.3倍に膨らんだ。それでも静的アセットに出てしまえばバンドルには載らない。
結果は12章すべてピクセル一致で、NG はゼロだった。項目でいうと84/84 の満点で、ch04 も Vue 版と md5 完全一致に戻った。テストも3,120件パス。
ビルドが3分で黙る
margin を測るためにビルドさせた。6〜7分で終わる想定だったのに、Nitro の段階で止まった。
前日と同じ症状だった。ビルド用に一時退避された画像159枚が、元の場所に戻らないまま残っている。復元させて、パイプを外してログへ直接書く形で再実行した。
また約3分で止まった。2回連続。バックグラウンド実行で出力が途切れるのが原因と見て、159枚をもう一度復元してから foreground(上限10分)で回した。
通った。margin 656.3 → 943.3 KiB、+287.0 KiB。 DD の予測 −269.8 KiB を上回った。
学習ゲートが空回りしている
コミットで学習ゲートに止められた。/learn を実行させたら、クイズを出すツールがセッションに見つからない。調べさせると、クイズサーバーが MCP に登録されていなかった。
ついでに履歴も見せてもらった。前日7/29のコミットは全部 LEARN_SKIP で通っていて、最後に受領証が出たのは7/28。学習ゲートは2日間、実質的に動いていない。
今日も LEARN_SKIP で通してマージし、デプロイまで進めた。デプロイ後の margin は944 KiB。
本番で12章を見る
本番の SSR を確認させたら、ch02、ch03、ch04 で島も data-fig も0だった。手が止まる。ただエッジキャッシュの疑いがあったので、キャッシュバスターを付けて叩き直させたら正常に返ってきた。一時的な現象だった。
改めて12章を確認させた。島84個、SVG は全章 SSR、CSS の名前空間も焼き込み済みだった。
ch04 は重くて Chrome のツールがバックグラウンドに落ちたので、Playwright で本番の描画を直接撮らせた。dev と md5 完全一致、つまり移行前の Vue 版と同じ絵が出ている。自分の目でも1枚見た。マゼンタの段階利益ボックスも配色もフォントも崩れていない。クイズの島もクリックが通る。
昨日の積み残しは、ここで閉じた。
次のファミリは島化しやすいはずだった
miller-viewer 島に移る。着手前に1つだけ確かめさせた。その部品は今 SSR されているか。
代表3ファイルすべてで MillerViewerLoader は <ClientOnly> の内側にあった。もともとクライアントでしか描画していないのだから、島に切り出しても SSR は後退しない。教科書でやった「本文を焼き込む」方式は要らない。
セッションが検証ログとスクリーンショットで重くなっていたので、ここで切った。引き継ぎには注記を1つ付けた。01-summary.vue だけは Loader に子要素を渡していて、単純な島化では済まないかもしれない。
引き継いだ先の第一報が、想定より大きい話だった。着手前に見ていた規模は63ページ、118箇所。実際に調べさせると、MillerViewerLoader を使っているのは lessons/bookkeeping の34ファイルだけではなく、8コース119ファイルにまたがっていた。今回の対象は33ページ。
33ページのベースラインを採取して、パイロットを1本通した。18/18で合格し、スクリーンショットはデスクトップもモバイルもピクセル一致だった。残り32ページの変換に進んだ。
作ったばかりのホストファイルが消えた
変換後のスナップショットを採らせたら、全ページが同一ハッシュで、エラーが1件出た。
dev サーバーが大量削除の直後に壊れていた。再起動して見に行くと、作ったばかりのホストファイルが無い。PowerShell で実在を確認させても無い。
原因は自分たちで書いた削除ループだった。
# 変換済みの .vue を消すための一覧。ホスト自身のコメントにも同じ文字列が入っていた
grep -rl 'MillerViewerLoader' <対象ディレクトリ>
ホストファイルのコメントに MillerViewerLoader と書いてある。だから抽出の一覧に自分自身が入り、自分を消した。他に巻き込まれたファイルは無い。件数を照合させて確かめた。ホストを作り直して、採取をやり直した。
33/33、全594項目が一致した。
ページを移動したときの2件の NG
同じホストの中でページを移動したときの挙動も見た。島がきちんと破棄されて再マウントされるか、操作が効くか。2件 NG が出た。
移行前の Vue ページ(intro-to-accounting/part01)で同じ操作をさせたら、そちらでも同じ挙動だった。MillerViewer にもとからあるバグで、この移行で持ち込んだものではない。テスト側の期待値を直したら、挙動は18項目すべて OK になった。
歯止めも足した。check:islands を miller-viewer に対応させて、単体テストに sharedProps のケースを追加。どちらもネガティブテストにかけて、わざと壊したときに落ちることを確認させた。通ったことしか見ていない検査は歯止めにならない、というのは前日の学びのままだ。
数字が出ない
ビルドして margin を測った。
削減量は DD 予測の10.4%だった。
33ページの外部HTML化は完了して、検証も全部パスしている。壊れてはいない。ただ、目的だったバンドルの削減がほとんど取れていない。中断条件に引っかかったので、そこで手を止めて報告してもらった。
教科書のときは予測 −269.8 KiB に対して、margin が287.0 KiB 広がった。同じ DD が出した予測なのに、こちらは1割しか出ない。予測の精度はファミリごとにばらつく。上から順に潰していけばいいという前提が崩れた。
次は先に内訳を確定させる
次の候補は financial-statements-quiz の78ページ、予測 −277.7 KiB。同じ失敗を繰り返さないよう、着手する前に実際のチャンクの内訳を確定させた。
クイズのデータは前日すでに外部 JSON へ出してあった。残って重いのは図のコンポーネントらしい。図の動的な部分がルート要素のクラス1つだけなら、静的に焼き込んでも動きは保てる。89図すべてが同じパターンだった。
今度は数字の裏が取れている。その方式で着手して、途中まで進めたところで WIP コミットにして保全した。
学び
- 一括削除のスクリプトは、自分自身がその条件にマッチしないか先に確かめる。ホストのコメントに部品名を書いただけで削除対象になった
<style scoped>を素の CSS に落とすと、接頭辞を共有する図が同じページで混ざる。図ごとに名前空間を切る- 見た目の差分が出たら、一致した個体との違いを探す。
.mm-と.tax-だけが固有の接頭辞だと分かった時点で原因は決まった - 移行で出た NG は、移行前のページで同じ操作をして切り分ける。既存バグを自分の回帰と誤認すると、直さなくていいものを直すことになる
- ビルドをバックグラウンドで回すと出力が途切れて3分で止まる。foreground で回す
- 削減の予測はファミリ単位でばらつく。着手する前にチャンクの実体を見る
明日やること
-
financial-statements-quizの変換を仕上げる(WIP コミットで止めてある) - 学習ゲートのクイズサーバーを MCP に登録し直す。2日間
LEARN_SKIPで通り続けている