@speedkit/cli 2.48.0 → 2.49.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [2.49.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v2.48.0...v2.49.0) (2024-07-26)
2
+
3
+
4
+ ### Features
5
+
6
+ * **customer-config:** add soft navigation tracking ([e473277](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/e4732778c3a33046b2d602743b22b8e3e4e8ec73))
7
+
1
8
  # [2.48.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v2.47.1...v2.48.0) (2024-07-26)
2
9
 
3
10
 
package/README.md CHANGED
@@ -21,7 +21,7 @@ $ npm install -g @speedkit/cli
21
21
  $ sk COMMAND
22
22
  running command...
23
23
  $ sk (--version)
24
- @speedkit/cli/2.48.0 linux-x64 node-v20.16.0
24
+ @speedkit/cli/2.49.0 linux-x64 node-v20.16.0
25
25
  $ sk --help [COMMAND]
26
26
  USAGE
27
27
  $ sk COMMAND
@@ -35,6 +35,7 @@ export interface CustomerConfigSettings {
35
35
  useScrapingBee?: boolean;
36
36
  withGoogleOptimize?: boolean;
37
37
  activateCfRocketLoaderWorkaround?: boolean;
38
+ hasSoftNavigations?: boolean;
38
39
  isShopify?: boolean;
39
40
  isShopware?: boolean;
40
41
  isSalesforce?: boolean;
@@ -161,7 +161,7 @@ class CustomerConfigService {
161
161
  }
162
162
  }
