UNPKG

7.97 kBJavaScriptView Raw
1this.workbox = this.workbox || {};
2this.workbox.googleAnalytics = (function (exports, Plugin_mjs, cacheNames_mjs, getFriendlyURL_mjs, logger_mjs, Route_mjs, Router_mjs, NetworkFirst_mjs, NetworkOnly_mjs) {
3 'use strict';
4
5 try {
6 self['workbox:google-analytics:4.3.0'] && _();
7 } catch (e) {} // eslint-disable-line
8
9 /*
10 Copyright 2018 Google LLC
11
12 Use of this source code is governed by an MIT-style
13 license that can be found in the LICENSE file or at
14 https://opensource.org/licenses/MIT.
15 */
16 const QUEUE_NAME = 'workbox-google-analytics';
17 const MAX_RETENTION_TIME = 60 * 48; // Two days in minutes
18
19 const GOOGLE_ANALYTICS_HOST = 'www.google-analytics.com';
20 const GTM_HOST = 'www.googletagmanager.com';
21 const ANALYTICS_JS_PATH = '/analytics.js';
22 const GTAG_JS_PATH = '/gtag/js';
23 const GTM_JS_PATH = '/gtm.js';
24 // endpoints. Most of the time the default path (/collect) is used, but
25 // occasionally an experimental endpoint is used when testing new features,
26 // (e.g. /r/collect or /j/collect)
27
28 const COLLECT_PATHS_REGEX = /^\/(\w+\/)?collect/;
29
30 /*
31 Copyright 2018 Google LLC
32
33 Use of this source code is governed by an MIT-style
34 license that can be found in the LICENSE file or at
35 https://opensource.org/licenses/MIT.
36 */
37 /**
38 * Creates the requestWillDequeue callback to be used with the background
39 * sync queue plugin. The callback takes the failed request and adds the
40 * `qt` param based on the current time, as well as applies any other
41 * user-defined hit modifications.
42 *
43 * @param {Object} config See workbox.googleAnalytics.initialize.
44 * @return {Function} The requestWillDequeu callback function.
45 *
46 * @private
47 */
48
49 const createOnSyncCallback = config => {
50 return async ({
51 queue
52 }) => {
53 let entry;
54
55 while (entry = await queue.shiftRequest()) {
56 const {
57 request,
58 timestamp
59 } = entry;
60 const url = new URL(request.url);
61
62 try {
63 // Measurement protocol requests can set their payload parameters in
64 // either the URL query string (for GET requests) or the POST body.
65 const params = request.method === 'POST' ? new URLSearchParams((await request.clone().text())) : url.searchParams; // Calculate the qt param, accounting for the fact that an existing
66 // qt param may be present and should be updated rather than replaced.
67
68 const originalHitTime = timestamp - (Number(params.get('qt')) || 0);
69 const queueTime = Date.now() - originalHitTime; // Set the qt param prior to applying hitFilter or parameterOverrides.
70
71 params.set('qt', queueTime); // Apply `paramterOverrideds`, if set.
72
73 if (config.parameterOverrides) {
74 for (const param of Object.keys(config.parameterOverrides)) {
75 const value = config.parameterOverrides[param];
76 params.set(param, value);
77 }
78 } // Apply `hitFilter`, if set.
79
80
81 if (typeof config.hitFilter === 'function') {
82 config.hitFilter.call(null, params);
83 } // Retry the fetch. Ignore URL search params from the URL as they're
84 // now in the post body.
85
86
87 await fetch(new Request(url.origin + url.pathname, {
88 body: params.toString(),
89 method: 'POST',
90 mode: 'cors',
91 credentials: 'omit',
92 headers: {
93 'Content-Type': 'text/plain'
94 }
95 }));
96
97 {
98 logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(url.href)}'` + `has been replayed`);
99 }
100 } catch (err) {
101 await queue.unshiftRequest(entry);
102
103 {
104 logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(url.href)}'` + `failed to replay, putting it back in the queue.`);
105 }
106
107 throw err;
108 }
109 }
110
111 {
112 logger_mjs.logger.log(`All Google Analytics request successfully replayed; ` + `the queue is now empty!`);
113 }
114 };
115 };
116 /**
117 * Creates GET and POST routes to catch failed Measurement Protocol hits.
118 *
119 * @param {Plugin} queuePlugin
120 * @return {Array<Route>} The created routes.
121 *
122 * @private
123 */
124
125
126 const createCollectRoutes = queuePlugin => {
127 const match = ({
128 url
129 }) => url.hostname === GOOGLE_ANALYTICS_HOST && COLLECT_PATHS_REGEX.test(url.pathname);
130
131 const handler = new NetworkOnly_mjs.NetworkOnly({
132 plugins: [queuePlugin]
133 });
134 return [new Route_mjs.Route(match, handler, 'GET'), new Route_mjs.Route(match, handler, 'POST')];
135 };
136 /**
137 * Creates a route with a network first strategy for the analytics.js script.
138 *
139 * @param {string} cacheName
140 * @return {Route} The created route.
141 *
142 * @private
143 */
144
145
146 const createAnalyticsJsRoute = cacheName => {
147 const match = ({
148 url
149 }) => url.hostname === GOOGLE_ANALYTICS_HOST && url.pathname === ANALYTICS_JS_PATH;
150
151 const handler = new NetworkFirst_mjs.NetworkFirst({
152 cacheName
153 });
154 return new Route_mjs.Route(match, handler, 'GET');
155 };
156 /**
157 * Creates a route with a network first strategy for the gtag.js script.
158 *
159 * @param {string} cacheName
160 * @return {Route} The created route.
161 *
162 * @private
163 */
164
165
166 const createGtagJsRoute = cacheName => {
167 const match = ({
168 url
169 }) => url.hostname === GTM_HOST && url.pathname === GTAG_JS_PATH;
170
171 const handler = new NetworkFirst_mjs.NetworkFirst({
172 cacheName
173 });
174 return new Route_mjs.Route(match, handler, 'GET');
175 };
176 /**
177 * Creates a route with a network first strategy for the gtm.js script.
178 *
179 * @param {string} cacheName
180 * @return {Route} The created route.
181 *
182 * @private
183 */
184
185
186 const createGtmJsRoute = cacheName => {
187 const match = ({
188 url
189 }) => url.hostname === GTM_HOST && url.pathname === GTM_JS_PATH;
190
191 const handler = new NetworkFirst_mjs.NetworkFirst({
192 cacheName
193 });
194 return new Route_mjs.Route(match, handler, 'GET');
195 };
196 /**
197 * @param {Object=} [options]
198 * @param {Object} [options.cacheName] The cache name to store and retrieve
199 * analytics.js. Defaults to the cache names provided by `workbox-core`.
200 * @param {Object} [options.parameterOverrides]
201 * [Measurement Protocol parameters](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters),
202 * expressed as key/value pairs, to be added to replayed Google Analytics
203 * requests. This can be used to, e.g., set a custom dimension indicating
204 * that the request was replayed.
205 * @param {Function} [options.hitFilter] A function that allows you to modify
206 * the hit parameters prior to replaying
207 * the hit. The function is invoked with the original hit's URLSearchParams
208 * object as its only argument.
209 *
210 * @memberof workbox.googleAnalytics
211 */
212
213
214 const initialize = (options = {}) => {
215 const cacheName = cacheNames_mjs.cacheNames.getGoogleAnalyticsName(options.cacheName);
216 const queuePlugin = new Plugin_mjs.Plugin(QUEUE_NAME, {
217 maxRetentionTime: MAX_RETENTION_TIME,
218 onSync: createOnSyncCallback(options)
219 });
220 const routes = [createGtmJsRoute(cacheName), createAnalyticsJsRoute(cacheName), createGtagJsRoute(cacheName), ...createCollectRoutes(queuePlugin)];
221 const router = new Router_mjs.Router();
222
223 for (const route of routes) {
224 router.registerRoute(route);
225 }
226
227 router.addFetchListener();
228 };
229
230 /*
231 Copyright 2018 Google LLC
232
233 Use of this source code is governed by an MIT-style
234 license that can be found in the LICENSE file or at
235 https://opensource.org/licenses/MIT.
236 */
237
238 exports.initialize = initialize;
239
240 return exports;
241
242}({}, workbox.backgroundSync, workbox.core._private, workbox.core._private, workbox.core._private, workbox.routing, workbox.routing, workbox.strategies, workbox.strategies));
243