jchv / go-webview2

WebView2 bindings for pure Go, without CGo, based on the webview/webview bindings.
Other
257 stars 63 forks source link

WebView2API For Client-Side #39

Closed CanPacis closed 2 years ago

CanPacis commented 2 years ago

I created a global WebView2API for a better client-side communication. Also implemented a basic PostMessage method that basically evaluates a postMessage call that can be listened on the front-end.

I think a global API like this one better aligns with the web standards and would be easier to use. Instead of polluting the global namespace with webview.Bind people can communicate between processes in a cleaner manner. Creating global functions also tend to cause problems with TypeScript as well beacuse each of them needs to be declared in a seperate file, at least my experience wasn't the best.

Simple usage would be something like this;

// While creating a new vebview with options, we can provide a WebView2API handler
w := webview2.NewWithOptions(webview2.WebViewOptions{
    Debug:     true,
    AutoFocus: true,
    WebView2API: apiHandler,
    WindowOptions: webview2.WindowOptions{
        Title: "Minimal webview example",
    },
})

// ...

// Then we would define the method as such;
func apiHandler(message string) interface{} {
    // deal with the message and return any message that is serializable
    return "hello, world!"
}

On the client-side we can create a WebView2API object and send and listen to messages

// First we check if the API is provided
if ("WebView2API" in window) {
    let bridge = new WebView2API();
    await bridge.send(""); // returns "hello, world!"

    // We can also listen to arbitrary messages with event listeners as well
    bridge.addEventListener("message", (event) => console.log(event)) // Logs a custom message event
}
jchv commented 2 years ago

I'm a bit of two minds about this one.

I do agree that the Bind approach is not ideal. It's merely supported to give us parity with webview/webview.

However, I don't otherwise think go-webview2, being what it is, Go bindings for Webview2, should prescribe an RPC mechanism. Instead, it would be better if we could expose APIs that would allow apps and libraries to implement their own RPC mechanisms. (We're stuck with having Bind no matter what, since it's already there and needed for parity with webview/webview.)

Of course, in both cases, we have to be careful. Any API surface that is exposed by go-webview2 is something that apps can depend on, and therefore I generally try to keep the API surface of go-webview2 itself pretty small. Since software is starting to depend on go-webview2, I think it's important to be very judicious about new additions to the surface area. As of today, there are no releases and therefore no semver guarantees, but that will change (and I don't want to unnecessarily break compatibility even if there is no compatibility guarantee.)

I'll leave this open for now since I have not come to a conclusion.

CanPacis commented 2 years ago

Just updated for linter check... Yeah I understand what you mean. Coming from a web developer perspective, I would rather use something like a lower level API interface that wouldn't just pollute the global namespace. But it is what it is and frankly, I never thought this parity side of things. I think a web-like API interface is the way to let the others deal with their own RPC mechanisms. But you know, you are the maintainer, if you want a solution like this in the future the PR is here use it however you like. For now, I think I'll use a fork.