uxm v1.2.0
...
Usage
# install using npm
npm install uxm
# or yarn
yarn add uxm
Collect user-centric metrics and send them to analytics.
Metrics are observed because their appearance is not guaranteed during one session. User may close the tab early or not interact with a page.
Replace reportToGoogleAnalytics
with your custom function for metrics collection.
import { metrics } from 'uxm'
import { reportToGoogleAnalytics } from 'uxm/google-analytics-reporter'
metrics
.on('first-contentful-paint', fcp => reportToGoogleAnalytics({ fcp })
.on('largest-contentful-paint', lcp => reportToGoogleAnalytics({ lcp }))
.on('first-input-delay', fid => reportToGoogleAnalytics({ fid }))
.on('cumulative-layout-shift', cls => reportToGoogleAnalytics({ cls }))
More examples:
...
import {
getTimeToFirstByte,
getFirstContentfulPaint,
getDomContentLoaded,
getOnLoad,
metrics,
getHardwareConcurrency,
getEffectiveConnectionType,
getDeviceMemory,
getUrl
} from 'uxm'
// later, track sessionId and debounce events
import { reportMetrics } from 'uxm/api-reporter'
const loadingMetrics = {
ttfb: await getTimeToFirstByte(),
fcp: await getFirstContentfulPaint(),
dcl: await getDomContentLoaded(),
ol: await getOnLoad()
}
const device = {
effectiveConnectionType: getEffectiveConnectionType(),
url: getUrl()
}
reportMetrics({ ...loadingMetrics, ...device })
// report delayed metrics
metrics
.on('largest-contentful-paint', lcp => reportMetrics({ lcp }))
.on('first-input-delay', fid => reportMetrics({ fid }))
.on('cumulative-layout-shift', cls => reportMetrics({ cls }))
...
import { observer, time, timeEnd, timeEndPaint } from 'uxm'
// collect CrUX metrics like in prev example
// ...
// observe SPA events
observer.on('measures', measures => reportEvents('measures', parseMeasures(measures))) // ignore <1s
observer.on('long-tasks', longTasks => reportEvents('longTasks', parseLongTasks(longTasks))) // use only duration
observer.on('resources', resources => reportEvents('resources', parseResources(resources))) // only XHR
observer.on('layout-shifts', layoutShifts => reportEvents('layoutShifts', parseLayoutShifts(layoutShifts))) // round to % & only values
// track performance with custom metrics
time('render')
await render() // perform UI render
timeEndPaint('render') // report only after all the paints finished
time('compute')
computeSomething() // perform heavy compute and track exact time
timeEnd('compute') // report it, use time & timeEnd as trackable console.time + console.timeEnd
...
// from
import { useEffect } from 'react'
import { time, timeEndPaint } from 'uxm'
export const App = () => {
time('renderApp')
useEffect(() => {
timeEndPaint('renderApp')
}, [])
return <div className="app">Hello</div>
}
// or:
import { useTime } from 'uxm/react'
export const App = () => {
useTime('renderApp')
return <div className="app">Hello</div>
}
function useTime(label) {
time(label)
useEffect(() => {
timeEndPaint(label) // wait for the paint
}, []) // only once
}
// report "measures" to analytics
observer.on('measures', (measures) => reportEvents(measures))
API
User-centric metrics
https://web.dev/metrics/#important-metrics-to-measure
Subscribe to the core user-centric metrics.
- FCP: metrics.on('first-contentful-paint', fcp => {})
- LCP: metrics.on('largest-contentful-paint', lcp => {})
- FID: metrics.on('first-input-delay', fid => {})
- CLS: metrics.on('cumulative-layout-shift', cls => {})
- await getFirstContentfulPaint() || getFirstInputDelay() || getLargestContentfulPaint() || getCumulativeLayoutShift()
Custom events
https://web.dev/metrics/#define-your-own-metrics
Subscribe on raw events and build your own metrics.
Use getEventsByType(type)
to get buffered events.
- performanceEvents.on('long-task', longTasks => {})
- performanceEvents.on('element-timing', elementTimings => {})
- performanceEvents.on('resource', resources => {})
- performanceEvents.on('layout-shift', layoutShifts => {})
- await getEventsByType('mark' || 'measure' || 'resource' || 'element-timing' || 'layout-shift' || 'long-task', 'navigation', events => {})
- createPerformanceObserver(eventType, cb)
Profile your app and build custom metrics
- mark(markName) + measure(measureName, startMarkName, endMarkName) => traditional userTiming
- time(label) + timeEnd(label) || timeEndPaint(label) => trackable constole.time|console.timeEnd, timeEndPaint waits for idle main thread for UI operations
- performanceEvents.on('measure', measures => {})
Device info
Sync API to differenciate devices.
- getDeviceMemory()
- getEffectiveConnectionType()
- getHardwareConcurrency()
- getUrl()
- getUserAgent()
Navigation timing
Async API for back-end monitoring.
- await getTimeToFirstByte()
- await getServerTiming()
- await getDomContentLoaded()
- await getOnLoad()
Deprecated
from v1
del
: getFirstPaint() - useless, use getFirstContentfulPaint or getEventsByType('paint') and filterfirst-paint
del
: getUserTimings() => use getEventsByType('mark') + getEventsByType('measure')del
: getResources() => getEventsByType('resources')del
: getLongTasks() => not buffered yet, later getEventsByType('long-task')del
: uxm(opts) => in favor of explicit configdel
: getDeviceType() => better to use real device parsing or an HTTP header from CDN
Examples
Credits
Made with ❤️ at Treo.sh.
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago