feat(arc-vue): 描画の環境依存とタイミング依存を切り離す - #25
Open
sousuke0422 wants to merge 4 commits into
Open
Conversation
|
Warning Testing pausedMonthly snapshot limit reached. Update your plan for additional snapshots and to resume testing. |
Pin device tier in Storybook stories so CI runners with different deviceMemory/hardwareConcurrency render the same virtualization path. Assisted-by: multi-agent-shogun-aki-tweak
Watch useVirtualization and remeasure scrollRef after DOM updates so viewportJson.client_height matches the virtualized container on tier flip. Assisted-by: multi-agent-shogun-aki-tweak
sousuke0422
force-pushed
the
feat/vrt-arc-measurement
branch
from
August 11, 2026 09:45
906f88f to
a28be49
Compare
Split virtualization state into requestedVirtualization (CSS class, applied immediately) and viewportReady (WASM viewport, enabled only after nextTick + scroll metrics sync). viewportJson stays undefined until the measured state is ready, so no render call can carry a stale client_height from the previous tier. Tests drop latestViewportJson()/.at(-1) and assert every render_svg / render_canvas_commands call: no stale 880 anywhere, and every post-flip call must carry the measured viewport (600). Verified to fail on a28be49 (call #2 passed client_height 880) and pass with the fix. Assisted-by: multi-agent-shogun-aki-tweak
…t in CI While virtualization is requested but the viewport is not yet measured (initial mount, tier-flip window), both render_svg and render_canvas_commands could run once with viewport_json undefined, rendering the full range. Defer both computeds at a single chokepoint until viewportReady; non-virtual (high tier) renders are not delayed. Add window-invariant tests scanning every mock call (W1 mount svg/canvas, W2 flip-window props/backend leaks, high-tier non-delay guard) and wire 'pnpm test' (vitest run) into the vue CI job so the suite actually runs. Assisted-by: multi-agent-shogun-aki-tweak
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
VRT でスクリーンショットを撮るとき、描画結果が実行環境やタイミングによって変わらないようにする。
背景
detectDeviceTier()はnavigator.deviceMemoryとnavigator.hardwareConcurrencyを読んで low / high を決めていた。この判定が
useVirtualizationを切り替え、viewportJsonを通ってrender_svgに渡る引数を変える。つまり同じ入力データでも、動かす機械によって描画結果が変わりうる。
VRT はスクリーンショットの差分で回帰を検出する仕組みなので、環境で絵が変わる要因は誤検出の直接の原因になる。
計測結果
VRT に載せる前に、環境依存で問題になりうる箇所を 3 つ想定して実測した。
結果として、今のストーリー構成では 3 つとも画像の差分にはならなかった。
wasm の初期化待ちで空の絵が撮れる可能性を確認したが、20 回撮って 1 回も再現しなかった。
デバイス階層の違いは、DOM のクラス属性としては実際に分岐していた。
ただし PNG のハッシュは全パターンで同一だった。
チャートの高さが約 210px、ビューポートが 240px で、仮想化が省略する対象が存在しなかったため。
clientHeightの測定タイミングによる差も再現しなかった。したがってこの PR は、今すでに起きている差分の修正ではない。
ストーリーのデータ量が増えて仮想化が実際に働き始めた時点で顕在化する問題への、事前の対処にあたる。
変更内容
deviceTierprop を追加し、渡された場合は自動判定より優先する。Storybook の全ストーリーでこれを
highに固定した。deviceTierをconstからcomputedに変えている。prop の変更に追従させるため。
反応性を通したことで生まれた欠陥を二つ塞いだ
deviceTierを computed にしたことで、実行時に階層が変わりうるようになった。その結果、測定が追従していない箇所が二つ露見した。
どちらもレビューで指摘を受けている。
一つ目は階層が high から low へ変わったときで、
clientHeightが古いままviewportJsonが組まれ、全範囲の WASM 描画が一度走っていた。二つ目は初回マウント時で、
init()の完了後に描画が可能になった時点ではまだ測定が済んでおらず、同じく全範囲の描画が一度走っていた。低性能な端末ほど、起動のたびに仮想化が避けるはずだった処理を通ることになる。
どちらも
viewportPendingという単一の条件でまとめて塞いだ。仮想化が要求されていて、かつ測定が済んでいない間は、SVG と Canvas のどちらの経路でも WASM を呼ばない。
経路ごとに個別の手当てを積むと、次に増えた経路が漏れるため。
検証
回帰テストは、階層が変わった後に起きた
render_svgとrender_canvas_commandsの呼び出しを全件走査する。viewportJsonを欠くもの、あるいは古い高さを含むものが一つでもあれば落ちる。最初に書いたテストは最後の呼び出ししか見ておらず、途中の誤った描画を素通りさせていた。
最終的な出力は正しくなるため、それでは欠陥を検出できない。
各テストが修正前のコードで落ちることを実測している。
viewportPendingを常に false へ潰した状態では 4 件が落ち、SVG と Canvas の両方で「viewport を伴わない呼び出しが何回目に起きたか」が出力される。テストが CI で実行されるようにした
これまで vue の job は
typecheckとbuildしか実行しておらず、追加したテストは CI で一度も走っていなかった。job に非対話の vitest 実行を追加している。
追加しただけで終わらせず、テストをわざと壊した状態で job が失敗することを確認した。
実行ステップが存在していても、テストを拾っていなければ意味がないため。
既知の制約
ストーリーを
highに固定したことで、仮想化が有効な経路は VRT の対象から外れている。この経路を継続的に見るなら、
lowに固定したストーリーを別途用意する必要がある。チャートがビューポートを超える大きさのストーリーが存在しないため、仮想化そのものの描画結果は未検証のままになっている。
wasm 初期化については、遅延を人為的に作って空の絵が撮れることを確認する対照実験を行っていない。
20 回の非再現は、この環境で初期化が速かったことを示すにとどまる。
この三つは、タスク数がビューポートを超えるストーリーを
lowとhighの二本用意すれば、まとめて解消できる見込みがある。CI の状況
rust、vue、chromatic、Storybook Publish はいずれも成功している。
UI TestsとUI Reviewは Chromatic の月次スナップショット枠を使い切ったため保留になっている。この PR の内容とは無関係で、プラン側の対応が必要になる。
Assisted-by: multi-agent-shogun-aki-tweak