Repository: KaotoIO/vscode-kaoto
Pull request #849: fix: web extension failed to load in a browser
Author: login: djelinek
Created: 2025-03-26T11:57:28Z | Merged: 2025-03-27T08:59:44Z

![Screenshot 2025-03-26 at 12 49 10](https://github.com/user-attachments/assets/629d61c7-82ec-4a84-b893-dd562f0e9539)



Diff:
diff --git a/src/extension/ExtensionContextHandler.ts b/src/extension/ExtensionContextHandler.ts
index 3fb6dd9e..eecfadde 100644
--- a/src/extension/ExtensionContextHandler.ts
+++ b/src/extension/ExtensionContextHandler.ts
@@ -15,7 +15,6 @@
  */
 import * as vscode from 'vscode';
 import * as KogitoVsCode from '@kie-tools-core/vscode-extension/dist';
-import { dirname } from 'path';
 import { execSync } from 'child_process';
 import { HelpFeedbackProvider } from '../views/providers/HelpFeedbackProvider';
 import { IntegrationsProvider } from '../views/providers/IntegrationsProvider';
@@ -193,7 +192,8 @@ export class ExtensionContextHandler {
 
 		this.context.subscriptions.push(
 			vscode.commands.registerCommand(INTEGRATIONS_RUN_COMMAND_ID, async (integration: Integration) => {
-				await new CamelRunJBangTask(integration.filepath.fsPath, dirname(integration.filepath.fsPath)).execute();
+				const runTask = await CamelRunJBangTask.create(integration.filepath.fsPath);
+				await runTask.execute();
 				await this.sendCommandTrackingEvent(INTEGRATIONS_RUN_COMMAND_ID);
 			}),
 		);
@@ -208,7 +208,7 @@ export class ExtensionContextHandler {
 					await new CamelAddPluginJBangTask('kubernetes').executeAndWait();
 					KaotoOutputChannel.logInfo('Apache Camel JBang Kubernetes plugin was installed.');
 				}
-				await new CamelKubernetesRunJBangTask(integration.filepath.fsPath, dirname(integration.filepath.fsPath)).execute();
+				await new CamelKubernetesRunJBangTask(integration.filepath.fsPath).execute();
 				await this.sendCommandTrackingEvent(INTEGRATIONS_KUBERNETES_RUN_COMMAND_ID);
 			}),
 		);
diff --git a/src/helpers/CamelJBang.ts b/src/helpers/CamelJBang.ts
index a1dd8fc2..626d6483 100644
--- a/src/helpers/CamelJBang.ts
+++ b/src/helpers/CamelJBang.ts
@@ -13,10 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ShellExecution, ShellExecutionOptions, workspace } from 'vscode';
+import { RelativePattern, ShellExecution, ShellExecutionOptions, Uri, workspace } from 'vscode';
 import { arePathsEqual } from './helpers';
 import { dirname } from 'path';
-import { globSync } from 'glob';
 
 export enum RouteOperation {
 	start = 'start',
@@ -63,20 +62,14 @@ export class CamelJBang {
 		);
 	}
 
