declare global { interface Window { timings: { cache: Record addLog: ( key: string, startTime: DOMHighResTimeStamp, endTime: DOMHighResTimeStamp ) => void log: (key: string, logAll: boolean) => number | void logAll: (keyStartsWith?: string) => void dumpKeys: () => string[] } } } const ENABLE_TIMINGS = process.env.REACT_APP_ENABLE_TIMINGS === 'true' export const timingsWrapper = (fn: (...args: any[]) => any, name: string) => { if (ENABLE_TIMINGS) { return (...args: any[]) => { // Reference: https://developer.mozilla.org/en-US/docs/Web/API/Performance/now const startTime = performance.now() const result = fn(...args) const endTime = performance.now() window.timings.addLog(name, startTime, endTime) return result } } return fn } export const initTimings = () => { if (ENABLE_TIMINGS) { window.timings = { cache: {} as Record, addLog: ( key: string, startTime: DOMHighResTimeStamp, endTime: DOMHighResTimeStamp ) => { if (!window.timings.cache[key]) { window.timings.cache[key] = [] } window.timings.cache[key].push(endTime - startTime) }, log: (key: string, logAll: boolean = false): number | void => { const timings = window.timings.cache[key] if (timings) { const totalSamples = timings.length const totalMs = timings.reduce((acc, timing) => acc + timing, 0) const headline = `Timings for ${key} (${totalSamples} samples, ${totalMs}ms)` if (logAll === true) { console.groupCollapsed(headline) } else { console.group(headline) } console.log('Timings:') console.table(timings) console.log('Timing samples:', timings.length) console.log('Total (ms):', totalMs) console.groupEnd() if (logAll === true) { return totalMs } } if (logAll === true) { return 0 } }, logAll: (keyStartsWith?: string) => { let totalMs = 0 for (const key in window.timings.cache) { if ( typeof keyStartsWith === 'string' && keyStartsWith.length !== 0 && !key.startsWith(keyStartsWith) ) { continue } const totalMsForKey = window.timings.log(key, true) if (typeof totalMsForKey === 'number') { totalMs += totalMsForKey } } console.log('Total (ms) for all timings:', totalMs) }, dumpKeys: () => { return Object.keys(window.timings.cache) }, } console.log('Timings initialised') console.log('To dump an individual timing, run `window.timings.log("key")`') console.log('To dump all timings, run `window.timings.logAll()`') console.log('To dump all keys, run `window.timings.dumpKeys()`') } // no-op }