@codecademy/tracking 1.0.36-alpha.14a4697e2e.0 → 1.0.36-alpha.28eb0ac54d.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,8 @@
1
1
  import { initializeGTM } from './gtm';
2
2
  import { initializeOneTrust } from './onetrust';
3
+ import { initializePartytown } from './partytown';
4
+ let init = false; // For preventing multiple initializations
5
+
3
6
  /**
4
7
  * @see README.md for details and usage.
5
8
  */
@@ -9,17 +12,25 @@ export const initializeTrackingIntegrations = async _ref => {
9
12
  optedOutExternalTracking = _ref.optedOutExternalTracking,
10
13
  oneTrustScript = _ref.oneTrustScript,
11
14
  partytown = _ref.partytown;
12
- // 1. Wait to allow any other post-hydration logic to run first (not as critical when using partytown)
13
- await new Promise(resolve => setTimeout(resolve, partytown ? 100 : 1000));
15
+ if (init) {
16
+ return;
17
+ }
18
+ init = true;
19
+ if (partytown) {
20
+ initializePartytown();
21
+ } else {
22
+ // Wait to allow any other post-hydration logic to run first
23
+ await new Promise(resolve => setTimeout(resolve, 1000));
24
+ }
14
25
 
15
- // 2. Load in OneTrust's banner and wait for its `OptanonWrapper` callback
26
+ // Load in OneTrust's banner and wait for its `OptanonWrapper` callback
16
27
  await initializeOneTrust({
17
28
  scope,
18
29
  environment,
19
30
  scriptId: oneTrustScript
20
31
  });
21
32
 
22
- // 3. Load GTM
33
+ // Load GTM
23
34
  initializeGTM({
24
35
  scope,
25
36
  environment,
@@ -0,0 +1 @@
1
+ export declare function initializePartytown(): void;
@@ -0,0 +1,74 @@
1
+ import { partytownSnippet } from '@builder.io/partytown/integration';
2
+ const ptConfig = () => ({
3
+ forward: ['dataLayer.push',
4
+ // for GTM
5
+ 'fbq',
6
+ // for Facebook Pixel
7
+ '_hsq.push' // for Hubspot
8
+ ],
9
+ lib: '/partytown/',
10
+ logScriptExecution: true,
11
+ loadScriptsOnMainThread: [/googleads/, /bing/, /pepperjam/, /snap/, /lightboxcdn/],
12
+ resolveUrl(url, location, type) {
13
+ /*
14
+ * This function runs in a worker and cannot access vars that might seem
15
+ * in scope in this file.
16
+ */
17
+
18
+ if (url.hostname === 'www.googletagmanager.com' && type === 'iframe') {
19
+ /*
20
+ * GTM tries to create an iframe that loads a script to create a GTM
21
+ * service worker. When scripts within Partytown try to create an iframe,
22
+ * Partytown's proxy behavior is to make the request for the iframe src
23
+ * using fetch from a worker. This is typically better than normal iframe
24
+ * loading behavior because it keeps the request off the main thread.
25
+ * However, fetch in a worker is more strict about cors than requests
26
+ * natively made by iframe elements. A fetch for this particular iframe
27
+ * src would fail becuase Google does not include a cors response header.
28
+ * In some cases with Partytown, we might work around this with a reverse
29
+ * proxy, but that also doesn't work in this case because the GTM code in
30
+ * this iframe needs to create a service worker within an iframe that has
31
+ * a certain origin. The alternate workaround here is to effectively
32
+ * block Partytown when it tries to resolve the iframe url and to send
33
+ * that url back to the main thread (via BroadcastChannel) so that a
34
+ * regular iframe can be created, just as GTM would have normally done.
35
+ */
36
+ new BroadcastChannel('gtm-iframe').postMessage(url.href);
37
+ return new URL('', 'http:.');
38
+ }
39
+ if (url.hostname === 'connect.facebook.net') {
40
+ /*
41
+ * Proxy Pacebook Pixel requests to resolve cors issues
42
+ * see https://partytown.builder.io/facebook-pixel#proxy-requests
43
+ */
44
+ return new URL(`partytown-fb${url.pathname}${url.search}`, location.origin);
45
+ }
46
+ return url;
47
+ }
48
+ });
49
+ const encapsulate = js => `(() => {${js}})();`;
50
+ export function initializePartytown() {
51
+ new BroadcastChannel('gtm-iframe').onmessage = _ref => {
52
+ let iframeSrc = _ref.data;
53
+ // This 2 layer approach matches the way GTM would try to setup the iframe.
54
+ const outer = hiddenIframe(document);
55
+ document.body.appendChild(outer);
56
+ const inner = hiddenIframe(outer.contentWindow.document, iframeSrc);
57
+ outer.appendChild(inner);
58
+ };
59
+ const ptScript = document.createElement('script');
60
+ // encapsulation is necessary to avoid collision of global minified vars
61
+ ptScript.innerHTML = encapsulate(partytownSnippet(ptConfig()));
62
+ document.head.appendChild(ptScript);
63
+ }
64
+ function hiddenIframe(d, src) {
65
+ const iframe = d.createElement('iframe');
66
+ // These attributes match what GTM would use when it creates an iframe.
67
+ iframe.height = '0';
68
+ iframe.width = '0';
69
+ iframe.setAttribute('style', 'display: none; visibility: hidden;');
70
+ if (src) {
71
+ iframe.src = src;
72
+ }
73
+ return iframe;
74
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codecademy/tracking",
3
3
  "description": "Tracking library for Codecademy",
4
- "version": "1.0.36-alpha.14a4697e2e.0",
4
+ "version": "1.0.36-alpha.28eb0ac54d.0",
5
5
  "author": "Codecademy Engineering <dev@codecademy.com>",
6
6
  "files": [
7
7
  "dist/**"
@@ -13,5 +13,5 @@
13
13
  "access": "public"
14
14
  },
15
15
  "repository": "git@github.com:codecademy-engineering/mono.git",
16
- "gitHead": "77fa7f8fb87c1f5543a976166d7764b962fd5c23"
16
+ "gitHead": "da642417f43efaad84a791ea16daac85c3330732"
17
17
  }