-	public run(filePath: string, cwd?: string): ShellExecution {
+	public async run(filePath: string, cwd?: string): Promise<ShellExecution> {
 		const shellExecOptions: ShellExecutionOptions = {
 			cwd: cwd,
 		};
+		const runArgs = await this.getRunArguments(filePath);
 		return new ShellExecution(
 			this.jbang,
-			[
-				...this.defaultJbangArgs,
-				'run',
-				`'${filePath}'`,
-				...this.getRunArguments(filePath),
-				this.getCamelVersion(),
-				this.getRedHatMavenRepository(),
-			].filter(function (arg) {
+			[...this.defaultJbangArgs, 'run', `'${filePath}'`, ...runArgs, this.getCamelVersion(), this.getRedHatMavenRepository()].filter(function (arg) {
 				return arg; // remove ALL empty values ("", null, undefined and 0)
 			}),
 			shellExecOptions,
@@ -105,10 +98,10 @@ export class CamelJBang {
 		}
 	}
 
-	private getRunArguments(filePath: string): string[] {
+	private async getRunArguments(filePath: string): Promise<string[]> {
 		const runArgs = workspace.getConfiguration().get('kaoto.camelJBang.RunArguments') as string[];
 		if (runArgs) {
-			return this.handleMissingXslFiles(filePath, runArgs);
+			return await this.handleMissingXslFiles(filePath, runArgs);
 		} else {
 			return [];
 		}
@@ -146,9 +139,10 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
-		const xsls = globSync(`${dirname(filePath)}/*.xsl`).length > 0;
-		if (xsls) {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const folderUri = Uri.file(dirname(filePath));
+		const xsls = await workspace.findFiles(new RelativePattern(folderUri, '*.xsl'));
+		if (xsls.length > 0) {
 			return runArgs; // don't modify default run arguments specified via settings which should by default contain *.xsl
 		} else {
 			return runArgs.filter((parameter) => parameter !== '*.xsl');
diff --git a/src/tasks/CamelKubernetesRunJBangTask.ts b/src/tasks/CamelKubernetesRunJBangTask.ts
index 90d21b45..e3f5cd62 100644
--- a/src/tasks/CamelKubernetesRunJBangTask.ts
+++ b/src/tasks/CamelKubernetesRunJBangTask.ts
@@ -16,10 +16,10 @@
 import { TaskScope } from 'vscode';
 import { CamelJBangTask } from './CamelJBangTask';
 import { CamelJBang } from '../helpers/CamelJBang';
-import { basename } from 'path';
+import { basename, dirname } from 'path';
 
 export class CamelKubernetesRunJBangTask extends CamelJBangTask {
-	constructor(filePath: string, cwd?: string) {
-		super(TaskScope.Workspace, `Deploying - ${basename(filePath)}`, new CamelJBang().kubernetesRun(filePath, cwd));
+	constructor(filePath: string) {
+		super(TaskScope.Workspace, `Deploying - ${basename(filePath)}`, new CamelJBang().kubernetesRun(filePath, dirname(filePath)));
 	}
 }
diff --git a/src/tasks/CamelRunJBangTask.ts b/src/tasks/CamelRunJBangTask.ts
index e5178f3c..ee79622a 100644
--- a/src/tasks/CamelRunJBangTask.ts
+++ b/src/tasks/CamelRunJBangTask.ts
@@ -13,15 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { TaskScope } from 'vscode';
+import { ShellExecution, TaskScope } from 'vscode';
 import { CamelJBangTask } from './CamelJBangTask';
 import { CamelJBang } from '../helpers/CamelJBang';
-import { basename } from 'path';
+import { basename, dirname } from 'path';
 
 export class CamelRunJBangTask extends CamelJBangTask {
-	constructor(filePath: string, cwd?: string) {
-		super(TaskScope.Workspace, `Running - ${basename(filePath)}`, new CamelJBang().run(filePath, cwd));
-
+	private constructor(shellExecution: ShellExecution, filePath: string) {
+		super(TaskScope.Workspace, `Running - ${basename(filePath)}`, shellExecution);
 		this.isBackground = true;
 	}
+
+	static async create(filePath: string): Promise<CamelRunJBangTask> {
+		const shellExecution = await new CamelJBang().run(filePath, dirname(filePath));
+		return new CamelRunJBangTask(shellExecution, filePath);
+	}
 }


Reviews:
user: login: apupier
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T14:41:01Z
user: login: djelinek
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T14:52:08Z
user: login: apupier
body: works but I do not understand well why
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-26T14:57:02Z
user: login: apupier
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T14:59:09Z
user: login: djelinek
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:01:24Z
user: login: lhein
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:05:39Z
user: login: djelinek
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:53:02Z
user: login: djelinek
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T17:53:55Z
user: login: djelinek
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T19:57:38Z
user: login: lhein
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T20:08:20Z
user: login: apupier
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-27T07:42:48Z
user: login: apupier
body: ah await need to verify if we can remove glob from package.json dependencies
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-27T07:43:29Z
user: login: apupier
body: glob is not listed in package.json (so guess it was working thanks to implicit transitive dependencies before)
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-27T07:48:34Z

Review comments:
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: apupier
body: ouch this smells problems with edge cases
created_at: 2025-03-26T14:41:01Z
author_association: MEMBER
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: djelinek
body: which edge cases?

this all mess is just about somehow divide web and desktop extension bundles.. other way is to strictly divide codebase which is touching extension points - extension.ts and extensionWeb.ts

which is possible in term of full project refactor

this dynamic loading happens when code is really called which is at the moment happening only for desktop (extension.ts)
created_at: 2025-03-26T14:52:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: apupier
body: by experience, using dynamic import inlined in the code is often not working in some conditions (which I cannot explain as i do not understand exactly why it is needed)
created_at: 2025-03-26T14:59:09Z
author_association: MEMBER
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: djelinek
body: alright.. then other option is to fully refactor and divide those extension contributions  for desktepOnly and desktopWeb
created_at: 2025-03-26T15:01:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: lhein
body: Can you remind me why we need that web extension thingy at all? 
created_at: 2025-03-26T17:05:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: djelinek
body: if I understood correctly the main reason is Github Codespaces or vscode.dev in a browser

main usecase for GH Codespace would be to open it by press ´.´ on some camel gh repository which will opens it automatically using codespaces and then when you install Kaoto extension there you should be able to design/see routes
created_at: 2025-03-26T17:53:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: djelinek
body: how often this usage is expected or how useful it is I do not know..
created_at: 2025-03-26T17:53:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -146,7 +139,9 @@ export class CamelJBang {
 	 * Mainly in ZSH shell there is problem when Camel JBang is executed with non existing files added using '*.xsl' file pattern
 	 * it is caused by null glob option disabled by default for ZSH shell
 	 */
-	private handleMissingXslFiles(filePath: string, runArgs: string[]): string[] {
+	private async handleMissingXslFiles(filePath: string, runArgs: string[]): Promise<string[]> {
+		const globSync = (await import('glob')).globSync; // glob needs to be imported dynamically to avoid issues when extension is bundled for Web
path: src/helpers/CamelJBang.ts
user: login: djelinek
body: alright.. I have removed `glob` import to avoid need of using dynamic loading 🙂 now we are relying on a vscode `workspace` API which should be much safer
created_at: 2025-03-26T19:57:38Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-03-26T19:56:51Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=KaotoIO_vscode-kaoto&pullRequest=849) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=KaotoIO_vscode-kaoto&pullRequest=849&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=KaotoIO_vscode-kaoto&pullRequest=849&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=KaotoIO_vscode-kaoto&pullRequest=849&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=KaotoIO_vscode-kaoto&pullRequest=849&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=KaotoIO_vscode-kaoto&pullRequest=849&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=KaotoIO_vscode-kaoto&pullRequest=849)


author_association: NONE