From c094ecc796ca685f3816cc567efd195e4315da92 Mon Sep 17 00:00:00 2001 From: Helen Lin Date: Tue, 9 Jul 2024 15:24:14 -0700 Subject: [PATCH] Perfkit (#2268) * add perfkit * add spa mode * working perfkit * format * format * fix test * Fix test * set up perfkit in test * address errors * guard perfkit * pinned perfkit version --- .../AnalyticsProvider.test.tsx | 14 ++++- .../analytics-manager/AnalyticsProvider.tsx | 2 + .../src/analytics-manager/PerfKit.tsx | 60 +++++++++++++++++++ packages/hydrogen/vitest.setup.ts | 5 ++ 4 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 packages/hydrogen/src/analytics-manager/PerfKit.tsx diff --git a/packages/hydrogen/src/analytics-manager/AnalyticsProvider.test.tsx b/packages/hydrogen/src/analytics-manager/AnalyticsProvider.test.tsx index 2ff514b15f..589bedba60 100644 --- a/packages/hydrogen/src/analytics-manager/AnalyticsProvider.test.tsx +++ b/packages/hydrogen/src/analytics-manager/AnalyticsProvider.test.tsx @@ -308,9 +308,11 @@ function triggerCartUpdate({ }); } -function customerPrivacyReady() { - const event = new CustomEvent('visitorConsentCollected'); - document.dispatchEvent(event); +function mockPerfKit() { + window.PerfKit = { + navigate: () => {}, + setPageType: () => {}, + }; } function LoopAnalytics({ @@ -325,8 +327,13 @@ function LoopAnalytics({ }): JSX.Element { const analytics = useAnalytics(); const {ready} = analytics.register('loopAnalytics'); + const {ready: customerPrivacyReady} = analytics.register( + 'Internal_Shopify_CustomerPrivacy', + ); + const {ready: perfKitReady} = analytics.register('Internal_Shopify_Perf_Kit'); useEffect(() => { + mockPerfKit(); if (registerCallback) { registerCallback(analytics, ready); } else { @@ -335,6 +342,7 @@ function LoopAnalytics({ }); customerPrivacyReady(); + perfKitReady(); return (
{typeof children === 'function' ? children(analytics) : children}
diff --git a/packages/hydrogen/src/analytics-manager/AnalyticsProvider.tsx b/packages/hydrogen/src/analytics-manager/AnalyticsProvider.tsx index 29e853fa3d..bce0684aef 100644 --- a/packages/hydrogen/src/analytics-manager/AnalyticsProvider.tsx +++ b/packages/hydrogen/src/analytics-manager/AnalyticsProvider.tsx @@ -37,6 +37,7 @@ import {ShopifyAnalytics} from './ShopifyAnalytics'; import {CartAnalytics} from './CartAnalytics'; import type {CustomerPrivacyApiProps} from '../customer-privacy/ShopifyCustomerPrivacy'; import type {Storefront} from '../storefront'; +import {PerfKit} from './PerfKit'; import {errorOnce, warnOnce} from '../utils/warning'; export type ShopAnalytics = { @@ -359,6 +360,7 @@ function AnalyticsProvider({ domain={cookieDomain} /> )} + {!!shop && } ); } diff --git a/packages/hydrogen/src/analytics-manager/PerfKit.tsx b/packages/hydrogen/src/analytics-manager/PerfKit.tsx new file mode 100644 index 0000000000..d8767c41a3 --- /dev/null +++ b/packages/hydrogen/src/analytics-manager/PerfKit.tsx @@ -0,0 +1,60 @@ +import {parseGid, useLoadScript} from '@shopify/hydrogen-react'; +import {ShopAnalytics, useAnalytics} from './AnalyticsProvider'; +import {AnalyticsEvent} from './events'; +import {useEffect, useRef} from 'react'; + +declare global { + interface Window { + PerfKit: { + navigate: () => void; + setPageType: (pageType: string) => void; + }; + } +} + +// Pin to a version that have SPA support. +// TODO: Update to a stable version when available. +const PERF_KIT_UNSTABLE = + 'https://cdn.shopify.com/shopifycloud/perf-kit/shopify-perf-kit-1bd852a.min.js'; + +export function PerfKit({shop}: {shop: ShopAnalytics}) { + const loadedEvent = useRef(false); + const {subscribe, register} = useAnalytics(); + const {ready} = register('Internal_Shopify_Perf_Kit'); + + const scriptStatus = useLoadScript(PERF_KIT_UNSTABLE, { + attributes: { + id: 'perfkit', + 'data-application': 'hydrogen', + 'data-shop-id': parseGid(shop.shopId).id.toString(), + 'data-storefront-id': shop.hydrogenSubchannelId, + 'data-monorail-region': 'global', + 'data-spa-mode': 'true', + 'data-resource-timing-sampling-rate': '100', + }, + }); + + useEffect(() => { + if (scriptStatus !== 'done' || loadedEvent.current) return; + loadedEvent.current = true; + + subscribe(AnalyticsEvent.PAGE_VIEWED, () => { + window.PerfKit?.navigate(); + }); + subscribe(AnalyticsEvent.PRODUCT_VIEWED, () => { + window.PerfKit?.setPageType('product'); + }); + subscribe(AnalyticsEvent.COLLECTION_VIEWED, () => { + window.PerfKit?.setPageType('collection'); + }); + subscribe(AnalyticsEvent.SEARCH_VIEWED, () => { + window.PerfKit?.setPageType('search'); + }); + subscribe(AnalyticsEvent.CART_VIEWED, () => { + window.PerfKit?.setPageType('cart'); + }); + + ready(); + }, [subscribe, ready, scriptStatus]); + return null; +} diff --git a/packages/hydrogen/vitest.setup.ts b/packages/hydrogen/vitest.setup.ts index e06e481853..86629772de 100644 --- a/packages/hydrogen/vitest.setup.ts +++ b/packages/hydrogen/vitest.setup.ts @@ -3,3 +3,8 @@ import matchers from '@testing-library/jest-dom/matchers'; import {expect} from 'vitest'; expect.extend(matchers); + +// Defining `document.currentScript` to avoid errors in tests +Object.defineProperty(document, 'currentScript', { + value: document.createElement('script'), +});