163
163
  async getConfigSettings() {
164
- let { production, staging, subRouteScope, includeServiceWorker, activateImageOptimisation, removeLazyLoading, addPreRendering, supportShadowDomInPreRendering, shadowDomCustomElementPrefix, activateRumTracking, useGATracking, useScrapingBee, withGoogleOptimize, activateCfRocketLoaderWorkaround, isShopify, isShopware, isSalesforce, isPlentymarkets, shopifyId, } = {};
164
+ let { production, staging, subRouteScope, includeServiceWorker, activateImageOptimisation, removeLazyLoading, addPreRendering, supportShadowDomInPreRendering, shadowDomCustomElementPrefix, activateRumTracking, useGATracking, useScrapingBee, withGoogleOptimize, activateCfRocketLoaderWorkaround, hasSoftNavigations, isShopify, isShopware, isSalesforce, isPlentymarkets, shopifyId, } = {};
165
165
  this.appName = await this.cli.prompt(`Enter SK App Name:`, {
166
166
  validator: (input) => /^[\da-z]+(?:-[\da-z]+)*$/.test(input) ? "" : "No valid kebab-case",
167
167
  defaultAnswer: this.appName,
@@ -216,8 +216,11 @@ class CustomerConfigService {
216
216
  }
217
217
  useScrapingBee = await this.cli.confirm("Do customer responses differ geo-location-based (ScrapingBee will be needed to fetch documents)?", false);
218
218
  activateRumTracking = await this.cli.confirm("Activate RUM Tracking?");
219
- if (activateRumTracking && !isShopify) {
220
- useGATracking = await this.cli.confirm("Add Tracking based on Google Analytics' DataLayer?");
219
+ if (activateRumTracking) {
220
+ if (!isShopify) {
221
+ useGATracking = await this.cli.confirm("Add Tracking based on Google Analytics' DataLayer?");
222
+ }
223
+ hasSoftNavigations = await this.cli.confirm("Add Tracking for Soft Navigations?", false);
221
224
  }
222
225
  withGoogleOptimize = await this.cli.confirm("Is Google Optimize being used?", false);
223
226
  activateCfRocketLoaderWorkaround = isShopify
@@ -239,6 +242,7 @@ class CustomerConfigService {
239
242
  useScrapingBee,
240
243
  withGoogleOptimize,
241
244
  activateCfRocketLoaderWorkaround,
245
+ hasSoftNavigations,
242
246
  isShopify,
243
247
  isShopware,
244
248
  isSalesforce,
@@ -1,4 +1,7 @@
1
1
  import { BaseBundle } from 'rum/BaseBundle';
2
+ {{#if hasSoftNavigations}}
3
+ import { HistoryApiPlugin } from 'rum/HistoryApiPlugin';
4
+ {{/if}}
2
5
  {{#if useGATracking}}
3
6
  import { GAEcommerceTrackingPlugin } from 'rum/GAEcommerceTrackingPlugin';
4
7
  {{/if}}
@@ -7,69 +10,76 @@ import { GAEcommerceTrackingPlugin } from 'rum/GAEcommerceTrackingPlugin';
7
10
  if (window !== window.top) {
8
11
  return;
9
12
  }
13
+ {{#if hasSoftNavigations}}
14
+
15
+ var softLcpPending = false;
16
+ var latestUrl = location.href;
17
+ {{/if}}
10
18
 
11
19
  window.SpeedKit = window.SpeedKit || {};
12
20
  SpeedKit.rumPlugins = SpeedKit.rumPlugins || [];
13
21
  SpeedKit.rumPlugins.push(
14
22
  new BaseBundle(),
23
+ {{#if hasSoftNavigations}}
24
+ new HistoryApiPlugin(), // Soft Navigation Tracking using History API
25
+ {{/if}}
15
26
  {{#if useGATracking}}
16
27
  new GAEcommerceTrackingPlugin(),
17
28
  {{/if}}
18
29
 
19
30
  {{#if addPreRendering}}
20
- {
21
- key: "isPreRendered",
22
- type: "PiDimension",
23
- on: "load",
24
- set: function () {
25
- return !!document.querySelector(".speed-kit-pre-rendered");
31
+ {
32
+ key: "isPreRendered",
33
+ type: "PiDimension",
34
+ on: "load",
35
+ set: function () {
36
+ return !!document.querySelector(".speed-kit-pre-rendered");
37
+ },
26
38
  },
27
- },
28
- {
29
- on: onPrerenderReady,
30
- track: function (controller, custom, event) {
31
- var measure = performance.measure("sk-prerender-observe-runtime", {
32
- start: "sk-prerender-observe-start",
33
- end: "sk-prerender-observe-end",
34
- });
35
- var timing = {
36
- start: measure.startTime,
37
- duration: measure.duration,
38
- url: window.location.href,
39
- element: event?.detail?.element,
40
- };
41
- controller.trackCustomEvent(
42
- "skPrerenderReady",
43
- JSON.stringify(timing),
44
- timing.duration,
45
- );
39
+ {
40
+ on: onPrerenderReady,
41
+ track: function (controller, custom, event) {
42
+ var measure = performance.measure("sk-prerender-observe-runtime", {
43
+ start: "sk-prerender-observe-start",
44
+ end: "sk-prerender-observe-end",
45
+ });
46
+ var timing = {
47
+ start: measure.startTime,
48
+ duration: measure.duration,
49
+ url: window.location.href,
50
+ element: event?.detail?.element,
51
+ };
52
+ controller.trackCustomEvent(
53
+ "skPrerenderReady",
54
+ JSON.stringify(timing),
55
+ timing.duration,
56
+ );
57
+ },
46
58
  },
47
- },
48
- {
49
- on: onPrerenderReady,
50
- track: function (controller) {
51
- var measure = performance.measure(
52
- "sk-prerender-observe-change-detection",
53
- {
54
- start: "sk-prerender-change-detection-start",
55
- end: "sk-prerender-change-detection-end",
56
- },
57
- );
58
- var timing = {
59
- start: measure.startTime,
60
- duration: measure.duration,
61
- url: window.location.href,
62
- };
63
-
64
- controller.trackCustomEvent(
65
- "skPrerenderChangeDetection",
66
- JSON.stringify(timing),
67
- timing.duration,
68
- );
59
+ {
60
+ on: onPrerenderReady,
61
+ track: function (controller) {
62
+ var measure = performance.measure(
63
+ "sk-prerender-observe-change-detection",
64
+ {
65
+ start: "sk-prerender-change-detection-start",
66
+ end: "sk-prerender-change-detection-end",
67
+ },
68
+ );
69
+ var timing = {
70
+ start: measure.startTime,
71
+ duration: measure.duration,
72
+ url: window.location.href,
73
+ };
74
+
75
+ controller.trackCustomEvent(
76
+ "skPrerenderChangeDetection",
77
+ JSON.stringify(timing),
78
+ timing.duration,
79
+ );
80
+ },
69
81
  },
70
- },
71
82
  {{/if}}
72
-
73
83
  {
74
84
  key: 'language',
75
85
  type: 'SessionDimension',
@@ -312,6 +322,93 @@ import { GAEcommerceTrackingPlugin } from 'rum/GAEcommerceTrackingPlugin';
312
322
  },
313
323
  },
314
324
  {{/if}}
325
+ {{/if}}
326
+ {{#if hasSoftNavigations}}
327
+ {
328
+ on: "softNavigation",
329
+ track: (controller) => {
330
+ var onlyHashChanged =
331
+ latestUrl.split("#")[0] === location.href.split("#")[0];
332
+ latestUrl = location.href;
333
+
334
+ if (onlyHashChanged) {
335
+ controller.trackCustomEvent("hashChanged", location.href, Date.now());
336
+ return;
337
+ }
338
+
339
+ controller.trackCustomEvent("softNav", location.href, Date.now());
340
+ var navStartMark = "soft-nav_" + location.pathname;
341
+ performance.mark(navStartMark);
342
+
343
+ // Only capture soft LCP on following pages/page types:
344
+ // * <add>
345
+ // TODO: update list
346
+
347
+ // TODO: update exemplary url pattern to match pages/page types to capture
348
+ if (location.href.indexOf("/p/")) {
349
+ softLcpPending = true;
350
+ }
351
+
352
+ var softNavigationPerformanceObserver = new PerformanceObserver(
353
+ (entries, observer) => {
354
+ // TODO: update exemplary selectors within this block
355
+
356
+ if (!document.querySelector(".productBasicInfo")) {
357
+ return;
358
+ }
359
+
360
+ var imageEntries = Array.from(entries.getEntries()).filter(
361
+ (item) =>
362
+ item.name.indexOf("/img/produkte/") > -1 &&
363
+ item.name.indexOf("/img/produkte/15_") === -1,
364
+ );
365
+ if (!imageEntries || imageEntries.length < 1) {
366
+ return;
367
+ }
368
+
369
+ var element = document.querySelector(
370
+ ".productBasicInfo .carousel__img-wrapper img",
371
+ );
372
+ if (!element) {
373
+ return;
374
+ }
375
+ var imageUrl = element.currentSrc || element.srcset || "";
376
+
377
+ var image = imageEntries.filter((entry) => {
378
+ var urlObj = new URL(entry.name);
379
+ return imageUrl.indexOf(urlObj.pathname) > -1;
380
+ })[0];
381
+ if (!softLcpPending || !image) {
382
+ return;
383
+ }
384
+
385
+ var measure = performance.measure("lcp_" + location.pathname, {
386
+ start: navStartMark,
387
+ end: image.responseEnd,
388
+ });
389
+
390
+ var timing = {
391
+ start: measure.startTime,
392
+ duration: measure.duration,
393
+ image: image.name,
394
+ url: window.location.href,
395
+ };
396
+ controller.trackCustomEvent(
397
+ "softNavLcp",
398
+ JSON.stringify(timing),
399
+ Date.now(),
400
+ );
401
+ softLcpPending = false;
402
+ softNavigationPerformanceObserver.disconnect();
403
+ },
404
+ );
405
+
406
+ softNavigationPerformanceObserver.observe({
407
+ buffered: true,
408
+ type: "resource",
409
+ });
410
+ },
411
+ },
315
412
  {{/if}}
316
413
  );
317
414
  {{#if isShopify}}
@@ -712,5 +712,5 @@
712
712
  ]
713
713
  }
714
714
  },
715
- "version": "2.48.0"
715
+ "version": "2.49.0"
716
716
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@speedkit/cli",
3
3
  "description": "Speed Kit CLI",
4
- "version": "2.48.0",
4
+ "version": "2.49.0",
5
5
  "author": {
6
6
  "name": "Baqend.com",
7
7
  "email": "info@baqend.com"