diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx index 73c8136efde6..43fae5b351d4 100644 --- a/packages/next/client/index.tsx +++ b/packages/next/client/index.tsx @@ -743,9 +743,7 @@ function Root({ // We should ask to measure the Web Vitals after rendering completes so we // don't cause any hydration delay: React.useEffect(() => { - if (onPerfEntry) { - measureWebVitals(onPerfEntry) - } + measureWebVitals(onPerfEntry) }, []) return children as React.ReactElement } diff --git a/packages/next/client/performance-relayer.ts b/packages/next/client/performance-relayer.ts index f1b43fa7e10e..1a2dfe1cb899 100644 --- a/packages/next/client/performance-relayer.ts +++ b/packages/next/client/performance-relayer.ts @@ -4,13 +4,32 @@ import { getFID, getLCP, getTTFB, + Metric, ReportHandler, } from 'web-vitals' -export default (onPerfEntry: ReportHandler) => { - getCLS(onPerfEntry) - getFID(onPerfEntry) - getFCP(onPerfEntry) - getLCP(onPerfEntry) - getTTFB(onPerfEntry) +let isRegistered = false +let userReportHandler: ReportHandler | undefined + +function onReport(metric: Metric) { + if (userReportHandler) { + userReportHandler(metric) + } +} + +export default (onPerfEntry?: ReportHandler) => { + // Update function if it changes: + userReportHandler = onPerfEntry + + // Only register listeners once: + if (isRegistered) { + return + } + isRegistered = true + + getCLS(onReport) + getFID(onReport) + getFCP(onReport) + getLCP(onReport) + getTTFB(onReport) }