Files

45 lines
2.0 KiB
JavaScript

/**
* Measure a page load on any origin, from a cold cache.
*
* node scripts/perf.mjs <origin> [--out file.json] [paths...]
*
* Per page, viewport (1440x900, 390x844) and network (unthrottled, Fast 3G with
* 4x CPU): TTFB, FCP, LCP and its element, CLS, TBT, first-party JS/CSS/font/image
* bytes, third-party bytes, request count, render-blocking stylesheets and the
* response headers of the HTML, JS, CSS and a font.
*/
import { chromium } from '@playwright/test'
import { writeFileSync } from 'node:fs'
import { measure, profiles, viewports } from './perf-measure.mjs'
const args = process.argv.slice(2)
const origin = args.find((a) => a.startsWith('http')) ?? 'https://hanzo.ai'
const out = args.includes('--out') ? args[args.indexOf('--out') + 1] : undefined
const paths = args.filter((a, i) => a.startsWith('/') && args[i - 1] !== '--out')
const pages = paths.length ? paths : ['/', '/login', '/signup', '/pricing', '/chat', '/models', '/kai']
const browser = await chromium.launch()
const result = { origin, at: new Date().toISOString(), pages: {} }
for (const path of pages) {
result.pages[path] = {}
for (const [vn, vp] of Object.entries(viewports)) {
for (const [pn, prof] of Object.entries(profiles)) {
// The median of three by LCP smooths the edge and the machine.
const runs = []
for (let i = 0; i < 3; i++) runs.push(await measure(browser, origin, path, vp, prof))
runs.sort((a, b) => a.lcp - b.lcp)
const r = runs[1]
result.pages[path][`${vn}-${pn}`] = r
console.log(
path.padEnd(10),
`${vn}-${pn}`.padEnd(15),
`ttfb ${r.ttfb} fcp ${r.fcp} lcp ${r.lcp} cls ${r.cls} tbt ${r.tbt}`,
`js ${(r.jsBytes / 1024) | 0}K/${r.jsCount} css ${(r.cssBytes / 1024) | 0}K font ${(r.fontBytes / 1024) | 0}K img ${(r.imgBytes / 1024) | 0}K 3p ${(r.thirdPartyBytes / 1024) | 0}K req ${r.requests}`,
r.lcpEl ?? '',
)
}
}
}
await browser.close()
if (out) writeFileSync(out, JSON.stringify(result, null, 1))