From 1b4cb28529198cbdf9f920eb14ef5eae22e56ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Mon, 19 Sep 2022 09:36:11 +0200 Subject: [PATCH] Send web vitals to Vercel analytics --- packages/next/client/app-index.tsx | 6 ++++ packages/next/client/performance-relayer.ts | 2 +- test/e2e/app-dir/index.test.ts | 37 +++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/next/client/app-index.tsx b/packages/next/client/app-index.tsx index fa475942a2f963b..552b2c00f739887 100644 --- a/packages/next/client/app-index.tsx +++ b/packages/next/client/app-index.tsx @@ -5,6 +5,8 @@ import ReactDOMClient from 'react-dom/client' import React from 'react' import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack' +import measureWebVitals from './performance-relayer' + /// // Override chunk URL mapping in the webpack runtime @@ -151,6 +153,10 @@ function ServerRoot({ cacheKey }: { cacheKey: string }) { } function Root({ children }: React.PropsWithChildren<{}>): React.ReactElement { + React.useEffect(() => { + measureWebVitals() + }, []) + if (process.env.__NEXT_TEST_MODE) { // eslint-disable-next-line react-hooks/rules-of-hooks React.useEffect(() => { diff --git a/packages/next/client/performance-relayer.ts b/packages/next/client/performance-relayer.ts index c1d87fed8784bfd..685b9289c78a2f3 100644 --- a/packages/next/client/performance-relayer.ts +++ b/packages/next/client/performance-relayer.ts @@ -32,7 +32,7 @@ function onReport(metric: Metric): void { const body: Record = { dsn: process.env.__NEXT_ANALYTICS_ID, id: metric.id, - page: window.__NEXT_DATA__.page, + page: window.__NEXT_DATA__?.page, href: initialHref, event_name: metric.name, value: metric.value.toString(), diff --git a/test/e2e/app-dir/index.test.ts b/test/e2e/app-dir/index.test.ts index 5d62435fb27d0c2..fcc5c80c7adeac3 100644 --- a/test/e2e/app-dir/index.test.ts +++ b/test/e2e/app-dir/index.test.ts @@ -29,6 +29,9 @@ describe('app dir', () => { 'react-dom': 'experimental', }, skipStart: true, + env: { + VERCEL_ANALYTICS_ID: 'fake-analytics-id', + }, }) if (assetPrefix) { @@ -1454,6 +1457,40 @@ describe('app dir', () => { }) }) + // Analytics events are only sent in production + ;(isDev ? describe.skip : describe)('Vercel analytics', () => { + it('should send web vitals to Vercel analytics', async () => { + let eventsCount = 0 + let countEvents = false + const browser = await webdriver(next.url, '/client-nested', { + beforePageLoad(page) { + page.route( + 'https://vitals.vercel-insights.com/v1/vitals', + (route) => { + if (countEvents) { + eventsCount += 1 + } + + route.fulfill() + } + ) + }, + }) + + // Start counting analytics events + countEvents = true + + // Refresh will trigger CLS and LCP. When page loads FCP and TTFB will trigger: + await browser.refresh() + + // After interaction LCP and FID will trigger + await browser.elementByCss('button').click() + + // Make sure all registered events in performance-relayer has fired + await check(() => eventsCount, /6/) + }) + }) + describe('known bugs', () => { it('should not share flight data between requests', async () => { const fetches = await Promise.all(