@speedkit/cli 3.2.0 → 3.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 +21 -0
- package/README.md +1 -1
- package/dist/helpers/cli-config.d.ts +1 -0
- package/dist/helpers/cli-config.js +2 -0
- package/dist/services/customer-config/customer-config-service-model.d.ts +1 -0
- package/dist/services/customer-config/customer-config-service.js +3 -1
- package/dist/services/customer-config/templates/config_SpeedKit.js.hbs +8 -0
- package/dist/services/customer-config/templates/config_dynamicBlocks.es6.hbs +6 -1
- package/dist/services/onboarding/browser/executable/executable-validator.d.ts +12 -0
- package/dist/services/onboarding/browser/executable/executable-validator.js +90 -0
- package/dist/services/onboarding/onboarding-service-factory.js +3 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [3.4.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.3.0...v3.4.0) (2025-08-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* escape path to browserExecutable for validator ([aafcecf](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/aafcecf3433a053aa87229492b4c8aca6b28867f))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **onboarding:** ask to download chrome ([c2e8f01](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/c2e8f0140bae117be04cb9da580318306aa0c285))
|
|
12
|
+
* **onboarding:** set correctPath to validate executable exists ([3d6a4dd](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/3d6a4dd68089937866c49ed60bdaece49e63083b))
|
|
13
|
+
|
|
14
|
+
# [3.3.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.2.0...v3.3.0) (2025-08-14)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **wizard:** extend questionnaire ([b36eb9f](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/b36eb9f595f904bd342907408bf40d1ba80c923b))
|
|
20
|
+
* **wizard:** extend questionnaire ([c1770cd](https://gitlab.orestes.info/baqend/speed-kit-cli/commit/c1770cd8642e71c69310659cae9835e4e4db838f))
|
|
21
|
+
|
|
1
22
|
# [3.2.0](https://gitlab.orestes.info/baqend/speed-kit-cli/compare/v3.1.2...v3.2.0) (2025-08-13)
|
|
2
23
|
|
|
3
24
|
|
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ class CliConfig {
|
|
|
29
29
|
slackToken: "",
|
|
30
30
|
testApp: "",
|
|
31
31
|
tempFolder: "/tmp",
|
|
32
|
+
runtimeConfig: {},
|
|
32
33
|
};
|
|
33
34
|
constructor(config) {
|
|
34
35
|
this.config = config;
|
|
@@ -40,6 +41,7 @@ class CliConfig {
|
|
|
40
41
|
this.loadConfigFromEnvironment();
|
|
41
42
|
this.resolveExtensionConfigPaths();
|
|
42
43
|
this.userCliConfig.tempFolder = this.config.cacheDir;
|
|
44
|
+
this.userCliConfig.runtimeConfig = this.config;
|
|
43
45
|
return this.userCliConfig;
|
|
44
46
|
}
|
|
45
47
|
createEmptyConfigFile() {
|
|
@@ -30,6 +30,7 @@ export interface CustomerConfigSettings {
|
|
|
30
30
|
activateImageOptimisation?: boolean;
|
|
31
31
|
removeLazyLoading?: boolean;
|
|
32
32
|
addPreRendering?: boolean;
|
|
33
|
+
addUADetection?: boolean;
|
|
33
34
|
supportShadowDomInPreRendering?: boolean;
|
|
34
35
|
shadowDomCustomElementPrefix?: string;
|
|
35
36
|
activateRumTracking?: 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, addPreRendering, supportShadowDomInPreRendering, shadowDomCustomElementPrefix, activateRumTracking, useGATracking, useScrapingBee, withGoogleOptimize, activateCfRocketLoaderWorkaround, hasSoftNavigations, isShopify, isShopware, isSalesforce, isOxid, isPlentymarkets, } = {};
|
|
139
|
+
let { production, staging, activateScopedDeployments, subRouteScope, includeServiceWorker, activateImageOptimisation, removeLazyLoading, addPreRendering, addUADetection, supportShadowDomInPreRendering, shadowDomCustomElementPrefix, activateRumTracking, useGATracking, useScrapingBee, withGoogleOptimize, activateCfRocketLoaderWorkaround, hasSoftNavigations, isShopify, isShopware, isSalesforce, isOxid, isPlentymarkets, } = {};
|
|
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,6 +181,7 @@ 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);
|
|
184
185
|
activateImageOptimisation = await this.cli.confirm("[IO] Should image optimisation be activated?", false);
|
|
185
186
|
removeLazyLoading = await this.cli.confirm("[Lazy-Loading] Does the shop require us to resolve lazy-loaded content?");
|
|
186
187
|
if (await this.cli.confirm("[Lambda-SSR] Add server-side-rendering? This requires a set-up Lambda function to work. Also requires usage of the DOM-based DocumentHandler.", false)) {
|
|
@@ -217,6 +218,7 @@ class CustomerConfigService {
|
|
|
217
218
|
activateImageOptimisation,
|
|
218
219
|
removeLazyLoading,
|
|
219
220
|
addPreRendering,
|
|
221
|
+
addUADetection,
|
|
220
222
|
supportShadowDomInPreRendering,
|
|
221
223
|
shadowDomCustomElementPrefix,
|
|
222
224
|
activateRumTracking,
|
|
@@ -70,6 +70,14 @@
|
|
|
70
70
|
{{#if addPreRendering}}
|
|
71
71
|
// Lambda SSR specific: detect device to cover different resolutions when rendered in lambda
|
|
72
72
|
userAgentDetection: true,
|
|
73
|
+
{{else if addUADetection}}
|
|
74
|
+
userAgentDetection: true,
|
|
75
|
+
{{/if}}
|
|
76
|
+
{{#if addUADetection}}
|
|
77
|
+
detectDevice: function(doc) {
|
|
78
|
+
// TODO adjust condition to your needs
|
|
79
|
+
return doc.querySelector('<mobile-specific-element>') ? "mobile" : "desktop";
|
|
80
|
+
},
|
|
73
81
|
{{/if}}
|
|
74
82
|
split: CURRENT_HOST_CONFIG.split,
|
|
75
83
|
splitTestId: CURRENT_HOST_CONFIG.splitTestId,
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
// ssr container
|
|
9
9
|
prerendered: [{ selector: "body > .speed-kit-shadow-app-root" }],
|
|
10
10
|
{{/if}}
|
|
11
|
-
|
|
11
|
+
{{#if addUADetection}}
|
|
12
|
+
detectDevice: (doc) => {
|
|
13
|
+
// TODO adjust condition to your needs
|
|
14
|
+
return doc.querySelector('<mobile-specific-element>') ? "mobile" : "desktop";
|
|
15
|
+
},
|
|
16
|
+
{{/if}}
|
|
12
17
|
blocks: [
|
|
13
18
|
// TODO: adjust/replace this exemplary list
|
|
14
19
|
{
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { UserCliConfig } from "../../../../helpers/cli-config";
|
|
2
|
+
import { CliServiceInterface } from "../../../cli";
|
|
3
|
+
export declare class ExecutableValidator {
|
|
4
|
+
readonly userConfig: UserCliConfig;
|
|
5
|
+
private cli;
|
|
6
|
+
constructor(userConfig: UserCliConfig, cli: CliServiceInterface);
|
|
7
|
+
validateOrInstall(): Promise<void>;
|
|
8
|
+
private getExecutablePathFromPuppeteer;
|
|
9
|
+
private isValidBrowserExecutable;
|
|
10
|
+
private cleanPath;
|
|
11
|
+
installBrowser(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExecutableValidator = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
// import CLI from puppeteer to use function as sames as `npx puppeteer browsers install`
|
|
6
|
+
const browsers_1 = require("@puppeteer/browsers");
|
|
7
|
+
const version_js_1 = require("puppeteer-core/internal/generated/version.js");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const application_error_1 = tslib_1.__importDefault(require("../../../error-handling/error/application-error"));
|
|
10
|
+
const browsers_2 = require("@puppeteer/browsers");
|
|
11
|
+
const node_path_1 = require("node:path");
|
|
12
|
+
class ExecutableValidator {
|
|
13
|
+
userConfig;
|
|
14
|
+
cli;
|
|
15
|
+
constructor(userConfig, cli) {
|
|
16
|
+
this.userConfig = userConfig;
|
|
17
|
+
this.cli = cli;
|
|
18
|
+
}
|
|
19
|
+
async validateOrInstall() {
|
|
20
|
+
// check if a valid browserExecutablePath is configured
|
|
21
|
+
const userChromePath = this.userConfig?.chromePath;
|
|
22
|
+
if (userChromePath.length > 0 &&
|
|
23
|
+
this.isValidBrowserExecutable(userChromePath)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// write error if configured path is not executable
|
|
27
|
+
if (userChromePath.length > 0) {
|
|
28
|
+
this.cli.writeError(`Invalid "chromePath" configured: ${userChromePath}`);
|
|
29
|
+
}
|
|
30
|
+
// check if a browser is installed via puppeteer
|
|
31
|
+
const puppeteerCache = new browsers_2.Cache(this.userConfig.tempFolder);
|
|
32
|
+
const installedBrowsers = puppeteerCache.getInstalledBrowsers();
|
|
33
|
+
if (installedBrowsers.length > 0) {
|
|
34
|
+
// found an installed browser, set path to this
|
|
35
|
+
this.userConfig.chromePath = installedBrowsers[0].executablePath;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// write warning that no browser is configured
|
|
39
|
+
if (userChromePath.length === 0) {
|
|
40
|
+
this.cli.writeWarning(`No Browser configured`);
|
|
41
|
+
}
|
|
42
|
+
// ask if you want to download stable chrome
|
|
43
|
+
const result = await this.cli.confirm("Do you want to download Chrome@latest via puppeteer?", true);
|
|
44
|
+
// @todo set more detailed error message here.
|
|
45
|
+
if (!result) {
|
|
46
|
+
throw new application_error_1.default("No Browser found to use", [
|
|
47
|
+
`set path to browser executable (chromePath) in ${this.userConfig.runtimeConfig.configDir}/config.json`,
|
|
48
|
+
`set path to browser executable (CHROME_PATH) in ./.env or as systemwide env`,
|
|
49
|
+
`let the ci download the latest chrome for you`,
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
// use puppeteerCli to download chrome
|
|
53
|
+
await this.installBrowser();
|
|
54
|
+
// set path to freshly installed chrome
|
|
55
|
+
this.userConfig.chromePath = this.getExecutablePathFromPuppeteer();
|
|
56
|
+
}
|
|
57
|
+
getExecutablePathFromPuppeteer() {
|
|
58
|
+
const puppeteerCache = new browsers_2.Cache(this.userConfig.tempFolder);
|
|
59
|
+
const installedBrowsers = puppeteerCache.getInstalledBrowsers();
|
|
60
|
+
return installedBrowsers[0].executablePath;
|
|
61
|
+
}
|
|
62
|
+
isValidBrowserExecutable(chromePath) {
|
|
63
|
+
return (0, node_fs_1.existsSync)(this.cleanPath((0, node_path_1.resolve)(chromePath)));
|
|
64
|
+
}
|
|
65
|
+
cleanPath(path) {
|
|
66
|
+
return path.trim().replaceAll(" ", "\\ ");
|
|
67
|
+
}
|
|
68
|
+
async installBrowser() {
|
|
69
|
+
const puppeteerCli = new browsers_1.CLI({
|
|
70
|
+
cachePath: this.userConfig.tempFolder,
|
|
71
|
+
scriptName: "@puppeteer/browsers",
|
|
72
|
+
version: version_js_1.packageVersion,
|
|
73
|
+
prefixCommand: {
|
|
74
|
+
cmd: "browsers",
|
|
75
|
+
description: "Manage browsers of this Puppeteer installation",
|
|
76
|
+
},
|
|
77
|
+
allowCachePathOverride: false,
|
|
78
|
+
pinnedBrowsers: {
|
|
79
|
+
[browsers_1.Browser.CHROME]: {
|
|
80
|
+
buildId: "stable",
|
|
81
|
+
skipDownload: false,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
// first two parameters would be npx puppeteer, when used outside sk-cli
|
|
86
|
+
await puppeteerCli.run(["", "", "browsers", "install"]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.ExecutableValidator = ExecutableValidator;
|
|
90
|
+
//
|
|
@@ -42,6 +42,7 @@ const path = tslib_1.__importStar(require("node:path"));
|
|
|
42
42
|
const static_recipe_1 = require("../integration-api/virtual/static-recipe");
|
|
43
43
|
const diff_against_current_page_1 = require("./dashboard/diff-against-current-page");
|
|
44
44
|
const extension_downloader_1 = require("./browser/extension/extension-downloader");
|
|
45
|
+
const executable_validator_1 = require("./browser/executable/executable-validator");
|
|
45
46
|
class OnboardingServiceFactory {
|
|
46
47
|
context;
|
|
47
48
|
cliConfig;
|
|
@@ -70,6 +71,8 @@ class OnboardingServiceFactory {
|
|
|
70
71
|
const extensionDownloader = new extension_downloader_1.ExtensionDownloader(this.cliConfig, cli);
|
|
71
72
|
const extensionPaths = await new extension_validator_1.ExtensionValidator(extensionDownloader, this.cliConfig, cli).getValidBrowserExtensionPaths();
|
|
72
73
|
this.cliConfig.chromeExtensionPaths = extensionPaths.join(",");
|
|
74
|
+
const browserValidator = new executable_validator_1.ExecutableValidator(this.cliConfig, cli);
|
|
75
|
+
await browserValidator.validateOrInstall();
|
|
73
76
|
const browserContext = new onboarding_model_1.BrowserContext(domainToStart, customerConfig.chromeFlags || [], this.cliConfig);
|
|
74
77
|
const fileWatcher = new file_watcher_1.FileWatcher(cli, customerConfig, files, documentHandler, browserContext, cache);
|
|
75
78
|
const athenaClient = (await this.getAthenaClient()) || null;
|
package/oclif.manifest.json
CHANGED