Measure complete CSS updates and fully cached warm reloads

This commit is contained in:
Jonathan Sykes
2026-10-08 05:12:32 +08:00
parent ce5a159d4a
commit a08d363f2d
5 changed files with 88 additions and 28 deletions

29
perf/measurement.mjs Normal file
View File

@@ -0,0 +1,29 @@
import assert from 'node:assert/strict';
export function assertChangedAssets(requests, expected) {
const paths=requests.filter(r=>r.bytes>0).map(r=>new URL(r.url,'http://localhost').pathname).filter(p=>/\.(?:js|css|woff2?|png|svg)$/.test(p)&&!['/sw.js','/asset-sync-core.js'].includes(p));
assert.deepEqual([...new Set(paths)],[expected],'only the changed application asset transfers; worker checks and derived index/manifest are separate overhead');
}
export async function waitForIdleAssets(page) {
if(!await page.evaluate(()=>!!window.Lazy?.warm))return;
await page.evaluate(()=>Lazy.warm());
const end=Date.now()+120000;
while(true) {
const ready=await page.evaluate(async()=>{
const c=await caches.open('ytplayer-assets'),r=await c.match('/__ytp_asset_state');
// Legacy rollback has no manifest state and installs its complete shell instead.
if(!r)return (await caches.keys()).some(k=>/^ytplayer-(?!assets|thumbs|fonts)/.test(k));
const m=(await r.json()).current;
return (await Promise.all(Object.values(m.groups).flatMap(g=>g.files).map(async p=>{
const response=await c.match(p+'?v='+m.files[p].h);
return response?.headers.get('X-Asset-Hash')===m.files[p].h;
}))).every(Boolean);
});
if(ready)return;
if(Date.now()>end)throw Error('Idle warm did not complete before benchmark');
await new Promise(r=>setTimeout(r,100));
}
}
export function assertWarmAssets(requests) {
const assets=requests.filter(r=>r.bytes>0&&/\.(?:js|css|woff2?|png|svg)(?:[?#]|$)/.test(r.url)&&!new URL(r.url,'http://localhost').pathname.endsWith('/sw.js'));
assert.deepEqual(assets,[],'warm reload does not transfer unfinished shell assets');
}