can't open the local url
import { Webview } from 'webview-bun';
import index from "./index.html";
import { serve } from "bun";
const server = serve({
routes: {
"/*": index,
},
});
setTimeout(() => {
let w = new Webview();
w.title = 'Hello World';
w.navigate(server.url.toString()); // http://localhost:3000/
w.run();
}, 500);
opens about:bank. but, opening, for example, https://example.com - It's working
ok, I figured it out, it's because the webview is blocking the stream so much that localhost:3000 cannot be created. It helps to bring logic into the webworker. But.. it doesn't work when compiling #37
Webview doesn't need a server, it's a browser - a client. Due to the event loop, and bun not having threads, you can't serve AND run webview in the same process. You can use a child process OR you can treat your webview-bun app as just a client-side app, build a SPA, and/or bind functions to call using webview.bind. Hope this helps.
There are so many limitations, for example, need to compile the SPA into a true single file with embedded CSS and JS, Since webview only accepts a single HTML string instead of Bun.HTMLBundle. What about images, font, and other resources?
If it’s defined in the css, it should be bundled. If it’s not, you can use the internet url of it somewhere (github pages perhaps). You can serve it up as a base64 string from a IPC function call. Or you can attempt the dreaded file:// path…
Good evening everyone, I'm Brazilian. I don't speak English very well, but I found a solution. I managed to create a binary like this and also get the server working alongside it. On src/index.ts make:
` import WebView from "@rcompat/webview"; import platform from "@rcompat/webview/windows-x64";
async function runServerMode() { const { default: ServerModule } = await import("./server/server.module"); new ServerModule(); await new Promise(() => {}); }
function isScriptRunMode(): boolean { return !!process.argv[1] && /.(js|ts|mjs|cjs)$/.test(process.argv[1]); }
function determineSpawnCmd(): string[] { if (isScriptRunMode()) { return ["bun", process.argv[1]!, "--server"]; } const exePath = process.execPath || process.argv[0]; return [exePath!, "--server"]; }
async function streamChildOutput(stream: ReadableStream<Uint8Array> | null, logFn: (s: string) => void) { if (!stream) return; const reader = (stream as ReadableStream<Uint8Array>).getReader(); const decoder = new TextDecoder(); try { while (true) { const { value, done } = await reader.read(); if (done) break; if (value) logFn(decoder.decode(value)); } } catch (decoder_error) { console.error({decoder_error}) // ignore read errors on shutdown } finally { try { await reader.cancel(); } catch {} } }
async function waitForServer(url: string, timeoutMs = 5000, intervalMs = 150) { const start = Date.now(); while (Date.now() - start < timeoutMs) { try { const res = await fetch(url, { method: "GET" }); if (res.ok) return true; } catch (start_error) { console.error({start_error}) // ingnorar } await new Promise((r) => setTimeout(r, intervalMs)); } return false; }
async function runMainMode() { const cmd = determineSpawnCmd();
const child = Bun.spawn({ cmd, stdout: "pipe", stderr: "pipe", env: process.env, cwd: process.cwd(), });
streamChildOutput(child.stdout as unknown as ReadableStream<Uint8Array> | null, (s) => console.log("[SERVER]", s.trim()) ); streamChildOutput(child.stderr as unknown as ReadableStream<Uint8Array> | null, (s) => console.error("[SERVER-ERR]", s.trim()) );
// aguarda servidor subir (healthcheck) const url = "http://localhost:3000/"; const ok = await waitForServer(url, 8000, 200); if (!ok) { console.error("Servidor não respondeu em http://localhost:3000/ — abortando."); // fecha child e sai try { child.kill(); } catch {} process.exit(1); }
// cria e abre o WebView const view = new WebView({ debug: true, platform }); view.navigate(url); view.run();
// quando WebView fechar, finaliza o child try { child.kill(); } catch (run_main_mode_error) { console.error({run_main_mode_error}) // ingorar } }
// ENTRYPOINT if (process.argv.includes("--server")) { runServerMode().catch((e) => { console.error("Server failed:", e); process.exit(1); }); } else { runMainMode().catch((e) => { console.error("Main failed:", e); process.exit(1); }); }
`