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.79k stars 144 forks source link

Improving TinyGo support #269

Open slimsag opened 3 years ago

slimsag commented 3 years ago

Experimental TinyGo support in Vecty has landed: https://github.com/tinygo-org/tinygo/issues/1282#issuecomment-674475054

For details on what that means, its limitations, and how to use it - see: https://github.com/hexops/vecty/pull/243#issue-295065853

This issue is for tracking improvements to TinyGo support that would get it out of experimental status.

slimsag commented 3 years ago

@dlmrich that’s great to hear! I’ll check it out and update the instructions for using that soon

marwan-at-work commented 3 years ago

Hey @slimsag , hope you're well. I'm curious if there has been any updates here or if there's anything that TinyGo is pending on to make improvements in Vecty? Thanks!

slimsag commented 3 years ago

Things here have improved quite considerably on the TinyGo side:

I haven't yet had a chance to try out this, but if someone wants to:

  1. Remove dom_tinygo.go in this repository.
  2. Remove this line from dom_no_tinygo.go: https://github.com/hexops/vecty/blob/main/dom_no_tinygo.go#L1
  3. Try running the examples in this repository with latest TinyGo.

I suspect many things will 'just work' now.

deadprogram commented 2 years ago

I suspect many things will 'just work' now.

Has anyone had a chance to try this recently? I would agree with the above statement! :smile_cat:

dkegel-fastly commented 2 years ago

I just tried running vecty's tests with tinygo dev (well, with my setenv branch) after making the two changes above. Six tests fail:

TestCore: panic: runtime error: nil pointer dereference
TestHTML_reconcile_nil: panic: vecty: internal error (only one of HTML.tag or HTML.text may be set)
TestRenderBody_ExpectsBody: panic: vecty: RenderBody: expected Component.Render to return a "body", found ""
TestRenderBody_RenderSkipper_Skip: panic: vecty: RenderBody: Component.SkipRender illegally returned true
TestRerender_nil: panic: vecty: Rerender illegally called with a nil Component argument
TestRerender_no_prevRender: panic: vecty: Rerender invoked on Component that has never been rendered

The next step, if someone has the time, might be to create minimal test cases for one or more of those & file them individually in https://github.com/tinygo-org/tinygo/issues.

dgryski commented 2 years ago

TestCore (at least) seems to be testing that things panic in the appropriate places, which means we should retest with a tinygo branch with https://github.com/tinygo-org/tinygo/pull/2331 applied to it (since otherwise all panics are fatal.)

dkegel-fastly commented 2 years ago

Seemed to die pretty quickly on branch recover3:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00007fff204d492e libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff205035bd libsystem_pthread.dylib`pthread_kill + 263
    frame #2: 0x00007fff20458406 libsystem_c.dylib`abort + 125
    frame #3: 0x000000010000678d vecty.test`runtime.runtimePanic + 46
    frame #4: 0x0000000100006a97 vecty.test`runtime.nilPanic + 16
    frame #5: 0x00000001000276e5 vecty.test`github.com/hexops/vecty.TestCore$3$1 + 47
    frame #6: 0x0000000100027646 vecty.test`github.com/hexops/vecty.recoverStr + 144
    frame #7: 0x0000000100027436 vecty.test`github.com/hexops/vecty.TestCore$3 + 118
    frame #8: 0x00000001000156b6 vecty.test`(*testing.T).Run + 227
    frame #9: 0x0000000100027321 vecty.test`github.com/hexops/vecty.TestCore + 83
    frame #10: 0x000000010003217e vecty.test`github.com/hexops/vecty.TestMain + 2422
    frame #11: 0x00000001000322ac vecty.test`main.main + 17

Also, there was this warning first; my tinygo was built using "make", fwiw.

ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, but used in _(*sync.Once).Do from /var/folders/v0/0k9hwftd29b18z9z7s2g2sfc0000gn/T/tinygo198488412/main.o. To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
slimsag commented 2 years ago

It may be the case that TinyGo just doesn't support recover() very well, has anyone tried just disabling tests that rely on recover() and seeing if the remainder pass - and better, the examples?

dkegel-fastly commented 2 years ago

The recover support is still draft, fwiw.
Quite a few tests do pass, the exceptions are listed above. I have not tried examples yet, leaving that to people who actually use vecty; mine was just a drive-by "which tests fail" check.

aykevl commented 2 years ago

TestCore (at least) seems to be testing that things panic in the appropriate places, which means we should retest with a tinygo branch with tinygo-org/tinygo#2331 applied to it (since otherwise all panics are fatal.)

Unfortunately, #2331 is only for non-WebAssembly instruction sets. WebAssembly is kind of a pain to support... Just FYI.

slimsag commented 2 years ago

@aykevl makes sense, thanks for that info! We don't use recover() outside of tests anyway (it's literally just to check if we panic under the right (wrong) conditions) :)

I think the next step here is for someone to try running the examples with tinygo and/or sending a PR to disable those tests when compiling with TinyGo.

