/
performance-relayer.ts
91 lines (82 loc) · 2.55 KB
/
performance-relayer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/* global location */
import {
onCLS,
onFCP,
onFID,
onINP,
onLCP,
onTTFB,
Metric,
ReportCallback,
} from 'next/dist/compiled/web-vitals'
const initialHref = location.href
let isRegistered = false
let userReportHandler: ReportCallback | undefined
function onReport(metric: Metric): void {
if (userReportHandler) {
userReportHandler(metric)
}
// This code is not shipped, executed, or present in the client-side
// JavaScript bundle unless explicitly enabled in your application.
//
// When this feature is enabled, we'll make it very clear by printing a
// message during the build (`next build`).
if (
process.env.NODE_ENV === 'production' &&
// This field is empty unless you explicitly configure it:
process.env.__NEXT_ANALYTICS_ID
) {
const body: Record<string, string> = {
dsn: process.env.__NEXT_ANALYTICS_ID,
id: metric.id,
page: window.__NEXT_DATA__?.page,
href: initialHref,
event_name: metric.name,
value: metric.value.toString(),
speed:
'connection' in navigator &&
(navigator as any)['connection'] &&
'effectiveType' in (navigator as any)['connection']
? ((navigator as any)['connection']['effectiveType'] as string)
: '',
}
const blob = new Blob([new URLSearchParams(body).toString()], {
// This content type is necessary for `sendBeacon`:
type: 'application/x-www-form-urlencoded',
})
const vitalsUrl = 'https://vitals.vercel-insights.com/v1/vitals'
// Navigator has to be bound to ensure it does not error in some browsers
// https://xgwang.me/posts/you-may-not-know-beacon/#it-may-throw-error%2C-be-sure-to-catch
const send = navigator.sendBeacon && navigator.sendBeacon.bind(navigator)
function fallbackSend() {
fetch(vitalsUrl, {
body: blob,
method: 'POST',
credentials: 'omit',
keepalive: true,
// console.error is used here as when the fetch fails it does not affect functioning of the app
}).catch(console.error)
}
try {
// If send is undefined it'll throw as well. This reduces output code size.
send!(vitalsUrl, blob) || fallbackSend()
} catch (err) {
fallbackSend()
}
}
}
export default (onPerfEntry?: ReportCallback): void => {
// Update function if it changes:
userReportHandler = onPerfEntry
// Only register listeners once:
if (isRegistered) {
return
}
isRegistered = true
onCLS(onReport)
onFID(onReport)
onFCP(onReport)
onLCP(onReport)
onTTFB(onReport)
onINP(onReport)
}