-
Notifications
You must be signed in to change notification settings - Fork 0
/
gatsby-browser.tsx
165 lines (148 loc) · 4.73 KB
/
gatsby-browser.tsx
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import {
ShouldUpdateScrollArgs,
type RouteUpdateArgs,
type WrapPageElementBrowserArgs,
} from "gatsby";
import React, { type ReactElement } from "react";
import {
getCLS,
getFID,
getLCP,
getTTFB,
getFCP,
Metric,
ReportHandler,
} from "web-vitals";
import { Layout } from "./src/components/Layout/Layout";
// Gatsby hook for when the route has changed on the client side
// See https://www.gatsbyjs.org/docs/browser-apis/#onRouteUpdate
export const onRouteUpdate = ({
prevLocation,
location,
}: RouteUpdateArgs): void => {
if (prevLocation) {
// Cast is needed because of https://github.com/gatsbyjs/gatsby/issues/29124
const prevPath = (prevLocation as Location).pathname,
path = location.pathname;
// Push our own event to the dataLayer on page change rather than using the
// 'gatsby-route-change' event built into gatsby-plugin-google-tagmanager.
// Because gatsby-route-change is pushed on initial page load as well as route change,
// AND because it doesn't use requestAnimationFrame to delay until the page title has been updated
const sendPageView = () => {
window.dataLayer.push({
location: location.href,
referrer: prevLocation.href,
});
// Don't consider hash changes to be a page view - pageviews only happy when the path changes
if (prevPath != path) window.dataLayer.push({ event: "pageview" });
};
// Delay before push to the data layer, to make sure the page title has been updated
// See https://github.com/gatsbyjs/gatsby/pull/10917/files#diff-bf0d94c8bf47d5c1687e342c2dba1e00R12-R13
if ("requestAnimationFrame" in window) {
requestAnimationFrame(() => {
requestAnimationFrame(sendPageView);
});
} else {
// simulate 2 rAF calls
setTimeout(sendPageView, 32);
}
} else {
window.dataLayer.push({
location: location.href,
referrer: document.referrer,
});
}
};
/**
* Gatsby hook for overriding scroll position
* See https://www.gatsbyjs.org/docs/browser-apis/#shouldUpdateScroll
*/
export const shouldUpdateScroll = ({
routerProps: { location },
prevRouterProps,
getSavedScrollPosition,
}: ShouldUpdateScrollArgs): boolean | string | [number, number] => {
if (
// If there's no previous route props we're coming from an external site, which means
// we want to scroll to the hash (if there is one), and _not_ a saved scroll position
!prevRouterProps ||
// Or we're linking to as hash within the same page
(prevRouterProps.location.pathname === location.pathname && location.hash)
) {
// Provide our own scroll to hash to avoid Gatsby using a stored scroll position
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const targetElement = location.hash
? document.querySelector(location.hash)
: null;
if (targetElement) {
targetElement.setAttribute("tabIndex", "-1");
(targetElement as HTMLElement).focus();
targetElement.scrollIntoView();
}
});
});
return false;
}
const savedScrollY = (getSavedScrollPosition(location)?.[1] || 0) as number;
if (savedScrollY > 0) {
window.scrollTo(0, savedScrollY);
return false;
}
if (location.hash) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const targetElement = document.querySelector(location.hash);
// Default to Gatsby's default behaviour if the element doesn't exist
if (!targetElement) return true;
// Provide our own scroll to hash to avoid Gatsby using a stored scroll position
targetElement.setAttribute("tabIndex", "-1");
(targetElement as HTMLElement).focus();
targetElement.scrollIntoView();
});
});
return false;
}
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const contentStartElement = document.getElementById("content-start");
if (!contentStartElement) return true;
contentStartElement.setAttribute("tabIndex", "-1");
contentStartElement.focus();
contentStartElement.scrollIntoView();
});
});
// Default to scrolling to the content start element as the standard navigation behaviour
return false;
};
/**
* Gatsby hook for when the runtime first starts client side
* See https://www.gatsbyjs.com/docs/browser-apis#onClientEntry
*/
export const onClientEntry = (): void => {
getCLS(sendWebVitalToGTM);
getFCP(sendWebVitalToGTM);
getFID(sendWebVitalToGTM);
getLCP(sendWebVitalToGTM);
getTTFB(sendWebVitalToGTM);
};
const sendWebVitalToGTM: ReportHandler = ({
name,
delta,
id,
}: Metric): void => {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "web-vitals",
eventCategory: "Web Vitals",
eventAction: name,
eventLabel: id,
eventValue: Math.round(name === "CLS" ? delta * 1000 : delta),
});
};
export const wrapPageElement = ({
element,
props,
}: WrapPageElementBrowserArgs): ReactElement => (
<Layout {...props}>{element}</Layout>
);