VinceJnz commented 2 years ago

I've just tried to run the hellovecty example.

Should I have followed these instructions?

  1. Remove dom_tinygo.go in this repository.
  2. Remove this line from dom_no_tinygo.go: https://github.com/hexops/vecty/blob/main/dom_no_tinygo.go#L1
  3. Try running the examples in this repository with latest TinyGo.

Here the browser console output:

23:14:54.856 GEThttp://localhost:8080/
[[HTTP/1.1 304 Not Modified 1ms]]()

23:14:54.894 GEThttp://localhost:8080/wasm_exec.js
[[HTTP/1.1 304 Not Modified 1ms]]()

23:14:54.916 The script from “http://localhost:8080/wasm_exec.js” was loaded even though its MIME type (“text/plain”) is not a valid JavaScript MIME type. [localhost:8080](http://localhost:8080/)
23:14:54.937 XHRGEThttp://localhost:8080/main.wasm
[[HTTP/1.1 200 OK 1ms]]()

23:14:54.967 (19429:0x00017fd0) [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.968 panic: vecty: Component T does not implement vecty.Copier interface [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.968 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.968 TinyGo does not support Vecty components that do not implement the vecty.Copier interface. [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.968 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.968 ## What does this mean? [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.968 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.968 TinyGo currently does not have support for reflect.New: https://github.com/tinygo-org/tinygo/issues/1087 [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.969 This prevents Vecty from automatically copying your component for you using reflection. [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.969 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.969 ## How do I fix this? [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.969 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.969 You will need to implement the 'vecty.Copier' interface on your component, e.g.: [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.969 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970    func (c *MyComponent) Copy() vecty.Component { [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970        cpy := *c [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970        return &cpy [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970    } [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970 ## Which component? [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970 <empty string> [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970 Vecty has printed as much information as it can about the component above. Unfortunately, you will need to hunt it down yourself. [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.970 <empty string> 2 [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:14:54.971 Uncaught (in promise) RuntimeError: unreachable executed
    run http://localhost:8080/wasm_exec.js:486
    <anonymous> http://localhost:8080/:11
    promise callback* http://localhost:8080/:10
[main.wasm:4411:1](http://localhost:8080/main.wasm)
23:14:55.011 GEThttp://localhost:8080/favicon.ico
[[HTTP/1.1 200 OK 0ms]]()
VinceJnz commented 2 years ago

After removing 1 and 2

The browser displayed "Hello Vecty!"

The browser console output still has some errors:

23:27:14.281 GEThttp://localhost:8080/
[[HTTP/1.1 200 OK 1ms]]()

23:27:14.317 GEThttp://localhost:8080/wasm_exec.js
[[HTTP/1.1 200 OK 1ms]]()

23:27:14.320 The script from “http://localhost:8080/wasm_exec.js” was loaded even though its MIME type (“text/plain”) is not a valid JavaScript MIME type. [localhost:8080](http://localhost:8080/)
23:27:14.364 XHRGEThttp://localhost:8080/main.wasm
[[HTTP/1.1 200 OK 5ms]]()

23:27:14.391 syscall/js.finalizeRef not implemented [wasm_exec.js:313:15](http://localhost:8080/wasm_exec.js)
23:27:14.392 syscall/js.finalizeRef not implemented [wasm_exec.js:313:15](http://localhost:8080/wasm_exec.js)
23:27:14.392 syscall/js.finalizeRef not implemented [wasm_exec.js:313:15](http://localhost:8080/wasm_exec.js)
23:27:14.436 GEThttp://localhost:8080/favicon.ico
[[HTTP/1.1 200 OK 3ms]]()
VinceJnz commented 2 years ago

I've tried running the "Markdown" example

Here's the browser console output

23:38:31.097 GEThttp://localhost:8080/
[[HTTP/1.1 304 Not Modified 2ms]]()

23:38:31.138 GEThttp://localhost:8080/wasm_exec.js
[[HTTP/1.1 304 Not Modified 2ms]]()

23:38:31.162 The script from “http://localhost:8080/wasm_exec.js” was loaded even though its MIME type (“text/plain”) is not a valid JavaScript MIME type. [localhost:8080](http://localhost:8080/)
23:38:31.190 XHRGEThttp://localhost:8080/main.wasm
[[HTTP/1.1 200 OK 45ms]]()

23:38:31.254 GEThttp://localhost:8080/favicon.ico
[[HTTP/1.1 200 OK 0ms]]()

23:38:32.317 m���j�������7�panic: runtime error: nil pointer dereference [wasm_exec.js:268:19](http://localhost:8080/wasm_exec.js)
23:38:32.320 Uncaught (in promise) RuntimeError: unreachable executed
    run http://localhost:8080/wasm_exec.js:486
    <anonymous> http://localhost:8080/:11
    promise callback* http://localhost:8080/:10
[main.wasm:39478:1](http://localhost:8080/main.wasm)