calibre
Version:
Performance monitoring with Synthetic testing, Chrome UX Report, and Real User Metrics
94 lines (80 loc) • 2.7 kB
JavaScript
import ora from 'ora'
import columnify from 'columnify'
import { summary } from '../../api/rum.js'
import { humaniseError } from '../../utils/api-error.js'
import { options } from '../../utils/cli.js'
import { rumFilterOptions } from '../../utils/rum-options.js'
import { format } from '../../utils/formatters/index.js'
import { colorByGrading } from '../../views/grading.js'
const METRIC_LABELS = new Map([
['lcp', 'Largest Contentful Paint'],
['cls', 'Cumulative Layout Shift'],
['inp', 'Interaction to Next Paint'],
['fcp', 'First Contentful Paint'],
['ttfb', 'Time to First Byte'],
['rtt', 'Round Trip Time']
])
const main = async args => {
let result
let spinner
if (!args.json) {
spinner = ora('Connecting to Calibre').start()
}
try {
result = await summary(args)
if (args.json) return console.log(JSON.stringify(result, null, 2))
} catch (e) {
if (args.json) return console.error(e)
spinner.fail()
throw new Error(humaniseError(e))
}
if (!result.aggregate || result.aggregate.length === 0) {
spinner.fail(
'No RUM data available. Check that RUM is enabled for this site with: calibre rum config --site=<slug>'
)
return
}
spinner.succeed('RUM Summary')
console.log(
`Live visitors: ${result.liveVisitors} | Countries: ${result.distinctCountriesCount} | Sessions: ${result.aggregate[0].sessionCount}`
)
console.log('')
if (result.uxRating && result.uxRating.length > 0) {
const overall = result.uxRating.find(r => r.metric === 'overall_rating')
if (overall) {
console.log(
`UX Rating: Good ${overall.goodPercentage.toFixed(1)}% | Needs Improvement ${overall.needsImprovementPercentage.toFixed(1)}% | Poor ${overall.poorPercentage.toFixed(1)}%`
)
}
}
console.log('')
const agg = new Map(Object.entries(result.aggregate[0]))
const formatters = new Map(
(result.metrics || []).map(m => [m.value, m.formatter])
)
const metrics = ['lcp', 'cls', 'inp', 'fcp', 'ttfb', 'rtt']
const rows = metrics
.filter(m => agg.get(m) !== null && agg.get(m) !== undefined)
.map(m => ({
metric: METRIC_LABELS.get(m) || m,
p75: colorByGrading(
format({ formatter: formatters.get(m), value: agg.get(m) }),
agg.get(`${m}Grading`)
)
}))
console.log(
columnify(rows, {
columnSplitter: ' | '
})
)
}
const command = 'summary [options]'
const describe =
'Display Real User Metrics (RUM) dashboard — live visitors, aggregate web vitals, and UX ratings.'
const handler = main
const builder = {
site: options.site,
json: options.json,
...rumFilterOptions
}
export { command, describe, handler, builder }