tr1ckydev / webview-bun

Bun bindings for webview, a tiny library for creating web-based desktop GUIs.
https://www.npmjs.com/package/webview-bun
MIT License
201 stars 8 forks source link

Run without blocking main or run inside of worker #10

Closed StrangeBytesDev closed 4 weeks ago

StrangeBytesDev commented 2 months ago

Currently webview.run() blocks the main thread, which limits your ability to run any kind of backend code, like a web server. Additionally, this currently doesn't work in a Worker script, although there is potentially a solution to this implemented here: https://github.com/primatejs/worker-bin

If it was possible to either run without block main or in a Worker, it'd make this much more useful for developing full on applications. I'm currently experimenting with using alternative methods for running the webview outside of the main thread, like node's worker_threads. I'll report back if I get anything working.

(Thanks for the great work on this! I'm extremely excited to use this in applications.)

tr1ckydev commented 2 months ago

Thanks for checking out my project! And yes it's fairly easy to do so using the Worker threads API. Here's a very simple example to demonstrate that,

index.ts

const server = Bun.serve({
    fetch() {
        return new Response(`Hello from Bun v${Bun.version}!`);
    }
});

const worker = new Worker("./webview.ts");
worker.addEventListener("close", () => server.stop(true));

webview.ts

import { Webview } from "webview-bun";

const webview = new Webview();
webview.navigate("http://localhost:3000/");
webview.run();

Compiling the above example into a single executable will also work just fine.

StrangeBytesDev commented 2 months ago

Please re-open this issue. That code won't actually work compiled. In your example, webview.ts isn't included in the compiled binary. You would need to use something like Bun's embed to get the webview.ts file to actually be included for it to work.

const server = Bun.serve({
    fetch() {
        return new Response(`Hello from Bun v${Bun.version}!`);
    }
});

import workerFile from './webview.ts' with {type: 'file'}
const worker = new Worker(URL.createObjectURL(Bun.file(workerFile)))

worker.addEventListener("close", () => server.stop(true));

But embeded workers cannot run any imports, which is why the repo I linked above exists as a proof of concept to get Webview's working in worker threads. As is, I can't come up with any way to run webview-bun without blocking the main thread.

tr1ckydev commented 2 months ago

Compiling the above example into a single executable will also work just fine.

I obviously wrote this only after I actually tried compiling it.

tr1ckydev commented 2 months ago

Note that you can also inline file as a blob content as told here https://bun.sh/docs/api/workers#blob-urls

StrangeBytesDev commented 2 months ago

Compiling the above example into a single executable will also work just fine.

I obviously wrote this only after I actually tried compiling it.

If you're just compiling it into the same folder where the source files exist it will appear to work fine. But as soon as you try and run it from anywhere else it will not work.

tr1ckydev commented 2 months ago

Oh you're right, reopening.

StrangeBytesDev commented 2 months ago

So far the closest thing I have to a working solution is to combine ffi.ts and webview.ts into a single file plus the actual setup code for the webview, embed that, and then run it with "node:worker_threads" rather than Bun's builtin Worker api. That approach won't embed the webview libraries though, so I was only able to make it work using the WEBVIEW_PATH env var approach. If you could embed the webview libraries from the main process and access them from the worker, you could probably get to a clean solution. Documentation on how the virtual filesystem works for embedding is pretty sparse though and I couldn't figure out a way to make that work.

terrablue commented 2 months ago

@StrangeBytesDev this is actually tricky to get right, and I haven't got yet a good, reusable solution.

The problem is that you can only load an so etc. as a compile-time binary (with { type: "file" }) and pass its URL to the worker, having the worker make a BunFile out of it inside its event, such that it can dynamically be passed to dlopen (as seen in https://github.com/primatejs/worker-bin).

In contrast, you cannot, at least currently, do the same for a JS import. This results in a silent failure inside the worker. Not being able to do it inside the worker means you cannot import the JS from elsewhere, in particular from another package such as this one. So no reusability.

As long as this isn't resolved, the usefulness of webview without worker support in Bun/Deno/Node in general is questionable... unless of course you're willing to vendor the logic into your own project, as unfortunately I'm forced to do now.

Please also note that even in its current state (vendoring the webview logic), this doesn't work on Mac x64 yet, see https://github.com/oven-sh/bun/issues/11959. If you're able to test it on Mac Arm and provide feedback in that issue, it would be helpful to delineate that problem, namely if it's just a Mac x64 or a general Mac problem.

terrablue commented 2 months ago

@StrangeBytesDev FYI, @rcompat/webview just added support for compiling with workers (just Bun, Deno/Node support will follow later):

// detect current platform
import Webview from "@rcompat/webview/worker";
// or cross-compile
// import Webview from "@rcompat/webview/worker/windows-x64";

// start server
Bun.serve({ port: 6161, fetch: () => new Response("hi") });

const webview = new Webview();
webview.navigate("http://localhost:6161");
webview.run();

@tr1ckydev feel free to reuse any code from @rcompat/webview to resolve this issue, it's MIT-licensed.

tr1ckydev commented 2 months ago

@terrablue Interesting work 👏! I'll definitely check it out. Im too trying to find some other easier way to do it. If you are on bun discord, you can find my progress in the showcase channel for webview-bun.

tr1ckydev commented 4 weeks ago

Fixed in Bun v1.1.25. https://bun.sh/blog/bun-v1.1.25#worker-in-standalone-executables

terrablue commented 2 weeks ago

FYI, Bun 1.1.25 did not really fix the accompanying Mac issue: it is still impossible to run a webview from within a worker, on Mac. 1.1.25 only made importing in worker files easier, but I wouldn't consider this issue done until Bun fixes https://github.com/oven-sh/bun/issues/11959, or a workaround is found.