@speedkit/cli 4.2.1 → 4.4.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 +18 -0
- package/README.md +1 -1
- package/dist/services/customer-config/templates/config_SpeedKit.js.hbs +27 -9
- package/dist/services/customer-config/templates/config_documentHandler.js.hbs +44 -430
- package/dist/services/customer-config/templates/config_loadHandler.js.hbs +13 -1
- package/dist/services/onboarding/browser/extension/extension-downloader.js +2 -2
- package/dist/services/onboarding/browser/extension/extension-validator.js +2 -1
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
# [4.4.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v4.3.0...v4.4.0) (2026-05-13)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **wizard:** ssr defaults ([a4443c1](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/a4443c10d33088deda104d352d548399c5a17748))
|
|
7
|
+
* **wizard:** ssr defaults ([e6b8a4d](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/e6b8a4d28cec310e381f25b7da217789ffa4c8f0))
|
|
8
|
+
* **wizard:** templates ([2ee8f80](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/2ee8f80e94b16c00a125886ab4642498fb9c06a9))
|
|
9
|
+
* **wizard:** templates ([8a322e7](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/8a322e70d899827ae43d6bfc2125cb15bbc6150a))
|
|
10
|
+
|
|
11
|
+
# [4.3.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v4.2.1...v4.3.0) (2026-05-12)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **devtools:** do not download devtools if one of the extensions is configured from local ([049cb38](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/049cb38d22756a837759094038c60ae6c22a6bb5))
|
|
17
|
+
* **devtools:** switch to the new devtools project ([b026e2a](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/b026e2a36b6353527204611e7f02463a58968dc7))
|
|
18
|
+
|
|
1
19
|
## [4.2.1](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v4.2.0...v4.2.1) (2026-05-12)
|
|
2
20
|
|
|
3
21
|
|
package/README.md
CHANGED
|
@@ -99,19 +99,14 @@ import { ShopifyPlugin } from "speed-kit-config/ShopifyPlugin";
|
|
|
99
99
|
{{#if addDeviceDetection}}
|
|
100
100
|
{{#unless addSSR}}
|
|
101
101
|
userAgentDetection: true,
|
|
102
|
-
{{/unless}}
|
|
103
102
|
detectDevice: function(doc) {
|
|
104
|
-
{{#if addSSR}}
|
|
105
|
-
// SSR specific – identify device based on screen width:
|
|
106
|
-
// TODO: adjust devices + breakpoints to your needs
|
|
107
|
-
var width = window?.screen?.width || 1024;
|
|
108
|
-
if (width < 768) return "mobile";
|
|
109
|
-
return "desktop";
|
|
110
|
-
{{else}}
|
|
111
103
|
// TODO: adjust condition to your needs
|
|
112
104
|
return doc.querySelector('<mobile-specific-element>') ? "mobile" : "desktop";
|
|
113
|
-
{{/if}}
|
|
114
105
|
},
|
|
106
|
+
{{/unless}}
|
|
107
|
+
{{#if addSSR}}
|
|
108
|
+
customDevice: customDevice(),
|
|
109
|
+
{{/if}}
|
|
115
110
|
{{/if}}
|
|
116
111
|
{{#if addSSR}}
|
|
117
112
|
customVariation: [
|
|
@@ -440,6 +435,29 @@ import { ShopifyPlugin } from "speed-kit-config/ShopifyPlugin";
|
|
|
440
435
|
// Utility Functions
|
|
441
436
|
//================================================================================
|
|
442
437
|
|
|
438
|
+
{{#if addSSR}}
|
|
439
|
+
function customDevice() {
|
|
440
|
+
var width = window.innerWidth || 1025;
|
|
441
|
+
// TODO: adjust devices + breakpoints to your needs
|
|
442
|
+
if (width <= 820) {
|
|
443
|
+
return "mobile";
|
|
444
|
+
}
|
|
445
|
+
return "desktop";
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Re-evaluate device on orientation change and push to service worker
|
|
449
|
+
window.addEventListener("orientationchange", function () {
|
|
450
|
+
if (typeof SpeedKit !== "undefined" && SpeedKit.updateDevice) {
|
|
451
|
+
SpeedKit.updateDevice(customDevice());
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
window.addEventListener("resize", function () {
|
|
455
|
+
if (typeof SpeedKit !== "undefined" && SpeedKit.updateDevice) {
|
|
456
|
+
SpeedKit.updateDevice(customDevice());
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
{{/if}}
|
|
460
|
+
|
|
443
461
|
function getEnabledHosts(enabledHostsConfigs) {
|
|
444
462
|
var allHosts = [];
|
|
445
463
|
enabledHostsConfigs.forEach(function (enabledHostsConfig) {
|
|
@@ -87,44 +87,16 @@ const config = {
|
|
|
87
87
|
{{/if}}
|
|
88
88
|
},
|
|
89
89
|
async preTransform({db, document, variation, url, headers}) {
|
|
90
|
-
|
|
91
|
-
// SSR specific:
|
|
92
|
-
generateMainShadowRoot(document);
|
|
93
|
-
{{else}}
|
|
94
|
-
// do nothing
|
|
95
|
-
{{/if}}
|
|
90
|
+
// do nothing
|
|
96
91
|
},
|
|
97
92
|
async postTransform({db, document, variation, url, headers}) {
|
|
98
93
|
{{#if includeServiceWorker}}
|
|
99
94
|
injectServiceWorkerScript(document, '{{includeServiceWorker}}');
|
|
100
95
|
|
|
101
96
|
{{/if}}
|
|
102
|
-
{{#if
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
createPreloadsForInnerStyleLinks(document);
|
|
106
|
-
removeInnerScriptNodes(document);
|
|
107
|
-
assignDynamicStylesToShadowDom(document);
|
|
108
|
-
addDeclarativeShadowDOMPolyfill(document);
|
|
109
|
-
wrapPreRenderedElementsWithCustomRootTags(document);
|
|
110
|
-
addPolyFillAfterMainPreRenderTemplate(document);
|
|
111
|
-
triggerShadowRendering(document);
|
|
112
|
-
{{#if isShopify}}
|
|
113
|
-
// Shopify specific: inject scripts into sk-html which set css variables (normally set to html element)
|
|
114
|
-
injectCSSVariableScripts(document);
|
|
115
|
-
{{/if}}
|
|
116
|
-
{{#if addSSRInnerShadowDomSupport}}
|
|
117
|
-
|
|
118
|
-
overrideCustomElementDefine(document);
|
|
119
|
-
walkPreRenderedElements(document);
|
|
120
|
-
{{/if}}
|
|
121
|
-
{{else}}
|
|
122
|
-
{{#if isShopify}}
|
|
123
|
-
// Shopify specific: inject script which sets css variables on the html element
|
|
124
|
-
injectCSSVariableScripts(document);
|
|
125
|
-
{{else}}
|
|
126
|
-
// do nothing
|
|
127
|
-
{{/if}}
|
|
97
|
+
{{#if isShopify}}
|
|
98
|
+
// Shopify specific: inject scripts which set css variables{{#if addSSR}} (normally set on the html element, but in SSR mode they have to be set on sk-html inside the shadow DOM){{/if}}
|
|
99
|
+
injectCSSVariableScripts(document);
|
|
128
100
|
{{/if}}
|
|
129
101
|
},
|
|
130
102
|
{{#if isPlentymarkets}}
|
|
@@ -159,6 +131,17 @@ const config = {
|
|
|
159
131
|
|
|
160
132
|
// SSR specific:
|
|
161
133
|
preRender: {
|
|
134
|
+
// Wraps pre-rendered content in a shadow DOM and runs the standard SSR
|
|
135
|
+
// setup (style preloads, dynamic styles, declarative shadow DOM polyfill,
|
|
136
|
+
// sk-html/sk-body wrapping, render trigger). Pre-rendered fragments are
|
|
137
|
+
// appended to `sk-shadow-app-root > template` by default.
|
|
138
|
+
defaultShadowRoot: true,
|
|
139
|
+
{{#if addSSRInnerShadowDomSupport}}
|
|
140
|
+
// Overrides `customElements.define` so the static SSR DOM is upgraded
|
|
141
|
+
// without invoking custom element constructors (required when the
|
|
142
|
+
// customer ships its own shadow DOMs / web components).
|
|
143
|
+
innerShadowDOMSupport: true,
|
|
144
|
+
{{/if}}
|
|
162
145
|
elements: [
|
|
163
146
|
// append all extracted styles to all pre-rendered elements (as they are capsuled in shadow doms)
|
|
164
147
|
// TODO check if all necessary styles are extracted by this rule
|
|
@@ -169,11 +152,10 @@ const config = {
|
|
|
169
152
|
"body > style:not([media='print'])",
|
|
170
153
|
"body > link[rel='stylesheet'][href]:not([media='print'])",
|
|
171
154
|
].join(","),
|
|
172
|
-
appendTo: "sk-shadow-app-root > template",
|
|
173
155
|
},
|
|
174
156
|
// this will be the main element to extract from the rendered DOM
|
|
175
157
|
// TODO change selector to the main element of your page
|
|
176
|
-
{ selector: "body > #app"
|
|
158
|
+
{ selector: "body > #app" },
|
|
177
159
|
],
|
|
178
160
|
guards: [
|
|
179
161
|
{
|
|
@@ -259,420 +241,52 @@ export const post = async (db, req, res) => {
|
|
|
259
241
|
document.querySelector("head").appendChild(swScript);
|
|
260
242
|
}
|
|
261
243
|
{{/if}}
|
|
262
|
-
{{#if
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Generates the main shadow root for the given DOM.
|
|
266
|
-
* This is the parent element of the extracted pre-rendered content.
|
|
267
|
-
*
|
|
268
|
-
* @param document
|
|
269
|
-
*/
|
|
270
|
-
function generateMainShadowRoot(document) {
|
|
271
|
-
const customContainer = document.createElement("sk-shadow-app-root");
|
|
272
|
-
customContainer.setAttribute("aria-hidden", "true"); // hide from screen readers
|
|
244
|
+
{{#if addSSRInnerShadowDomSupport}}
|
|
273
245
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
document.querySelector("body").prepend(customContainer);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Checks if the document is pre-rendered.
|
|
283
|
-
*
|
|
284
|
-
* @param document
|
|
285
|
-
*/
|
|
286
|
-
function isPreRendered(document) {
|
|
287
|
-
return !!document.querySelector("html.speed-kit-pre-rendered");
|
|
288
|
-
}
|
|
246
|
+
//================================================================================
|
|
247
|
+
// Puppeteer Callback
|
|
248
|
+
//================================================================================
|
|
289
249
|
|
|
290
250
|
/**
|
|
291
|
-
*
|
|
251
|
+
* Waits for the callback when custom elements are defined on the document.
|
|
292
252
|
*
|
|
293
|
-
* @
|
|
294
|
-
* @return {void}
|
|
253
|
+
* @return {Promise} - A promise that resolves when all custom elements are defined, or if a timeout of 5 seconds occurs.
|
|
295
254
|
*/
|
|
296
|
-
function
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
// preload fonts by moving font declarations from nested css to the head, as they are not supported in shadow doms
|
|
311
|
-
customShadowRoot.querySelectorAll(".speed-kit-font-face-preloads").forEach((fontFaceRules) => {
|
|
312
|
-
head.append(fontFaceRules);
|
|
255
|
+
async function waitForCallback() {
|
|
256
|
+
const undefinedElements = document.querySelectorAll(":not(:defined)");
|
|
257
|
+
// need to be defined here as they are sent to the lambda function
|
|
258
|
+
const customElementNames = [
|
|
259
|
+
// TODO add correct custom element names (find them by executing document.querySelectorAll(":not(:defined)"))
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
const promises = [...undefinedElements]
|
|
263
|
+
.filter((element) => customElementNames.some((name) => element.localName.includes(name)))
|
|
264
|
+
.map((element) => {
|
|
265
|
+
// eslint-disable-next-line no-undef
|
|
266
|
+
return customElements.whenDefined(element.localName);
|
|
313
267
|
});
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Removes all inner script nodes from the given document.
|
|
319
|
-
*
|
|
320
|
-
* @param {Document} document - The document object from which to remove script nodes.
|
|
321
|
-
*/
|
|
322
|
-
function removeInnerScriptNodes(document) {
|
|
323
|
-
// remove all innerShadowDom script, as they would be executed again
|
|
324
|
-
const customShadowRoots = getCustomShadowElements(document);
|
|
325
|
-
for (const customShadowRoot of customShadowRoots) {
|
|
326
|
-
Array.from(customShadowRoot.querySelectorAll("script")).forEach((scriptNode) => scriptNode.remove());
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
268
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
function assignDynamicStylesToShadowDom(document) {
|
|
337
|
-
const skStyles = document.querySelector("#speed-kit-df-styles");
|
|
338
|
-
|
|
339
|
-
if (!skStyles) {
|
|
340
|
-
throw new Abort("#speed-kit-df-styles not found");
|
|
341
|
-
}
|
|
342
|
-
const clonedStyles = document.createElement("style");
|
|
343
|
-
for (const attr of skStyles.attributes) {
|
|
344
|
-
clonedStyles.setAttribute(attr.name, attr.value);
|
|
345
|
-
}
|
|
346
|
-
clonedStyles.textContent = skStyles.textContent;
|
|
347
|
-
|
|
348
|
-
const customShadowElements = getCustomShadowElements(document);
|
|
349
|
-
customShadowElements.forEach((shadowElement) => {
|
|
350
|
-
shadowElement.prepend(clonedStyles);
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Helper function to select all template elements.
|
|
356
|
-
*
|
|
357
|
-
* @param document
|
|
358
|
-
* @returns {*}
|
|
359
|
-
*/
|
|
360
|
-
function getCustomShadowElements(document) {
|
|
361
|
-
return document.querySelectorAll("sk-shadow-app-root > template");
|
|
269
|
+
return await Promise.race([
|
|
270
|
+
Promise.all(promises),
|
|
271
|
+
new Promise((resolve) => {
|
|
272
|
+
setTimeout(resolve, 5000);
|
|
273
|
+
}),
|
|
274
|
+
]);
|
|
362
275
|
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Adds the declarative shadow dom polyfill to the head of the document.
|
|
366
|
-
*
|
|
367
|
-
* @param document
|
|
368
|
-
*/
|
|
369
|
-
function addDeclarativeShadowDOMPolyfill(document) {
|
|
370
|
-
const head = document.querySelector("head");
|
|
371
|
-
if (head) {
|
|
372
|
-
const script = document.createElement("script");
|
|
373
|
-
script.textContent = SKShadowRootsPolyfill.toString();
|
|
374
|
-
head.append(script);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Polyfills the creation of Shadow Roots for browsers that do not support Shadow DOM.
|
|
380
|
-
* If the browser supports Shadow DOM, this method does nothing.
|
|
381
|
-
* https://developer.chrome.com/docs/css-ui/declarative-shadow-dom#polyfill
|
|
382
|
-
*
|
|
383
|
-
* @param {HTMLTemplateElement} template - The template element to be transformed into a Shadow Root.
|
|
384
|
-
* @constructor
|
|
385
|
-
*/
|
|
386
|
-
function SKShadowRootsPolyfill(template) {
|
|
387
|
-
// If the browser supports Shadow DOM, do nothing, as template is already transformed to a shadowRoot.
|
|
388
|
-
if (!template) {
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
const mode = template.getAttribute("shadowrootmode");
|
|
392
|
-
const shadowRoot = template.parentNode.attachShadow({ mode });
|
|
393
|
-
shadowRoot.appendChild(template.content);
|
|
394
|
-
template.remove();
|
|
395
|
-
shadowRoot
|
|
396
|
-
.querySelectorAll("template[shadowrootmode]")
|
|
397
|
-
.forEach((template) => {
|
|
398
|
-
SKShadowRootsPolyfill(template);
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Wraps pre-rendered elements with custom sk-html and sk-body tags.
|
|
404
|
-
*
|
|
405
|
-
* @param document
|
|
406
|
-
*/
|
|
407
|
-
function wrapPreRenderedElementsWithCustomRootTags(document) {
|
|
408
|
-
const customShadowRoots = getCustomShadowElements(document);
|
|
409
|
-
|
|
410
|
-
function createCustomElement(tagName, sourceSelector) {
|
|
411
|
-
const el = document.createElement(tagName);
|
|
412
|
-
const source = document.querySelector(sourceSelector);
|
|
413
|
-
if (source) {
|
|
414
|
-
for (const attr of source.attributes) {
|
|
415
|
-
el.setAttribute(attr.name, attr.value);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
return el;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
for (const customShadowRoot of customShadowRoots) {
|
|
422
|
-
const skHtml = createCustomElement("sk-html", "html");
|
|
423
|
-
const skBody = createCustomElement("sk-body", "body");
|
|
424
|
-
|
|
425
|
-
// move all children from the shadow root element into sk-body
|
|
426
|
-
while (customShadowRoot.firstChild) {
|
|
427
|
-
// remove class which is no longer needed
|
|
428
|
-
customShadowRoot.firstChild.classList.remove("speed-kit-pre-rendered-block-added");
|
|
429
|
-
|
|
430
|
-
// move element to sk-body
|
|
431
|
-
skBody.appendChild(customShadowRoot.firstChild);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// append sk-body inside sk-html
|
|
435
|
-
skHtml.appendChild(skBody);
|
|
436
|
-
|
|
437
|
-
// append sk-html into the shadow root element
|
|
438
|
-
customShadowRoot.appendChild(skHtml);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Calls the polyfill for shadowRoots after the main pre-rendered template.
|
|
444
|
-
*
|
|
445
|
-
* @param document
|
|
446
|
-
*/
|
|
447
|
-
function addPolyFillAfterMainPreRenderTemplate(document) {
|
|
448
|
-
const customShadowRoots = getCustomShadowElements(document);
|
|
449
|
-
for (const customShadowRoot of customShadowRoots) {
|
|
450
|
-
let topLevelPreRenderElements = customShadowRoot.querySelectorAll("sk-body > *");
|
|
451
|
-
topLevelPreRenderElements.forEach((element) => {
|
|
452
|
-
let topTemplate = element.querySelector('template[shadowrootmode="open"]');
|
|
453
|
-
if (!topTemplate) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// polyfill for shadowRoots
|
|
458
|
-
let polyfillScript = document.createElement("script");
|
|
459
|
-
polyfillScript.textContent = `SKShadowRootsPolyfill(document?.currentScript?.previousElementSibling)`;
|
|
460
|
-
topTemplate.after(polyfillScript);
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Forces rendering of elements within custom shadow DOMs by briefly toggling
|
|
467
|
-
* their visibility via injected style rules.
|
|
468
|
-
*
|
|
469
|
-
* @param document
|
|
470
|
-
*/
|
|
471
|
-
function triggerShadowRendering(document) {
|
|
472
|
-
const customShadowRoots = getCustomShadowElements(document);
|
|
473
|
-
for (const customShadowRoot of customShadowRoots) {
|
|
474
|
-
const hidingStyle = document.createElement("style");
|
|
475
|
-
hidingStyle.textContent = `sk-html{visibility:hidden;}`;
|
|
476
|
-
customShadowRoot.prepend(hidingStyle);
|
|
477
|
-
|
|
478
|
-
const visibilityStyle = document.createElement("style");
|
|
479
|
-
visibilityStyle.textContent = `sk-html{visibility:visible;}`;
|
|
480
|
-
customShadowRoot.appendChild(visibilityStyle);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
{{#if addSSRInnerShadowDomSupport}}
|
|
484
|
-
|
|
485
|
-
//================================================================================
|
|
486
|
-
// Puppeteer Callback
|
|
487
|
-
//================================================================================
|
|
488
|
-
|
|
489
|
-
/**
|
|
490
|
-
* Waits for the callback when custom elements are defined on the document.
|
|
491
|
-
*
|
|
492
|
-
* @return {Promise} - A promise that resolves when all custom elements are defined, or if a timeout of 5 seconds occurs.
|
|
493
|
-
*/
|
|
494
|
-
async function waitForCallback() {
|
|
495
|
-
const undefinedElements = document.querySelectorAll(":not(:defined)");
|
|
496
|
-
// need to be defined here as they are sent to the lambda function
|
|
497
|
-
const customElementNames = [
|
|
498
|
-
// TODO add correct custom element names (find them by executing document.querySelectorAll(":not(:defined)"))
|
|
499
|
-
];
|
|
500
|
-
|
|
501
|
-
const promises = [...undefinedElements]
|
|
502
|
-
.filter((element) => customElementNames.some((name) => element.localName.includes(name)))
|
|
503
|
-
.map((element) => {
|
|
504
|
-
// eslint-disable-next-line no-undef
|
|
505
|
-
return customElements.whenDefined(element.localName);
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
return await Promise.race([
|
|
509
|
-
Promise.all(promises),
|
|
510
|
-
new Promise((resolve) => {
|
|
511
|
-
setTimeout(resolve, 5000);
|
|
512
|
-
}),
|
|
513
|
-
]);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
//================================================================================
|
|
517
|
-
// INLINE SCRIPTS
|
|
518
|
-
//================================================================================
|
|
519
|
-
|
|
520
|
-
/**
|
|
521
|
-
* Overrides the window.customElements.define method to add custom code before calling the original function.
|
|
522
|
-
*/
|
|
523
|
-
function overrideDefine() {
|
|
524
|
-
/* global HTMLElement, window, customElements */
|
|
525
|
-
|
|
526
|
-
// Store the original function
|
|
527
|
-
// eslint-disable-next-line no-undef
|
|
528
|
-
let originalDefine = window.customElements.define;
|
|
529
|
-
|
|
530
|
-
// Create new function
|
|
531
|
-
// eslint-disable-next-line no-undef
|
|
532
|
-
window.customElements.define = function (e, o, options) {
|
|
533
|
-
if (options?.is && options?.is.length > 0) {
|
|
534
|
-
// eslint-disable-next-line no-undef
|
|
535
|
-
return originalDefine.call(window.customElements, e, o, options);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
const lifeCycleCallbacks = [
|
|
539
|
-
"connectedCallback",
|
|
540
|
-
"disconnectedCallback",
|
|
541
|
-
"adoptedCallback",
|
|
542
|
-
"connectedMoveCallback",
|
|
543
|
-
"attributeChangedCallback",
|
|
544
|
-
"formAssociatedCallback",
|
|
545
|
-
"formResetCallback",
|
|
546
|
-
"formDisabledCallback",
|
|
547
|
-
"formStateRestoreCallback",
|
|
548
|
-
];
|
|
549
|
-
|
|
550
|
-
let preventInit = false;
|
|
551
|
-
let skProxy = function () {
|
|
552
|
-
// This constructor is invoked for every custom element.
|
|
553
|
-
// However, we can return a new instance in this constructor which is then used for upgrading the element.
|
|
554
|
-
// We are using the Reflect.construct method to prevent invoking the original constructor
|
|
555
|
-
// initialization code if we are in the static rendered DOM tree of Speed Kit
|
|
556
|
-
let instance;
|
|
557
|
-
if (preventInit) {
|
|
558
|
-
instance = Reflect.construct(HTMLElement, arguments, skProxy);
|
|
559
|
-
instance.__skStatic = preventInit;
|
|
560
|
-
} else {
|
|
561
|
-
instance = Reflect.construct(o, arguments, skProxy);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
return instance;
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
// create a dynamic proxy class which is overwriting all lifecycle hooks of the original class
|
|
568
|
-
skProxy.prototype = Object.create(o.prototype, {
|
|
569
|
-
constructor: {
|
|
570
|
-
value: skProxy,
|
|
571
|
-
writable: true,
|
|
572
|
-
configurable: true,
|
|
573
|
-
},
|
|
574
|
-
...Object.fromEntries(
|
|
575
|
-
lifeCycleCallbacks
|
|
576
|
-
.map((callbackName) => [callbackName, o.prototype[callbackName]])
|
|
577
|
-
.filter(([, hasCallback]) => hasCallback)
|
|
578
|
-
.map(([callbackName, callback]) => {
|
|
579
|
-
return [
|
|
580
|
-
callbackName,
|
|
581
|
-
{
|
|
582
|
-
value: function () {
|
|
583
|
-
if (!this.__skStatic) {
|
|
584
|
-
return callback.apply(this, arguments);
|
|
585
|
-
}
|
|
586
|
-
},
|
|
587
|
-
writable: true,
|
|
588
|
-
configurable: true,
|
|
589
|
-
},
|
|
590
|
-
];
|
|
591
|
-
}),
|
|
592
|
-
),
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
Object.setPrototypeOf(skProxy, o);
|
|
596
|
-
|
|
597
|
-
const skContainer = document.querySelector("sk-shadow-app-root");
|
|
598
|
-
let skContainerParentNode;
|
|
599
|
-
let skContainerNextNode;
|
|
600
|
-
if (skContainer) {
|
|
601
|
-
skContainerParentNode = skContainer.parentNode;
|
|
602
|
-
skContainerNextNode = skContainer.nextSibling;
|
|
603
|
-
skContainer.remove();
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// Control the upgrade of the sk static dom tree by temporary removing the tree while
|
|
607
|
-
// defining the new custom element. Do then a controlled upgrade of the sk dom tree by
|
|
608
|
-
// preventing the constructor invocation of the custom element class
|
|
609
|
-
originalDefine.call(window.customElements, e, skProxy, options);
|
|
610
|
-
if (skContainer) {
|
|
611
|
-
preventInit = true;
|
|
612
|
-
skContainerParentNode.insertBefore(skContainer, skContainerNextNode);
|
|
613
|
-
customElements.upgrade(skContainer);
|
|
614
|
-
preventInit = false;
|
|
615
|
-
}
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Overrides the custom element definition in the given document.
|
|
621
|
-
*
|
|
622
|
-
* @param {Document} document - The document object where the custom element is defined.
|
|
623
|
-
*
|
|
624
|
-
* @return {void} - This method does not return anything.
|
|
625
|
-
*/
|
|
626
|
-
function overrideCustomElementDefine(document) {
|
|
627
|
-
const script = document.createElement("script");
|
|
628
|
-
script.setAttribute("type", "text/javascript");
|
|
629
|
-
script.classList.add("sk-shadowroot-extension");
|
|
630
|
-
script.textContent = `(${overrideDefine.toString()})()`;
|
|
631
|
-
document.querySelector("head").appendChild(script);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Walks through pre-rendered elements and performs specific actions on each element.
|
|
636
|
-
*
|
|
637
|
-
* @param {Document} document - The HTML document object.
|
|
638
|
-
*/
|
|
639
|
-
function walkPreRenderedElements(document) {
|
|
640
|
-
const customShadowElements = getCustomShadowElements(document);
|
|
641
|
-
walkElements(customShadowElements, (element) => {
|
|
642
|
-
// TODO extend if shadow-doms should be modified, as access to the shadow dom is not possible via querySelectors from the outside
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Recursively walks through a tree of elements and applies a callback function to each element.
|
|
648
|
-
*
|
|
649
|
-
* @param {Array} elements - The array of elements to walk through. Each element should be an object with a 'children' property.
|
|
650
|
-
* @param {Function} callback - The callback function to apply to each element. It should take a single argument, which will be the current element.
|
|
651
|
-
*
|
|
652
|
-
* @return {undefined}
|
|
653
|
-
*/
|
|
654
|
-
function walkElements(elements, callback) {
|
|
655
|
-
elements.forEach((element) => {
|
|
656
|
-
callback(element);
|
|
657
|
-
if (element.children && element.children.length > 0) {
|
|
658
|
-
walkElements(element.children, callback);
|
|
659
|
-
}
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
{{/if}}
|
|
663
276
|
{{/if}}
|
|
664
277
|
{{#if isShopify}}
|
|
665
278
|
|
|
666
279
|
/**
|
|
667
|
-
* Injects scripts into sk-html within each shadow root that set CSS custom
|
|
280
|
+
* Injects scripts {{#if addSSR}}into sk-html within each shadow root that set CSS custom
|
|
668
281
|
* properties (e.g. --window-height, --announcement-bar-height, --header-height)
|
|
669
|
-
* on sk-html instead of the document's html element.
|
|
282
|
+
* on sk-html instead of the document's html element.{{else}}that set CSS custom properties
|
|
283
|
+
* (e.g. --window-height, --announcement-bar-height, --header-height) on the html element.{{/if}}
|
|
670
284
|
*
|
|
671
285
|
* @param document
|
|
672
286
|
*/
|
|
673
287
|
function injectCSSVariableScripts(document) {
|
|
674
288
|
{{#if addSSR}}
|
|
675
|
-
const customShadowRoots =
|
|
289
|
+
const customShadowRoots = document.querySelectorAll("sk-shadow-app-root > template");
|
|
676
290
|
for (const customShadowRoot of customShadowRoots) {
|
|
677
291
|
const skHtml = customShadowRoot.querySelector("sk-html");
|
|
678
292
|
if (!skHtml) continue;
|
|
@@ -180,6 +180,18 @@ import { PredictivePreloading } from 'predictive-preloading/predictivePreloading
|
|
|
180
180
|
},
|
|
181
181
|
{{/if}}
|
|
182
182
|
{{/if}}
|
|
183
|
+
{{#if addSSR}}
|
|
184
|
+
{
|
|
185
|
+
on: "nextTick",
|
|
186
|
+
track: function (controller) {
|
|
187
|
+
controller.trackCustomEvent(
|
|
188
|
+
"viewportSize",
|
|
189
|
+
JSON.stringify({ innerWidth: window.innerWidth, innerHeight: window.innerHeight }),
|
|
190
|
+
0,
|
|
191
|
+
);
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{{/if}}
|
|
183
195
|
{{#if useGATracking}}
|
|
184
196
|
|
|
185
197
|
// TODO: remove or adapt if events are not properly covered by GAEcommerceTrackingPlugin
|
|
@@ -237,7 +249,7 @@ import { PredictivePreloading } from 'predictive-preloading/predictivePreloading
|
|
|
237
249
|
// },
|
|
238
250
|
// },
|
|
239
251
|
{{else}}
|
|
240
|
-
|
|
252
|
+
|
|
241
253
|
{{#if isShopify}}
|
|
242
254
|
// No custom ecAddToCart tracking event needed as it is already handled by the speed-kit-config/ShopifyPlugin
|
|
243
255
|
// No custom ecConversion tracking event as it is already handled by the Speed Kit Extension for Shopify
|
|
@@ -44,7 +44,7 @@ export class ExtensionDownloader {
|
|
|
44
44
|
}
|
|
45
45
|
async updateLocalDevtools() {
|
|
46
46
|
// downloadExtension
|
|
47
|
-
const extensionResponse = await fetch("https://threepointonefour.app.baqend.com/v1/code/
|
|
47
|
+
const extensionResponse = await fetch("https://threepointonefour.app.baqend.com/v1/code/webhook_devtools_release?download");
|
|
48
48
|
// get fileName from header
|
|
49
49
|
const fileName = extensionResponse.headers.get("filename");
|
|
50
50
|
// resolve path for unpacked extension
|
|
@@ -74,7 +74,7 @@ export class ExtensionDownloader {
|
|
|
74
74
|
return manifestConfig.version;
|
|
75
75
|
}
|
|
76
76
|
async getRemoteVersion() {
|
|
77
|
-
const versionResponse = await fetch("https://threepointonefour.app.baqend.com/v1/code/
|
|
77
|
+
const versionResponse = await fetch("https://threepointonefour.app.baqend.com/v1/code/webhook_devtools_release");
|
|
78
78
|
if (!versionResponse.ok) {
|
|
79
79
|
throw new Error("Could not find version for" + devtools);
|
|
80
80
|
}
|
|
@@ -57,7 +57,8 @@ export class ExtensionValidator {
|
|
|
57
57
|
}
|
|
58
58
|
async handleDevtoolsExtension(validExtensions) {
|
|
59
59
|
// check if devtools extension can be find in current extensionPaths
|
|
60
|
-
if (validExtensions.some((config) => config.name.toLowerCase().includes("devtools
|
|
60
|
+
if (validExtensions.some((config) => config.name.toLowerCase().includes("speed-kit devtools") ||
|
|
61
|
+
config.name.toLowerCase().includes("devtools extension"))) {
|
|
61
62
|
return;
|
|
62
63
|
}
|
|
63
64
|
// download or update extension
|
package/oclif.manifest.json
CHANGED