@speedkit/cli 3.9.1 → 3.10.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 +21 -0
- package/README.md +1 -1
- package/dist/services/customer-config/customer-config-service-model.d.ts +3 -5
- package/dist/services/customer-config/customer-config-service.js +13 -21
- package/dist/services/customer-config/templates/config_SpeedKit.js.hbs +31 -44
- package/dist/services/customer-config/templates/config_customer.json.hbs +44 -54
- package/dist/services/customer-config/templates/config_documentHandler.js.hbs +212 -169
- package/dist/services/customer-config/templates/config_dynamicBlocks.es6.hbs +58 -31
- package/dist/services/customer-config/templates/config_dynamicStyles.css.hbs +21 -19
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [3.10.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.9.1...v3.10.0) (2025-10-15)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **wizard:** ssr ([7f48214](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/7f48214e04aae0183b4027e1d0b103f22bbb8499))
|
|
7
|
+
* **wizard:** ssr ([a848bb2](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/a848bb26f3fcafd79d12d7acbf4b9b4a32105ff4))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **customer-config:** improve root-referencing style handling by parallelizing css fetching ([907d487](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/907d4875ed738ac6ba773562907a947a529ac198))
|
|
13
|
+
* **customer-config:** move css processing from dh to lambda ([409da9b](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/409da9ba8c542ddcdc45feb5f25c06b3d98d37a3))
|
|
14
|
+
* **customer-config:** optimise ssr handling + provide dom-parsing dh as default ([ac0c2fa](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/ac0c2fab72f926d8a818d21dd8c0a67c736d033d))
|
|
15
|
+
* **customer-config:** prevent ssr shadow root container from being accessible by screen readers ([0743a91](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/0743a91a111ed1207fa3e8079c1a0f22166bc67c))
|
|
16
|
+
* **customer-config:** remove ssr tv blacklisting due to deprecation ([5a7e6c2](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/5a7e6c2bfb12678153d1f7dd2b16790a47c27484))
|
|
17
|
+
* **customer-config:** remove unnecessary ssr tablet disabling ([a48582f](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/a48582f65bb0f55019cc77476998c206f415d0ae))
|
|
18
|
+
* **customer-config:** scope shadow app root container positioning to pre-rendered pages ([46e970b](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/46e970b35295794b9e05c588bf34fc80470a2f84))
|
|
19
|
+
* **customer-config:** update ssr variation detection ([56a79b5](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/56a79b55f49b12628682bfbe9a23c403a39ebdba))
|
|
20
|
+
* **customer-config:** update ssr variation detection ([8744274](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/87442749b5a3dc730195d5f009316501d80ed95c))
|
|
21
|
+
|
|
1
22
|
## [3.9.1](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.9.0...v3.9.1) (2025-10-15)
|
|
2
23
|
|
|
3
24
|
|
package/README.md
CHANGED
|
@@ -29,11 +29,9 @@ export interface CustomerConfigSettings {
|
|
|
29
29
|
includeServiceWorker?: string;
|
|
30
30
|
activateImageOptimisation?: boolean;
|
|
31
31
|
removeLazyLoading?: boolean;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
shadowDomCustomElementPrefix?: string;
|
|
36
|
-
activateRumTracking?: boolean;
|
|
32
|
+
addSSR?: boolean;
|
|
33
|
+
addSSRInnerShadowDomSupport?: boolean;
|
|
34
|
+
addDeviceDetection?: boolean;
|
|
37
35
|
useGATracking?: boolean;
|
|
38
36
|
useScrapingBee?: boolean;
|
|
39
37
|
withGoogleOptimize?: boolean;
|
|
@@ -136,7 +136,7 @@ class CustomerConfigService {
|
|
|
136
136
|
return true;
|
|
137
137
|
}
|
|
138
138
|
async getConfigSettings() {
|
|
139
|
-
let { production, staging, activateScopedDeployments, subRouteScope, includeServiceWorker, activateImageOptimisation, removeLazyLoading,
|
|
139
|
+
let { production, staging, activateScopedDeployments, subRouteScope, includeServiceWorker, activateImageOptimisation, removeLazyLoading, addSSR, addSSRInnerShadowDomSupport, addDeviceDetection, useGATracking, useScrapingBee, withGoogleOptimize, activateCfRocketLoaderWorkaround, hasSoftNavigations, isShopify, isShopware, isSalesforce, isOxid, isPlentymarkets, isPOV, } = {};
|
|
140
140
|
this.appName = await this.cli.prompt(`[App Name] Enter desired SK app name:`, {
|
|
141
141
|
validator: (input) => /^[\da-z]+(?:-[\da-z]+)*$/.test(input) ? "" : "No valid kebab-case",
|
|
142
142
|
defaultAnswer: this.appName,
|
|
@@ -181,29 +181,23 @@ class CustomerConfigService {
|
|
|
181
181
|
if (await this.cli.confirm("[Service Worker] Is there a Service Worker which needs to be included?", false)) {
|
|
182
182
|
includeServiceWorker = await this.cli.prompt("[Service Worker] Enter path of Service Worker to be included:", { defaultAnswer: "/sw.js" });
|
|
183
183
|
}
|
|
184
|
-
addUADetection = await this.cli.confirm("[Variation handling] Do mobile and desktop versions of the website differ in their HTML structure, which would require us to add variations?", false);
|
|
185
184
|
activateImageOptimisation = await this.cli.confirm("[IO] Should image optimisation be activated?", false);
|
|
186
|
-
removeLazyLoading = await this.cli.confirm("[Lazy
|
|
187
|
-
if (await this.cli.confirm("[Lambda
|
|
188
|
-
|
|
189
|
-
if (await this.cli.confirm("[Lambda
|
|
190
|
-
|
|
191
|
-
shadowDomCustomElementPrefix = await this.cli.prompt("[Lambda-SSR] Please specify the prefix of the custom elements used (e.g. o2 uses tef-): ", { defaultAnswer: "custom-" });
|
|
185
|
+
removeLazyLoading = await this.cli.confirm("[Lazy Loading] Does the shop require us to resolve lazy-loaded content?");
|
|
186
|
+
if (await this.cli.confirm("[Lambda SSR] Add server-side-rendering? This requires a set-up Lambda function to work.", false)) {
|
|
187
|
+
addSSR = true;
|
|
188
|
+
if (await this.cli.confirm("[Lambda SSR] Does the customer utilize Shadow DOMs? If so additional handling for this will be added.", false)) {
|
|
189
|
+
addSSRInnerShadowDomSupport = true;
|
|
192
190
|
}
|
|
193
|
-
await this.cli.confirm("Confirm that you increased the Node memory limit to at least 1024 as the SSR setup is memory intensive." +
|
|
194
|
-
' BBQ App -> Data -> App -> Search for App -> Addons -> "nodeMemLimit": 1024', false);
|
|
195
191
|
}
|
|
192
|
+
// ask for variation handling only if adding Lambda SSR is not needed, as it will come with device detection anyway
|
|
193
|
+
addDeviceDetection = addSSR
|
|
194
|
+
? true
|
|
195
|
+
: await this.cli.confirm("[Device Detection] Do mobile and desktop versions of the website differ in their HTML structure, which would require us to add variations?", false);
|
|
196
196
|
useScrapingBee = await this.cli.confirm("[ScrapingBee] Do customer responses differ geo-location-based which would require ScrapingBee API to fetch documents?", false);
|
|
197
|
-
activateRumTracking = true;
|
|
198
|
-
// activateRumTracking = await this.cli.confirm(
|
|
199
|
-
// "[Tracking] Activate RUM Tracking?",
|
|
200
|
-
// );
|
|
201
|
-
// if (activateRumTracking) {
|
|
202
197
|
if (!isShopify) {
|
|
203
198
|
useGATracking = await this.cli.confirm("[Tracking] Add tracking based on Google Analytics' DataLayer?");
|
|
204
199
|
}
|
|
205
200
|
hasSoftNavigations = await this.cli.confirm("[Tracking] Add tracking for Soft Navigations?", false);
|
|
206
|
-
// }
|
|
207
201
|
isPOV = await this.cli.confirm("[Tracking] Is a POV (proof of value) anticipated, so that additional tracking is needed?", false);
|
|
208
202
|
withGoogleOptimize = await this.cli.confirm("[Services] Is Google Optimize used?", false);
|
|
209
203
|
activateCfRocketLoaderWorkaround = isShopify
|
|
@@ -218,11 +212,9 @@ class CustomerConfigService {
|
|
|
218
212
|
includeServiceWorker,
|
|
219
213
|
activateImageOptimisation,
|
|
220
214
|
removeLazyLoading,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
shadowDomCustomElementPrefix,
|
|
225
|
-
activateRumTracking,
|
|
215
|
+
addSSR,
|
|
216
|
+
addSSRInnerShadowDomSupport,
|
|
217
|
+
addDeviceDetection,
|
|
226
218
|
useGATracking,
|
|
227
219
|
useScrapingBee,
|
|
228
220
|
withGoogleOptimize,
|
|
@@ -25,30 +25,6 @@
|
|
|
25
25
|
var ENABLED_HOSTS = getEnabledHosts(ENABLED_HOSTS_CONFIGS);
|
|
26
26
|
var CURRENT_HOST_CONFIG = getCurrentHostConfig(ENABLED_HOSTS_CONFIGS);
|
|
27
27
|
|
|
28
|
-
{{#if addPreRendering}}
|
|
29
|
-
// Lambda SSR specific: disable SK for tablets as they are not covered in lambda
|
|
30
|
-
function isTablet() {
|
|
31
|
-
var userAgent = window.navigator.userAgent.toLowerCase();
|
|
32
|
-
var tabletUAs = [
|
|
33
|
-
/tablet/,
|
|
34
|
-
/ipad/,
|
|
35
|
-
/nexus 7/,
|
|
36
|
-
/nexus 10/,
|
|
37
|
-
/silk\//,
|
|
38
|
-
/\bgt-[pn]\d{4}\b/,
|
|
39
|
-
/\bsm-t\d{3}\b/,
|
|
40
|
-
/^.*android(?!.*mobile|.*smart-tv|.*smarttv|.*aft[tm]|.*crkey).*$/,
|
|
41
|
-
];
|
|
42
|
-
|
|
43
|
-
if ("ontouchend" in document && userAgent.indexOf("Macintosh") > -1) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
return tabletUAs.some(function (ua) {
|
|
47
|
-
return ua.test(userAgent);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
{{/if}}
|
|
51
|
-
|
|
52
28
|
/**
|
|
53
29
|
* @type {SpeedKitConfig}
|
|
54
30
|
*/
|
|
@@ -66,22 +42,36 @@
|
|
|
66
42
|
includeServiceWorker: "{{includeServiceWorker}}",
|
|
67
43
|
{{/if}}
|
|
68
44
|
preloadDynamicBlocks: true,
|
|
69
|
-
rumTracking:
|
|
70
|
-
{{#if
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{{
|
|
74
|
-
|
|
45
|
+
rumTracking: true,
|
|
46
|
+
{{#if addDeviceDetection}}
|
|
47
|
+
{{#unless addSSR}}
|
|
48
|
+
userAgentDetection: true,
|
|
49
|
+
{{/unless}}
|
|
50
|
+
detectDevice: function(doc) {
|
|
51
|
+
{{#if addSSR}}
|
|
52
|
+
// SSR specific – identify device based on screen width:
|
|
53
|
+
// TODO: adjust devices + breakpoints to your needs
|
|
54
|
+
var width = window?.screen?.width || 1024;
|
|
55
|
+
if (width < 768) return "mobile";
|
|
56
|
+
return "desktop";
|
|
57
|
+
{{else}}
|
|
58
|
+
// TODO: adjust condition to your needs
|
|
59
|
+
return doc.querySelector('<mobile-specific-element>') ? "mobile" : "desktop";
|
|
60
|
+
{{/if}}
|
|
61
|
+
},
|
|
75
62
|
{{/if}}
|
|
76
|
-
{{#if
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
63
|
+
{{#if addSSR}}
|
|
64
|
+
customVariation: [
|
|
65
|
+
{
|
|
66
|
+
variationFunction: function (request, device, cookies) {
|
|
67
|
+
// SSR specific – don't report a variation for specific page types NOT covered by SSR:
|
|
68
|
+
// TODO: adjust and activate if needed
|
|
69
|
+
// if (request.url.indexOf("<url-page-type-idenfier>") > -1) return "desktop";
|
|
70
|
+
return device;
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
81
74
|
{{/if}}
|
|
82
|
-
split: CURRENT_HOST_CONFIG.split,
|
|
83
|
-
splitTestId: CURRENT_HOST_CONFIG.splitTestId,
|
|
84
|
-
disabled: !CURRENT_HOST_CONFIG.enabled{{#if addPreRendering}} || isTablet(){{/if}},
|
|
85
75
|
{{#if useScrapingBee}}
|
|
86
76
|
customVariation: [
|
|
87
77
|
{
|
|
@@ -94,6 +84,9 @@
|
|
|
94
84
|
},
|
|
95
85
|
],
|
|
96
86
|
{{/if}}
|
|
87
|
+
split: CURRENT_HOST_CONFIG.split,
|
|
88
|
+
splitTestId: CURRENT_HOST_CONFIG.splitTestId,
|
|
89
|
+
disabled: !CURRENT_HOST_CONFIG.enabled,
|
|
97
90
|
enabledSites: [
|
|
98
91
|
{
|
|
99
92
|
pathname: [
|
|
@@ -150,12 +143,6 @@
|
|
|
150
143
|
{{/if}}
|
|
151
144
|
],
|
|
152
145
|
blacklist: [
|
|
153
|
-
{{#if addPreRendering}}
|
|
154
|
-
// blacklist tv variations
|
|
155
|
-
{
|
|
156
|
-
tv: true,
|
|
157
|
-
},
|
|
158
|
-
{{/if}}
|
|
159
146
|
{
|
|
160
147
|
pathname: [
|
|
161
148
|
// TODO: adjust/replace this exemplary list
|
|
@@ -1,56 +1,46 @@
|
|
|
1
1
|
{
|
|
2
|
-
"production": {
|
|
3
|
-
"_meta": {
|
|
4
|
-
"shopSystem":
|
|
5
|
-
{{#if isShopify}}
|
|
6
|
-
|
|
7
|
-
{{else if isShopware}}
|
|
8
|
-
|
|
9
|
-
{{else if isSalesforce}}
|
|
10
|
-
|
|
11
|
-
{{else if isOxid}}
|
|
12
|
-
|
|
13
|
-
{{else if isPlentymarkets}}
|
|
14
|
-
|
|
15
|
-
{{else}}
|
|
16
|
-
|
|
17
|
-
{{/if}}
|
|
18
|
-
},
|
|
19
|
-
"app": "{{appName}}",
|
|
20
|
-
"domain": "{{production.host}}",
|
|
21
|
-
"origins": [
|
|
22
|
-
"https://{{production.host}}"
|
|
23
|
-
],
|
|
24
|
-
{{#if isShopify}}
|
|
25
|
-
|
|
26
|
-
{{else}}
|
|
27
|
-
|
|
28
|
-
{{/if}}
|
|
29
|
-
{{#if subRouteScope}}
|
|
30
|
-
|
|
31
|
-
{{else}}
|
|
32
|
-
|
|
33
|
-
{{/if}}
|
|
34
|
-
"forceInstall": {{production.forceInstall}}
|
|
35
|
-
}
|
|
36
|
-
{{#if staging.host}},
|
|
37
|
-
"staging": {
|
|
38
|
-
"name": "staging",
|
|
39
|
-
"domain": "{{staging.host}}",
|
|
40
|
-
"origins": [
|
|
41
|
-
"https://{{staging.host}}"
|
|
42
|
-
],
|
|
43
|
-
"forceInstall": {{staging.forceInstall}},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
{{else}}
|
|
47
|
-
"swPath": "/wrapper-sw.js",
|
|
48
|
-
{{/if}}
|
|
49
|
-
{{#if subRouteScope}}
|
|
50
|
-
"scope": "/{{subRouteScope}}/"
|
|
51
|
-
{{else}}
|
|
52
|
-
"scope": "/"
|
|
53
|
-
{{/if}}
|
|
54
|
-
}
|
|
55
|
-
{{/if}}
|
|
2
|
+
"production": {
|
|
3
|
+
"_meta": {
|
|
4
|
+
"shopSystem":
|
|
5
|
+
{{#if isShopify}}
|
|
6
|
+
"Shopify"
|
|
7
|
+
{{else if isShopware}}
|
|
8
|
+
"Shopware"
|
|
9
|
+
{{else if isSalesforce}}
|
|
10
|
+
"Salesforce Commerce Cloud"
|
|
11
|
+
{{else if isOxid}}
|
|
12
|
+
"OXID eShop"
|
|
13
|
+
{{else if isPlentymarkets}}
|
|
14
|
+
"Plentymarkets"
|
|
15
|
+
{{else}}
|
|
16
|
+
"TODO: enter name of system in use"
|
|
17
|
+
{{/if}}
|
|
18
|
+
},
|
|
19
|
+
"app": "{{appName}}",
|
|
20
|
+
"domain": "{{production.host}}",
|
|
21
|
+
"origins": [
|
|
22
|
+
"https://{{production.host}}"
|
|
23
|
+
],
|
|
24
|
+
{{#if isShopify}}
|
|
25
|
+
"swPath": "/apps/speed-kit/sw.js",
|
|
26
|
+
{{else}}
|
|
27
|
+
"swPath": "/wrapper-sw.js",
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{#if subRouteScope}}
|
|
30
|
+
"scope": "/{{subRouteScope}}/",
|
|
31
|
+
{{else}}
|
|
32
|
+
"scope": "/",
|
|
33
|
+
{{/if}}
|
|
34
|
+
"forceInstall": {{production.forceInstall}}
|
|
35
|
+
}
|
|
36
|
+
{{#if staging.host}},
|
|
37
|
+
"staging": {
|
|
38
|
+
"name": "staging",
|
|
39
|
+
"domain": "{{staging.host}}",
|
|
40
|
+
"origins": [
|
|
41
|
+
"https://{{staging.host}}"
|
|
42
|
+
],
|
|
43
|
+
"forceInstall": {{staging.forceInstall}},
|
|
44
|
+
}
|
|
45
|
+
{{/if}}
|
|
56
46
|
}
|
|
@@ -1,53 +1,51 @@
|
|
|
1
|
-
{{#
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
1
|
+
{{#if removeLazyLoading}}
|
|
2
|
+
const lazyLoadDefaultConfig = {
|
|
3
|
+
attributes: [
|
|
4
|
+
// TODO adjust based on if original attribute should be preserved or renamed
|
|
5
|
+
// when using find and set the original attribute is preserved
|
|
6
|
+
// when using find and rename the original attribute is renamed
|
|
7
|
+
{find: 'data-src', set: 'src'},
|
|
8
|
+
{find: 'data-srcset', set: 'srcset'},
|
|
9
|
+
],
|
|
10
|
+
lazyClass: 'lazyload',
|
|
11
|
+
lazyLoad: false,
|
|
12
|
+
preload: true // preload lazy-removed images in head
|
|
13
|
+
}
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const lazyLoadList = [
|
|
16
|
+
// TODO: adjust/replace this exemplary list
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
// Content page's stage image:
|
|
19
|
+
{
|
|
20
|
+
...lazyLoadDefaultConfig,
|
|
21
|
+
parentClasses: [
|
|
22
|
+
'image-with-text-overlay__banner',
|
|
23
|
+
],
|
|
24
|
+
limit: 1
|
|
25
|
+
},
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
// PLP product images:
|
|
28
|
+
{
|
|
29
|
+
...lazyLoadDefaultConfig,
|
|
30
|
+
parentClasses: [
|
|
31
|
+
'product-image__wrapper',
|
|
32
|
+
],
|
|
33
|
+
limit: 4
|
|
34
|
+
},
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
// PDP hero image:
|
|
37
|
+
{
|
|
38
|
+
...lazyLoadDefaultConfig,
|
|
39
|
+
parentClasses: [
|
|
40
|
+
'product-gallery__image',
|
|
41
|
+
],
|
|
42
|
+
limit: 1
|
|
43
|
+
},
|
|
44
|
+
];
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
{{/unless}}
|
|
46
|
+
{{/if}}
|
|
49
47
|
const config = {
|
|
50
|
-
rejectHTML({db,
|
|
48
|
+
rejectHTML({db, document, variation, url, headers}) {
|
|
51
49
|
/* Use to configure guards to prevent e.g. error and captcha pages from being cached */
|
|
52
50
|
{{#if isPlentymarkets}}
|
|
53
51
|
// we don't want to cache CSR pages
|
|
@@ -59,59 +57,58 @@ const config = {
|
|
|
59
57
|
return false;
|
|
60
58
|
{{/if}}
|
|
61
59
|
},
|
|
62
|
-
blacklistHTML({db,
|
|
60
|
+
blacklistHTML({db, document, variation, url, headers}) {
|
|
63
61
|
/* Use to configure guards to black-list e.g. specific page types */
|
|
64
|
-
{{#if addPreRendering}}
|
|
65
|
-
// dynamically blacklist unsupported variations as they are not covered in lambda
|
|
66
|
-
if (variation.toUpperCase() === "TABLET") {
|
|
67
|
-
return `Tablet viewport is unsupported: ${url}`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
{{/if}}
|
|
71
62
|
{{#if useScrapingBee}}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
63
|
+
|
|
64
|
+
// dynamically blacklist not 200 status codes from ScrapingBee
|
|
65
|
+
const spbStatusCode = headers["Spb-initial-status-code"];
|
|
66
|
+
if (spbStatusCode && spbStatusCode !== "200") {
|
|
67
|
+
return `initial status code unequal to 200 received from scrapingbee: ${url} ${spbStatusCode}`;
|
|
68
|
+
}
|
|
77
69
|
{{/if}}
|
|
70
|
+
|
|
78
71
|
return false;
|
|
79
72
|
},
|
|
80
|
-
shouldTransform({db,
|
|
73
|
+
shouldTransform({db, document, variation, url, headers}) {
|
|
81
74
|
return true;
|
|
82
75
|
},
|
|
83
|
-
shouldDelayDom({db,
|
|
76
|
+
shouldDelayDom({db, document, variation, url, headers}) {
|
|
84
77
|
{{#if isPlentymarkets}}
|
|
85
78
|
return false; // Plentymarkets specific
|
|
86
79
|
{{else}}
|
|
87
80
|
return true;
|
|
88
81
|
{{/if}}
|
|
89
82
|
},
|
|
90
|
-
async preTransform({db,
|
|
91
|
-
{{#
|
|
92
|
-
|
|
93
|
-
{{else}}
|
|
83
|
+
async preTransform({db, document, variation, url, headers}) {
|
|
84
|
+
{{#if addPreRendering}}
|
|
85
|
+
// SSR specific:
|
|
94
86
|
generateMainShadowRoot(document);
|
|
95
|
-
{{/unless}}
|
|
96
|
-
},
|
|
97
|
-
async postTransform({db, {{#if addPreRendering}}document{{else}}html{{/if}}, variation, url, headers}) {
|
|
98
|
-
{{#unless addPreRendering}}
|
|
99
|
-
{{#if includeServiceWorker}}
|
|
100
|
-
html = injectServiceWorkerScript(html, '{{includeServiceWorker}}');
|
|
101
|
-
{{/if}}
|
|
102
|
-
return html;
|
|
103
87
|
{{else}}
|
|
88
|
+
// do nothing
|
|
89
|
+
{{/if}}
|
|
90
|
+
},
|
|
91
|
+
async postTransform({db, document, variation, url, headers}) {
|
|
92
|
+
{{#if includeServiceWorker}}
|
|
93
|
+
injectServiceWorkerScript(document, '{{includeServiceWorker}}');
|
|
94
|
+
|
|
95
|
+
{{/if}}
|
|
96
|
+
{{#if addSSR}}
|
|
97
|
+
// SSR specific:
|
|
104
98
|
createPreloadsForInnerStyleLinks(document);
|
|
105
99
|
removeInnerScriptNodes(document);
|
|
106
|
-
|
|
100
|
+
assignDynamicStylesToShadowDom(document);
|
|
107
101
|
addDeclarativeShadowDOMPolyfill(document);
|
|
102
|
+
wrapPreRenderedElementsWithCustomRootTags(document);
|
|
108
103
|
addPolyFillAfterMainPreRenderTemplate(document);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
triggerShadowRendering(document);
|
|
105
|
+
{{#if addSSRInnerShadowDomSupport}}
|
|
106
|
+
|
|
107
|
+
overrideCustomElementDefine(document);
|
|
108
|
+
walkPreRenderedElements(document);
|
|
109
|
+
{{/if}}
|
|
110
|
+
{{else}}
|
|
111
|
+
// do nothing
|
|
115
112
|
{{/if}}
|
|
116
113
|
},
|
|
117
114
|
{{#if isPlentymarkets}}
|
|
@@ -130,11 +127,12 @@ const config = {
|
|
|
130
127
|
{{else}}
|
|
131
128
|
executeDeploymentDetection: true,
|
|
132
129
|
{{/if}}
|
|
133
|
-
{{#
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
{{#if removeLazyLoading}}
|
|
131
|
+
lazyLoadList,
|
|
132
|
+
{{/if}}
|
|
133
|
+
{{#if addSSR}}
|
|
134
|
+
|
|
135
|
+
// SSR specific:
|
|
138
136
|
preRender: {
|
|
139
137
|
lambdaUrl: '<generate-new-lambda-function-and-paste-url-endpoint-here>',
|
|
140
138
|
elements: [
|
|
@@ -147,11 +145,11 @@ const config = {
|
|
|
147
145
|
"body > style",
|
|
148
146
|
"body > link[rel='stylesheet'][href]",
|
|
149
147
|
].join(","),
|
|
150
|
-
appendTo: "
|
|
148
|
+
appendTo: "sk-shadow-app-root > template",
|
|
151
149
|
},
|
|
152
150
|
// this will be the main element to extract from the rendered DOM
|
|
153
151
|
// TODO change selector to the main element of your page
|
|
154
|
-
{ selector: "body > #app", appendTo: "
|
|
152
|
+
{ selector: "body > #app", appendTo: "sk-shadow-app-root > template" },
|
|
155
153
|
],
|
|
156
154
|
guards: [
|
|
157
155
|
{
|
|
@@ -160,7 +158,7 @@ const config = {
|
|
|
160
158
|
// e.g. wait for first 4 images to be loaded
|
|
161
159
|
'.products-list-page__products-list .products-list__tiles__element:nth-child(-n+4) img[src=""]',
|
|
162
160
|
],
|
|
163
|
-
{{#if
|
|
161
|
+
{{#if addSSRInnerShadowDomSupport}}
|
|
164
162
|
waitForCallback: waitForCallback.toString(),
|
|
165
163
|
{{/if}}
|
|
166
164
|
},
|
|
@@ -182,10 +180,10 @@ const config = {
|
|
|
182
180
|
],
|
|
183
181
|
},
|
|
184
182
|
},
|
|
185
|
-
{{/
|
|
183
|
+
{{/if}}
|
|
186
184
|
}
|
|
187
185
|
|
|
188
|
-
const documentHandler = new
|
|
186
|
+
const documentHandler = new DomDocumentHandler({
|
|
189
187
|
...config,
|
|
190
188
|
app: APP,
|
|
191
189
|
dynamicFetcher: DYNAMIC_FETCHER,
|
|
@@ -196,44 +194,42 @@ const documentHandler = new {{#if addPreRendering}}DomDocumentHandler{{else}}Doc
|
|
|
196
194
|
export const post = async (db, req, res) => {
|
|
197
195
|
await documentHandler.transformAndSend(db, req, res);
|
|
198
196
|
}
|
|
199
|
-
{{#
|
|
200
|
-
{{#if includeServiceWorker}}
|
|
201
|
-
|
|
202
|
-
//================================================================================
|
|
203
|
-
// Utility Functions
|
|
204
|
-
//================================================================================
|
|
205
|
-
|
|
206
|
-
function prepend(string, searchString, prependString) {
|
|
207
|
-
const index = string.lastIndexOf(searchString);
|
|
208
|
-
return string.slice(0, index) + prependString + string.slice(index);
|
|
209
|
-
}
|
|
197
|
+
{{#if includeServiceWorker}}
|
|
210
198
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Injects a script into the document to override the service worker registration.
|
|
201
|
+
*
|
|
202
|
+
* @param {Document} document - The document object where the script will be injected.
|
|
203
|
+
* @param {string} searchedSwPath - The path of the service worker to be overridden.
|
|
204
|
+
*/
|
|
205
|
+
function injectServiceWorkerScript(document, searchedSwPath) {
|
|
206
|
+
const swScript = document.createElement("script");
|
|
207
|
+
swScript.setAttribute("id", "speed-kit-service-worker");
|
|
208
|
+
swScript.type = 'text/javascript';
|
|
209
|
+
swScript.innerHTML = `
|
|
210
|
+
var serviceWorkerRegister = ServiceWorkerContainer.prototype.register;
|
|
211
|
+
ServiceWorkerContainer.prototype.register = function (swPath, options) {
|
|
216
212
|
if (swPath.indexOf('${searchedSwPath}') === 0 && SpeedKit.group === 'A') {
|
|
217
|
-
|
|
213
|
+
return navigator.serviceWorker.getRegistration();
|
|
218
214
|
}
|
|
219
215
|
return serviceWorkerRegister.call(this, swPath, options);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
{{
|
|
216
|
+
};`;
|
|
217
|
+
|
|
218
|
+
document.head.appendChild(swScript);
|
|
219
|
+
}
|
|
220
|
+
{{/if}}
|
|
221
|
+
{{#if addSSR}}
|
|
226
222
|
|
|
227
|
-
{{#if addPreRendering}}
|
|
228
223
|
/**
|
|
229
224
|
* Generates the main shadow root for the given DOM.
|
|
230
225
|
* This is the parent element of the extracted pre-rendered content.
|
|
226
|
+
*
|
|
231
227
|
* @param document
|
|
232
228
|
*/
|
|
233
229
|
function generateMainShadowRoot(document) {
|
|
234
|
-
const customContainer = document.createElement("
|
|
235
|
-
customContainer.
|
|
236
|
-
|
|
230
|
+
const customContainer = document.createElement("sk-shadow-app-root");
|
|
231
|
+
customContainer.setAttribute("aria-hidden", "true"); // hide from screen readers
|
|
232
|
+
|
|
237
233
|
const template = document.createElement("template");
|
|
238
234
|
template.setAttribute("shadowrootmode", "open");
|
|
239
235
|
customContainer.appendChild(template);
|
|
@@ -245,21 +241,22 @@ export const post = async (db, req, res) => {
|
|
|
245
241
|
* Creates preloads for inner style links in the given document.
|
|
246
242
|
*
|
|
247
243
|
* @param {Document} document - The document object to search for inner style links.
|
|
248
|
-
*
|
|
249
244
|
* @return {void}
|
|
250
245
|
*/
|
|
251
246
|
function createPreloadsForInnerStyleLinks(document) {
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
247
|
+
const customShadowRoots = getCustomShadowElements(document);
|
|
248
|
+
for (const customShadowRoot of customShadowRoots) {
|
|
249
|
+
const innerStyleLinks = customShadowRoot.querySelectorAll('link[rel="stylesheet"][href]');
|
|
250
|
+
|
|
251
|
+
const head = document.querySelector("head");
|
|
252
|
+
innerStyleLinks.forEach((styleLink) => {
|
|
253
|
+
const link = document.createElement("link");
|
|
254
|
+
link.setAttribute("rel", "preload");
|
|
255
|
+
link.setAttribute("as", "stylesheet");
|
|
256
|
+
link.setAttribute("href", styleLink.getAttribute("href"));
|
|
257
|
+
head.append(link);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
263
260
|
}
|
|
264
261
|
|
|
265
262
|
/**
|
|
@@ -269,25 +266,28 @@ export const post = async (db, req, res) => {
|
|
|
269
266
|
*/
|
|
270
267
|
function removeInnerScriptNodes(document) {
|
|
271
268
|
// remove all innerShadowDom script, as they would be executed again
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
269
|
+
const customShadowRoots = getCustomShadowElements(document);
|
|
270
|
+
for (const customShadowRoot of customShadowRoots) {
|
|
271
|
+
Array.from(customShadowRoot.querySelectorAll("script")).forEach((scriptNode) => scriptNode.remove());
|
|
272
|
+
}
|
|
275
273
|
}
|
|
276
274
|
|
|
277
275
|
/**
|
|
278
|
-
* Assigns styles to the Shadow DOM of specified document.
|
|
276
|
+
* Assigns dynamic styles to the Shadow DOM of specified document.
|
|
279
277
|
*
|
|
280
278
|
* @param {Document} document - The document object to which styles are to be assigned.
|
|
281
279
|
* @throws {Abort} Throws an error if `skStyles` is not found.
|
|
282
280
|
*/
|
|
283
|
-
function
|
|
284
|
-
const skStyles = document.querySelector(
|
|
281
|
+
function assignDynamicStylesToShadowDom(document) {
|
|
282
|
+
const skStyles = document.querySelector("#speed-kit-df-styles");
|
|
285
283
|
|
|
286
284
|
if (!skStyles) {
|
|
287
|
-
throw new Abort("
|
|
285
|
+
throw new Abort("#speed-kit-df-styles not found");
|
|
288
286
|
}
|
|
289
287
|
const clonedStyles = document.createElement("style");
|
|
290
|
-
|
|
288
|
+
for (const attr of skStyles.attributes) {
|
|
289
|
+
clonedStyles.setAttribute(attr.name, attr.value);
|
|
290
|
+
}
|
|
291
291
|
clonedStyles.textContent = skStyles.textContent;
|
|
292
292
|
|
|
293
293
|
const customShadowElements = getCustomShadowElements(document);
|
|
@@ -298,15 +298,17 @@ export const post = async (db, req, res) => {
|
|
|
298
298
|
|
|
299
299
|
/**
|
|
300
300
|
* Helper function to select all template elements.
|
|
301
|
+
*
|
|
301
302
|
* @param document
|
|
302
303
|
* @returns {*}
|
|
303
304
|
*/
|
|
304
305
|
function getCustomShadowElements(document) {
|
|
305
|
-
return document.querySelectorAll("
|
|
306
|
+
return document.querySelectorAll("sk-shadow-app-root > template");
|
|
306
307
|
}
|
|
307
308
|
|
|
308
309
|
/**
|
|
309
310
|
* Adds the declarative shadow dom polyfill to the head of the document.
|
|
311
|
+
*
|
|
310
312
|
* @param document
|
|
311
313
|
*/
|
|
312
314
|
function addDeclarativeShadowDOMPolyfill(document) {
|
|
@@ -324,7 +326,6 @@ export const post = async (db, req, res) => {
|
|
|
324
326
|
* https://developer.chrome.com/docs/css-ui/declarative-shadow-dom#polyfill
|
|
325
327
|
*
|
|
326
328
|
* @param {HTMLTemplateElement} template - The template element to be transformed into a Shadow Root.
|
|
327
|
-
*
|
|
328
329
|
* @constructor
|
|
329
330
|
*/
|
|
330
331
|
function SKShadowRootsPolyfill(template) {
|
|
@@ -344,49 +345,92 @@ export const post = async (db, req, res) => {
|
|
|
344
345
|
}
|
|
345
346
|
|
|
346
347
|
/**
|
|
347
|
-
*
|
|
348
|
+
* Wraps pre-rendered elements with custom sk-html and sk-body tags.
|
|
349
|
+
*
|
|
348
350
|
* @param document
|
|
349
351
|
*/
|
|
350
|
-
function
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if (
|
|
357
|
-
|
|
352
|
+
function wrapPreRenderedElementsWithCustomRootTags(document) {
|
|
353
|
+
const customShadowRoots = getCustomShadowElements(document);
|
|
354
|
+
|
|
355
|
+
function createCustomElement(tagName, sourceSelector) {
|
|
356
|
+
const el = document.createElement(tagName);
|
|
357
|
+
const source = document.querySelector(sourceSelector);
|
|
358
|
+
if (source) {
|
|
359
|
+
for (const attr of source.attributes) {
|
|
360
|
+
el.setAttribute(attr.name, attr.value);
|
|
361
|
+
}
|
|
358
362
|
}
|
|
363
|
+
return el;
|
|
364
|
+
}
|
|
359
365
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
366
|
+
for (const customShadowRoot of customShadowRoots) {
|
|
367
|
+
const skHtml = createCustomElement("sk-html", "html");
|
|
368
|
+
const skBody = createCustomElement("sk-body", "body");
|
|
369
|
+
|
|
370
|
+
// move all children from the shadow root element into sk-body
|
|
371
|
+
while (customShadowRoot.firstChild) {
|
|
372
|
+
// remove class which is no longer needed
|
|
373
|
+
customShadowRoot.firstChild.classList.remove("speed-kit-pre-rendered-block-added");
|
|
374
|
+
|
|
375
|
+
// move element to sk-body
|
|
376
|
+
skBody.appendChild(customShadowRoot.firstChild);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// append sk-body inside sk-html
|
|
380
|
+
skHtml.appendChild(skBody);
|
|
381
|
+
|
|
382
|
+
// append sk-html into the shadow root element
|
|
383
|
+
customShadowRoot.appendChild(skHtml);
|
|
384
|
+
}
|
|
365
385
|
}
|
|
366
386
|
|
|
367
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Calls the polyfill for shadowRoots after the main pre-rendered template.
|
|
389
|
+
*
|
|
390
|
+
* @param document
|
|
391
|
+
*/
|
|
392
|
+
function addPolyFillAfterMainPreRenderTemplate(document) {
|
|
368
393
|
const customShadowRoots = getCustomShadowElements(document);
|
|
394
|
+
for (const customShadowRoot of customShadowRoots) {
|
|
395
|
+
let topLevelPreRenderElements = customShadowRoot.querySelectorAll("sk-body > *");
|
|
396
|
+
topLevelPreRenderElements.forEach((element) => {
|
|
397
|
+
let topTemplate = element.querySelector('template[shadowrootmode="open"]');
|
|
398
|
+
if (!topTemplate) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
369
401
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
402
|
+
// polyfill for shadowRoots
|
|
403
|
+
let polyfillScript = document.createElement("script");
|
|
404
|
+
polyfillScript.textContent = `SKShadowRootsPolyfill(document?.currentScript?.previousElementSibling)`;
|
|
405
|
+
topTemplate.after(polyfillScript);
|
|
406
|
+
});
|
|
407
|
+
}
|
|
375
408
|
}
|
|
376
409
|
|
|
377
|
-
|
|
410
|
+
/**
|
|
411
|
+
* Forces rendering of elements within custom shadow DOMs by briefly toggling
|
|
412
|
+
* their visibility via injected style rules.
|
|
413
|
+
*
|
|
414
|
+
* @param document
|
|
415
|
+
*/
|
|
416
|
+
function triggerShadowRendering(document) {
|
|
378
417
|
const customShadowRoots = getCustomShadowElements(document);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
418
|
+
for (const customShadowRoot of customShadowRoots) {
|
|
419
|
+
const hidingStyle = document.createElement("style");
|
|
420
|
+
hidingStyle.textContent = `sk-html{visibility:hidden;}`;
|
|
421
|
+
customShadowRoot.prepend(hidingStyle);
|
|
422
|
+
|
|
423
|
+
const visibilityStyle = document.createElement("style");
|
|
424
|
+
visibilityStyle.textContent = `sk-html{visibility:visible;}`;
|
|
425
|
+
customShadowRoot.appendChild(visibilityStyle);
|
|
426
|
+
}
|
|
385
427
|
}
|
|
386
|
-
{{#if
|
|
428
|
+
{{#if addSSRInnerShadowDomSupport}}
|
|
429
|
+
|
|
387
430
|
//================================================================================
|
|
388
|
-
//
|
|
431
|
+
// Puppeteer Callback
|
|
389
432
|
//================================================================================
|
|
433
|
+
|
|
390
434
|
/**
|
|
391
435
|
* Waits for the callback when custom elements are defined on the document.
|
|
392
436
|
*
|
|
@@ -465,7 +509,7 @@ export const post = async (db, req, res) => {
|
|
|
465
509
|
return instance;
|
|
466
510
|
};
|
|
467
511
|
|
|
468
|
-
// create a dynamic proxy class which
|
|
512
|
+
// create a dynamic proxy class which is overwriting all lifecycle hooks of the original class
|
|
469
513
|
skProxy.prototype = Object.create(o.prototype, {
|
|
470
514
|
constructor: {
|
|
471
515
|
value: skProxy,
|
|
@@ -495,7 +539,7 @@ export const post = async (db, req, res) => {
|
|
|
495
539
|
|
|
496
540
|
Object.setPrototypeOf(skProxy, o);
|
|
497
541
|
|
|
498
|
-
const skContainer = document.querySelector("
|
|
542
|
+
const skContainer = document.querySelector("sk-shadow-app-root");
|
|
499
543
|
let skContainerParentNode;
|
|
500
544
|
let skContainerNextNode;
|
|
501
545
|
if (skContainer) {
|
|
@@ -560,6 +604,5 @@ export const post = async (db, req, res) => {
|
|
|
560
604
|
}
|
|
561
605
|
});
|
|
562
606
|
}
|
|
563
|
-
{{else}}
|
|
564
607
|
{{/if}}
|
|
565
608
|
{{/if}}
|
|
@@ -4,20 +4,21 @@
|
|
|
4
4
|
*/
|
|
5
5
|
window.dynamicBlockConfig = {
|
|
6
6
|
dynamicScriptExecution: true,
|
|
7
|
-
{{#if
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
7
|
+
{{#if addDeviceDetection}}
|
|
8
|
+
{{#unless addSSR}}
|
|
9
|
+
detectDevice: (doc) => {
|
|
10
|
+
// keep only if you need to check the DOM – for screen width checks the SK config's detectDevice is sufficient
|
|
11
|
+
|
|
12
|
+
// TODO: adjust condition to your needs
|
|
13
|
+
return doc.querySelector('<mobile-specific-element>') ? "mobile" : "desktop";
|
|
14
|
+
},
|
|
15
|
+
{{/unless}}
|
|
16
16
|
{{/if}}
|
|
17
17
|
blocks: [
|
|
18
18
|
// TODO: adjust/replace this exemplary list
|
|
19
19
|
{
|
|
20
20
|
selector: "body",
|
|
21
|
+
{{#unless addSSR}}
|
|
21
22
|
detectChanges: [
|
|
22
23
|
// Main Headline:
|
|
23
24
|
{
|
|
@@ -56,12 +57,14 @@
|
|
|
56
57
|
compare: ["src"],
|
|
57
58
|
},
|
|
58
59
|
],
|
|
60
|
+
{{/unless}}
|
|
59
61
|
},
|
|
60
62
|
{{#if isShopify}}
|
|
63
|
+
|
|
61
64
|
// Shopify specific:
|
|
62
65
|
{
|
|
63
66
|
selector: "#shopify-section-announcement-bar",
|
|
64
|
-
{{#unless
|
|
67
|
+
{{#unless addSSR}}
|
|
65
68
|
merge: false, // TODO: remove if body is not the main block
|
|
66
69
|
{{/unless}}
|
|
67
70
|
detectChanges: [{
|
|
@@ -110,31 +113,55 @@
|
|
|
110
113
|
{ selector: 'meta[property]', idAttribute: "property"},
|
|
111
114
|
{ selector: 'script[type="application/ld+json"]'},
|
|
112
115
|
],
|
|
113
|
-
|
|
116
|
+
{{#if addSSR}}
|
|
117
|
+
|
|
118
|
+
// SSR specific:
|
|
119
|
+
prerendered: [{ selector: "body > sk-shadow-app-root" }],
|
|
114
120
|
preRenderedRootConfig: [
|
|
115
121
|
// TODO: adjust/replace this exemplary list
|
|
116
122
|
{
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
selector: "sk-body",
|
|
124
|
+
remoteSelector: "body",
|
|
125
|
+
detectChanges: [
|
|
126
|
+
// Main Headline:
|
|
127
|
+
{
|
|
128
|
+
find: "h1",
|
|
129
|
+
compare: ["text"],
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// Top Banner:
|
|
133
|
+
{
|
|
134
|
+
find: ".header .top-banner",
|
|
135
|
+
compare: ["text"],
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
// First-Level Items of Header/Main Navigation:
|
|
139
|
+
{
|
|
140
|
+
find: ".header .main-navigation .first-level-item",
|
|
141
|
+
compare: ["text"],
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
// Stage Teaser:
|
|
145
|
+
{
|
|
146
|
+
find: ".stage-teaser source",
|
|
147
|
+
compare: ["srcset"],
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// PLP Items:
|
|
151
|
+
{
|
|
152
|
+
find: ".product-grid .product img",
|
|
153
|
+
limit: 9, // only compare the first 9 products
|
|
154
|
+
compare: ["src"],
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
// PDP Hero Image:
|
|
158
|
+
{
|
|
159
|
+
find: ".product-detail .slide.main img",
|
|
160
|
+
compare: ["src"],
|
|
161
|
+
},
|
|
135
162
|
],
|
|
136
163
|
},
|
|
137
|
-
|
|
138
|
-
|
|
164
|
+
],
|
|
165
|
+
{{/if}}
|
|
139
166
|
};
|
|
140
167
|
})();
|
|
@@ -24,20 +24,36 @@
|
|
|
24
24
|
background-position: calc(100% + 400px) 0;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
{{#if addSSR}}
|
|
28
|
+
|
|
29
|
+
/* SSR specific – positioning for pre-rendered container */
|
|
30
|
+
.speed-kit-pre-rendered sk-shadow-app-root {
|
|
31
|
+
position: absolute;
|
|
32
|
+
top: 0;
|
|
33
|
+
width: 100%;
|
|
34
|
+
left: 0;
|
|
35
|
+
right: 0;
|
|
36
|
+
z-index: 99999;
|
|
37
|
+
background: #fff;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
SSR specific:
|
|
42
|
+
remember to use sk-html/sk-body as additional selectors if you reference html/body to also cover the SSR case
|
|
43
|
+
*/
|
|
44
|
+
{{/if}}
|
|
27
45
|
{{#if withGoogleOptimize}}
|
|
28
46
|
|
|
29
47
|
/* Google Optimize Flicker Fix: */
|
|
48
|
+
{{#if addSSR}}
|
|
49
|
+
sk-html > sk-body,
|
|
50
|
+
{{/if}}
|
|
30
51
|
html > body {
|
|
31
52
|
opacity: 1 !important;
|
|
32
53
|
}
|
|
33
54
|
{{/if}}
|
|
34
55
|
|
|
35
56
|
.speed-kit-dynamic-loading {
|
|
36
|
-
{{#if addPreRendering}}
|
|
37
|
-
/* TODO: use the following wrapping selector if you want to apply those styles to the pre-rendered block instead: */
|
|
38
|
-
/* .speed-kit-pre-rendered-block-added */
|
|
39
|
-
{{/if}}
|
|
40
|
-
|
|
41
57
|
.dummy-price-class,
|
|
42
58
|
.dummy-availability-class {
|
|
43
59
|
visibility: hidden;
|
|
@@ -75,7 +91,6 @@ html > body {
|
|
|
75
91
|
}
|
|
76
92
|
}
|
|
77
93
|
|
|
78
|
-
|
|
79
94
|
/* Prevent Add2Cart clicks: */
|
|
80
95
|
.dummy-add2cart-class {
|
|
81
96
|
pointer-events: none !important;
|
|
@@ -111,16 +126,3 @@ html > body {
|
|
|
111
126
|
mask-repeat: no-repeat;
|
|
112
127
|
}
|
|
113
128
|
}
|
|
114
|
-
{{#if addPreRendering}}
|
|
115
|
-
|
|
116
|
-
/* Positioning for pre-rendered containers */
|
|
117
|
-
html.speed-kit-pre-rendered body > .speed-kit-shadow-app-root {
|
|
118
|
-
position: absolute;
|
|
119
|
-
top: 0;
|
|
120
|
-
width: 100%;
|
|
121
|
-
left: 0;
|
|
122
|
-
right: 0;
|
|
123
|
-
z-index: 99999;
|
|
124
|
-
background: #fff;
|
|
125
|
-
}
|
|
126
|
-
{{/if}}
|
package/oclif.manifest.json
CHANGED