Repository: oliverschwendener/ueli (ts)

Issue:
[Bug] Debugging on Windows
**Describe the bug**
I wanted to build an extension and followed the instructions here https://github.com/oliverschwendener/ueli/wiki/Development but this leads to a blank ui window. 

**To Reproduce**
Steps to reproduce the behavior:
1. clone the repository
2. start visual studio code
3. hit F5 to start the debbugging

**Expected behavior**
A running ueli instance with a debugger attached. 

**Screenshots**
Thats what I see: 
![image](https://github.com/user-attachments/assets/02920b1c-6a48-49ba-af13-bc95d78f22af)


**Environment**
 - OS: Windows
 - Version: latest main Branch

**Additional context**
Vite is building for production why it does not run a vite debug server and the HtmlLoader.ts has isPackaged set to false why it tries to open ueli against the vite debug server which is not running. 

` *  Executing task: C:\projekte\ueli/node_modules/.bin/vite.cmd build --sourcemap 

vite v6.0.0 building for production...
✓ 2178 modules transformed.
../../dist-renderer/settings.html                  1.17 kB │ gzip:   0.49 kB
../../dist-renderer/search.html                    1.20 kB │ gzip:   0.50 kB
../../dist-renderer/assets/search-CBlPBUAI.js     77.49 kB │ gzip:  24.46 kB │ map:   842.15 kB
../../dist-renderer/assets/settings-Dyw6eIXt.js  124.75 kB │ gzip:  33.15 kB │ map: 3,150.18 kB
../../dist-renderer/assets/index-ChpP12u8.js     822.80 kB │ gzip: 229.18 kB │ map: 8,530.78 kB
✓ built in 11.28s
vite v6.0.0 building for production...
✓ 437 modules transformed.
../../dist-main/createEmptyInstantSearchResult-r4_ve-14.js    0.16 kB │ gzip:  0.15 kB │ map:   0.46 kB
../../dist-main/index.js                                      3.15 kB │ gzip:  1.15 kB │ map:   6.94 kB
../../dist-main/index-DTW6E1yL.js                            62.09 kB │ gzip: 15.92 kB │ map: 249.00 kB
../../dist-main/index-ahzfg2ZJ.js                           112.46 kB │ gzip: 25.08 kB │ map: 365.28 kB
✓ built in 1.22s
vite v6.0.0 building for production...
✓ 1 modules transformed.
../../dist-preload/index.js  2.91 kB │ gzip: 0.77 kB │ map: 6.35 kB
✓ built in 25ms
 *  Terminal will be reused by tasks, press any key to close it. 
`

Thats what i see on the debug console 

`"C:\projekte\ueli/node_modules/.bin/electron.cmd" . --remote-debugging-port=9229
Debugger listening on ws://127.0.0.1:59328/0fbc8fc3-cc3e-4418-8a21-6bff8b7e1d41
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.

Debugger listening on ws://127.0.0.1:59330/6bea4501-7c8e-41bb-b449-a5574748c422
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.

DevTools listening on ws://127.0.0.1:9229/devtools/browser/ddf9dda0-8975-434b-942b-09e830912153
[8460:0106/211342.400:ERROR:network_service_instance_impl.cc(613)] Network service crashed, restarting service.
(node:8460) UnhandledPromiseRejectionWarning: Error: ERR_INVALID_URL (-300) loading ''
    at rejectAndCleanup (node:electron/js2c/browser_init:2:80490)
    at finishListener (node:electron/js2c/browser_init:2:80652)
    at WebContents.failListener (node:electron/js2c/browser_init:2:80938)
    at WebContents.emit (node:events:519:28)
    at WebContents.callbackTrampoline (node:internal/async_hooks:130:17)
    at _.loadURL (node:electron/js2c/browser_init:2:81840)
    at n.loadURL (node:electron/js2c/browser_init:2:13972)
    at ae.loadHtmlFile (C:\projekte\ueli\dist-main\index-DTW6E1yL.js:1:4677)
    at S.bootstrap (C:\projekte\ueli\dist-main\index-DTW6E1yL.js:46:15868)
    at C:\projekte\ueli\dist-main\index.js:1:3018
(Use `electron --trace-warnings ...` to show where the warning was created)
(node:8460) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)`




Pull request description:
fix: load static file when vite dev server url is not available
Fixes #1306

Patch:
diff --git a/src/main/Core/BrowserWindow/BrowserWindowModule.ts b/src/main/Core/BrowserWindow/BrowserWindowModule.ts
index 241a3b18..7155f960 100644
--- a/src/main/Core/BrowserWindow/BrowserWindowModule.ts
+++ b/src/main/Core/BrowserWindow/BrowserWindowModule.ts
@@ -21,7 +21,7 @@ export class BrowserWindowModule {
 
         moduleRegistry.register(
             "BrowserWindowHtmlLoader",
-            new HtmlLoader(moduleRegistry.get("App"), moduleRegistry.get("EnvironmentVariableProvider")),
+            new HtmlLoader(moduleRegistry.get("EnvironmentVariableProvider")),
         );
 
         moduleRegistry.register(
diff --git a/src/main/Core/BrowserWindow/HtmlLoader/HtmlLoader.ts b/src/main/Core/BrowserWindow/HtmlLoader/HtmlLoader.ts
index c8092711..2292b14c 100644
--- a/src/main/Core/BrowserWindow/HtmlLoader/HtmlLoader.ts
+++ b/src/main/Core/BrowserWindow/HtmlLoader/HtmlLoader.ts
@@ -1,19 +1,18 @@
 import type { EnvironmentVariableProvider } from "@Core/EnvironmentVariableProvider";
-import type { App, BrowserWindow } from "electron";
+import type { BrowserWindow } from "electron";
 import { join } from "path";
 import type { BrowserWindowHtmlLoader } from "../Contract";
 
 export class HtmlLoader implements BrowserWindowHtmlLoader {
-    public constructor(
-        private readonly app: App,
-        private readonly environmentVariableProvider: EnvironmentVariableProvider,
-    ) {}
+    public constructor(private readonly environmentVariableProvider: EnvironmentVariableProvider) {}
 
     public async loadHtmlFile(browserWindow: BrowserWindow, fileName: string): Promise<void> {
-        if (this.app.isPackaged) {
-            await browserWindow.loadFile(join(__dirname, "..", "dist-renderer", fileName));
+        const viteDevServerUrl = this.environmentVariableProvider.get("VITE_DEV_SERVER_URL");
+
+        if (viteDevServerUrl) {
+            await browserWindow.loadURL(`${viteDevServerUrl}/${fileName}`);
         } else {
-            await browserWindow.loadURL(`${this.environmentVariableProvider.get("VITE_DEV_SERVER_URL")}/${fileName}`);
+            await browserWindow.loadFile(join(__dirname, "..", "dist-renderer", fileName));
         }
     }
 }


Test patch:
diff --git a/src/main/Core/BrowserWindow/HtmlLoader/HtmlLoader.test.ts b/src/main/Core/BrowserWindow/HtmlLoader/HtmlLoader.test.ts
new file mode 100644
index 00000000..06759038
--- /dev/null
+++ b/src/main/Core/BrowserWindow/HtmlLoader/HtmlLoader.test.ts
@@ -0,0 +1,37 @@
+import type { EnvironmentVariableProvider } from "@Core/EnvironmentVariableProvider";
+import type { BrowserWindow } from "electron";
+import { join } from "path";
+import { describe, expect, it, vi } from "vitest";
+import { HtmlLoader } from "./HtmlLoader";
+
+describe(HtmlLoader, () => {
+    describe(HtmlLoader.prototype.loadHtmlFile, () => {
+        it("should load the HTML file from the Vite dev server URL if it is available", async () => {
+            const getMock = vi.fn().mockReturnValue("http://localhost:3000");
+            const loadURLMock = vi.fn();
+
+            const environmentVariableProvider = <EnvironmentVariableProvider>{ get: (n) => getMock(n) };
+            const browserWindow = <BrowserWindow>{ loadURL: (u) => loadURLMock(u) };
+
+            const htmlLoader = new HtmlLoader(environmentVariableProvider);
+
+            await htmlLoader.loadHtmlFile(browserWindow, "index.html");
+
+            expect(loadURLMock).toHaveBeenCalledWith("http://localhost:3000/index.html");
+        });
+
+        it("should load the HTML file from the dist-renderer directory if the Vite dev server URL is not available", async () => {
+            const getMock = vi.fn().mockReturnValue(undefined);
+            const loadFileMock = vi.fn();
+
+            const environmentVariableProvider = <EnvironmentVariableProvider>{ get: (n) => getMock(n) };
+            const browserWindow = <BrowserWindow>{ loadFile: (f) => loadFileMock(f) };
+
+            const htmlLoader = new HtmlLoader(environmentVariableProvider);
+
+            await htmlLoader.loadHtmlFile(browserWindow, "index.html");
+
+            expect(loadFileMock).toHaveBeenCalledWith(expect.stringContaining(join("dist-renderer", "index.html")));
+        });
+    });
+});