UNPKG

9.98 kBJavaScriptView Raw
1this.workbox = this.workbox || {};
2this.workbox.googleAnalytics = (function (exports,Plugin_mjs,cacheNames_mjs,Route_mjs,Router_mjs,NetworkFirst_mjs,NetworkOnly_mjs) {
3 'use strict';
4
5 try {
6 self.workbox.v['workbox:google-analytics:3.6.2'] = 1;
7 } catch (e) {} // eslint-disable-line
8
9 /*
10 Copyright 2017 Google Inc. All Rights Reserved.
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 const QUEUE_NAME = 'workbox-google-analytics';
25 const MAX_RETENTION_TIME = 60 * 48; // Two days in minutes
26 const GOOGLE_ANALYTICS_HOST = 'www.google-analytics.com';
27 const GTM_HOST = 'www.googletagmanager.com';
28 const ANALYTICS_JS_PATH = '/analytics.js';
29 const GTAG_JS_PATH = '/gtag/js';
30
31 // This RegExp matches all known Measurement Protocol single-hit collect
32 // endpoints. Most of the time the default path (/collect) is used, but
33 // occasionally an experimental endpoint is used when testing new features,
34 // (e.g. /r/collect or /j/collect)
35 const COLLECT_PATHS_REGEX = /^\/(\w+\/)?collect/;
36
37 /*
38 Copyright 2017 Google Inc. All Rights Reserved.
39 Licensed under the Apache License, Version 2.0 (the "License");
40 you may not use this file except in compliance with the License.
41 You may obtain a copy of the License at
42
43 http://www.apache.org/licenses/LICENSE-2.0
44
45 Unless required by applicable law or agreed to in writing, software
46 distributed under the License is distributed on an "AS IS" BASIS,
47 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
48 See the License for the specific language governing permissions and
49 limitations under the License.
50 */
51
52 /**
53 * Promisifies the FileReader API to await a text response from a Blob.
54 *
55 * @param {Blob} blob
56 * @return {Promise<string>}
57 *
58 * @private
59 */
60 const getTextFromBlob = (() => {
61 var _ref = babelHelpers.asyncToGenerator(function* (blob) {
62 // This usage of `return await new Promise...` is intentional to work around
63 // a bug in the transpiled/minified output.
64 // See https://github.com/GoogleChrome/workbox/issues/1186
65 return yield new Promise(function (resolve, reject) {
66 const reader = new FileReader();
67 reader.onloadend = function () {
68 return resolve(reader.result);
69 };
70 reader.onerror = function () {
71 return reject(reader.error);
72 };
73 reader.readAsText(blob);
74 });
75 });
76
77 return function getTextFromBlob(_x) {
78 return _ref.apply(this, arguments);
79 };
80 })();
81
82 /**
83 * Creates the requestWillDequeue callback to be used with the background
84 * sync queue plugin. The callback takes the failed request and adds the
85 * `qt` param based on the current time, as well as applies any other
86 * user-defined hit modifications.
87 *
88 * @param {Object} config See workbox.googleAnalytics.initialize.
89 * @return {Function} The requestWillDequeu callback function.
90 *
91 * @private
92 */
93 const createRequestWillReplayCallback = config => {
94 return (() => {
95 var _ref2 = babelHelpers.asyncToGenerator(function* (storableRequest) {
96 let { url, requestInit, timestamp } = storableRequest;
97 url = new URL(url);
98
99 // Measurement protocol requests can set their payload parameters in either
100 // the URL query string (for GET requests) or the POST body.
101 let params;
102 if (requestInit.body) {
103 const payload = requestInit.body instanceof Blob ? yield getTextFromBlob(requestInit.body) : requestInit.body;
104
105 params = new URLSearchParams(payload);
106 } else {
107 params = url.searchParams;
108 }
109
110 // Calculate the qt param, accounting for the fact that an existing
111 // qt param may be present and should be updated rather than replaced.
112 const originalHitTime = timestamp - (Number(params.get('qt')) || 0);
113 const queueTime = Date.now() - originalHitTime;
114
115 // Set the qt param prior to applying the hitFilter or parameterOverrides.
116 params.set('qt', queueTime);
117
118 if (config.parameterOverrides) {
119 for (const param of Object.keys(config.parameterOverrides)) {
120 const value = config.parameterOverrides[param];
121 params.set(param, value);
122 }
123 }
124
125 if (typeof config.hitFilter === 'function') {
126 config.hitFilter.call(null, params);
127 }
128
129 requestInit.body = params.toString();
130 requestInit.method = 'POST';
131 requestInit.mode = 'cors';
132 requestInit.credentials = 'omit';
133 requestInit.headers = { 'Content-Type': 'text/plain' };
134
135 // Ignore URL search params as they're now in the post body.
136 storableRequest.url = `${url.origin}${url.pathname}`;
137 });
138
139 return function (_x2) {
140 return _ref2.apply(this, arguments);
141 };
142 })();
143 };
144
145 /**
146 * Creates GET and POST routes to catch failed Measurement Protocol hits.
147 *
148 * @param {Plugin} queuePlugin
149 * @return {Array<Route>} The created routes.
150 *
151 * @private
152 */
153 const createCollectRoutes = queuePlugin => {
154 const match = ({ url }) => url.hostname === GOOGLE_ANALYTICS_HOST && COLLECT_PATHS_REGEX.test(url.pathname);
155
156 const handler = new NetworkOnly_mjs.NetworkOnly({
157 plugins: [queuePlugin]
158 });
159
160 return [new Route_mjs.Route(match, handler, 'GET'), new Route_mjs.Route(match, handler, 'POST')];
161 };
162
163 /**
164 * Creates a route with a network first strategy for the analytics.js script.
165 *
166 * @param {string} cacheName
167 * @return {Route} The created route.
168 *
169 * @private
170 */
171 const createAnalyticsJsRoute = cacheName => {
172 const match = ({ url }) => url.hostname === GOOGLE_ANALYTICS_HOST && url.pathname === ANALYTICS_JS_PATH;
173 const handler = new NetworkFirst_mjs.NetworkFirst({ cacheName });
174
175 return new Route_mjs.Route(match, handler, 'GET');
176 };
177
178 /**
179 * Creates a route with a network first strategy for the gtag.js script.
180 *
181 * @param {string} cacheName
182 * @return {Route} The created route.
183 *
184 * @private
185 */
186 const createGtagJsRoute = cacheName => {
187 const match = ({ url }) => url.hostname === GTM_HOST && url.pathname === GTAG_JS_PATH;
188 const handler = new NetworkFirst_mjs.NetworkFirst({ cacheName });
189
190 return new Route_mjs.Route(match, handler, 'GET');
191 };
192
193 /**
194 * @param {Object=} [options]
195 * @param {Object} [options.cacheName] The cache name to store and retrieve
196 * analytics.js. Defaults to the cache names provided by `workbox-core`.
197 * @param {Object} [options.parameterOverrides]
198 * [Measurement Protocol parameters](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters),
199 * expressed as key/value pairs, to be added to replayed Google Analytics
200 * requests. This can be used to, e.g., set a custom dimension indicating
201 * that the request was replayed.
202 * @param {Function} [options.hitFilter] A function that allows you to modify
203 * the hit parameters prior to replaying
204 * the hit. The function is invoked with the original hit's URLSearchParams
205 * object as its only argument.
206 *
207 * @memberof workbox.googleAnalytics
208 */
209 const initialize = (options = {}) => {
210 const cacheName = cacheNames_mjs.cacheNames.getGoogleAnalyticsName(options.cacheName);
211
212 const queuePlugin = new Plugin_mjs.Plugin(QUEUE_NAME, {
213 maxRetentionTime: MAX_RETENTION_TIME,
214 callbacks: {
215 requestWillReplay: createRequestWillReplayCallback(options)
216 }
217 });
218
219 const routes = [createAnalyticsJsRoute(cacheName), createGtagJsRoute(cacheName), ...createCollectRoutes(queuePlugin)];
220
221 const router = new Router_mjs.Router();
222 for (const route of routes) {
223 router.registerRoute(route);
224 }
225
226 self.addEventListener('fetch', evt => {
227 const responsePromise = router.handleRequest(evt);
228 if (responsePromise) {
229 evt.respondWith(responsePromise);
230 }
231 });
232 };
233
234 /*
235 Copyright 2017 Google Inc. All Rights Reserved.
236 Licensed under the Apache License, Version 2.0 (the "License");
237 you may not use this file except in compliance with the License.
238 You may obtain a copy of the License at
239
240 http://www.apache.org/licenses/LICENSE-2.0
241
242 Unless required by applicable law or agreed to in writing, software
243 distributed under the License is distributed on an "AS IS" BASIS,
244 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
245 See the License for the specific language governing permissions and
246 limitations under the License.
247 */
248
249 exports.initialize = initialize;
250
251 return exports;
252
253}({},workbox.backgroundSync,workbox.core._private,workbox.routing,workbox.routing,workbox.strategies,workbox.strategies));
254
255//# sourceMappingURL=workbox-google-analytics.dev.js.map