hexops / vecty

Vecty lets you build responsive and dynamic web frontends in Go using WebAssembly, competing with modern web frameworks like React & VueJS.
BSD 3-Clause "New" or "Revised" License
2.8k stars 143 forks source link

Add support for WebAssembly #215

Closed damz closed 5 years ago

damz commented 5 years ago

This is a fully working implementation of WebAssembly support in Vecty.

The really nice thing here is that a given code base can be compiled to JavaScript or to WebAssembly with barely any change (the only thing absolutely necessary is to add a select {} at the end of main for the WebAssembly version).

But there are a number of obvious problems for discussion:

slimsag commented 5 years ago

Nice, thanks for sending this! Hoping I'll have time to review this soon (midnight here, and quite busy in general at work).

One thing that immediately pops out to me: I think instead of using github.com/gopherjs/gopherwasm/js we should probably use build tags instead to avoid breaking existing GopherJS users and at the same time support WASM users.

damz commented 5 years ago

@slimsag That's is unfortunately not going to help, given that the code base already references "github.com/gopherjs/gopherjs/js".Object explicitly.

damz commented 5 years ago

(Note that gopherjs test is currently broken in Travis CI because of gopherjs/gopherjs#865.)

slimsag commented 5 years ago

@damz I am aware that Node returns a js.Object explicitly. My point is that with build tags, that could remain the case for GopherJS and not the case for wasm.

dmitshur commented 5 years ago

My point is that with build tags, that could remain the case for GopherJS and not the case for wasm.

That would mean the vecty API is different for GopherJS and Wasm, so users would need to change their code (how they use vecty) depending on whether they want to compile with GopherJS or Wasm. That wouldn't be great.

It works best when when the package API is pure Go, and github.com/gopherjs/gopherjs/js, syscall/js packages are not a part of that API surface. That way, it's an implementation difference that stays completely internal to your package.

I don't know if it's viable to achieve that with vecty, but I just wanted to share these observations. In the case of honnef.co/go/js/dom, we could only do it by changing its API.

damz commented 5 years ago

@dmitshur Agreed, even examples/todomvc inside the repository relies on HTML.Node(). This probably wants to become an interface somehow, but note that the "github.com/gopherjs/gopherjs/js".Object have additional magic (notably the struct tagging) that the new "syscall/js".Value do not have.

damz commented 5 years ago

FWIW, I uploaded a demo of the Markdown example compiled to WebAssembly.

slimsag commented 5 years ago

That would mean the vecty API is different for GopherJS and Wasm, so users would need to change their code (how they use vecty) depending on whether they want to compile with GopherJS or Wasm. That wouldn't be great.

@dmitshur I am aware this would be the case. I am approaching this with the assumption that mid to long term, everyone will be switching over to Go's native WebAssembly support and away from GopherJS, but I suppose that could be an invalid assumption on my part.

One fact that will likely always be true is that Vecty must expose some sort of access to the underlying DOM nodes, i.e. our public API will always have some way to get a js.Object.

If my assumption is right and GopherJS will eventually go away, I think exposing something like gopherwasm through our API makes Vecty less pure in the sense that it will try to support both GopherJS and WebAssembly. In this situation, I would rather offer what I consider to be a more clean API without using gopherwasm.

If my assumption is wrong and GopherJS will stay around e.g. even once Go 2 comes out, I think exposing gopherwasm would be the right choice (or, GopherJS should eventually just hook the syscall/js package and Vecty could expose that, kind of like how net/http works in GopherJS).

So I think the deciding answer for me boils down to the question: What is the future of GopherJS vs. WebAssembly?

progrium commented 5 years ago

As somebody that was intrigued by GopherJS, I never actually wanted to use it. With WebAssembly, I'm all over it. There are obviously differences in the details that I'm sure GopherJS people might prefer it, but from my point of view as a GopherJS outsider, with WebAssembly there is no reason for GopherJS. In fact, it's possible with some of the work we've been doing on top of the WebAssembly port, Vecty will become more popular focusing on WebAssembly.

slimsag commented 5 years ago

@dmitshur @damz any thoughts / opinions here given my last message? (I am aiming to land WebAssembly support over the weekend, if possible, due to high demand for it in general)

myitcv commented 5 years ago

@slimsag you might like to consider waiting for https://go-review.googlesource.com/c/go/+/142004 to land first?

slimsag commented 5 years ago

@myitcv thanks for the link. Yeah, I agree, given that is likely to change our implementation significantly. It also seems others here haven't quite had a chance to give input on my last message (or they don't wish to); I'll wait a bit longer for now.

I am still currently leaning towards "GopherJS will one day go away (so we should expose a pure non-gopherjswasm API)"

ghost commented 5 years ago

To answer your call for responses. I would prefer ecty to run inside wasm. In effect allowing me to output html directly over post message to the window thread. I don't want vecty running in gopherjs. This gets things much faster and make the window a single plain of html with a little bit of js for any interactivity.

The conceptual model relies on accepting a wasm web worker being a Server, and the window being the client. The wasm worker is doing everything and streaming out html through the post message ! Now the multi threading is formalised in that the window has its own thread. I know that the wasm and golang wasm have some significant architecture problems but that's another problem outside of vecty.

The question as to if gopherjs can be used in the window should be addressed. I am finding it useful for small interactive things like gathering form data etc or special UX effects.

slimsag commented 5 years ago

It's been a while (too long) and I think the correct decision is likely to be supporting WebAssembly and GopherJS under separate build tags for the reasons outlined in my prior comment. I will work on adding support for WebAssembly using this approach.

Also, I don't know for certain yet, but I suspect my prior statement to be more true given recent discussion around sunsetting GopherJS here: https://github.com/gopherjs/gopherjs/issues/855#issuecomment-451750737

Some of this sparks questions for me about whether or not Vecty should live under the GopherJS organization long-term, file https://github.com/gopherjs/vecty/issues/230 for discussing that.

slimsag commented 5 years ago

I've sent https://github.com/gopherjs/vecty/pull/232 which will supersede this PR by implementing the alternative approach I mentioned in my comments above.