vecty
vecty copied to clipboard
Improving TinyGo support
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.
- [ ] TinyGo cannot compile
example/markdown
's dependencies. - [ ] TinyGo cannot compile
example/todomvc
's dependencies. - [x] TinyGo has no
reflect.New
support, meaningvecty.Copier
must be implemented for all components. https://github.com/tinygo-org/tinygo/issues/1087 - [ ] Debug symbols / information is not included which means panics with component names
%T
show justT
instead ofmy/package.MyComponent
- [ ] There is no
wasmserve
equivilent for TinyGo yet
Thanks for your work on TinyGo support.
I've created equivalent of wasmserve for TinyGo. https://github.com/dImrich/tinygo-wasmserve
@dlmrich that’s great to hear! I’ll check it out and update the instructions for using that soon
@slimsag Great!
I have a little problem with vecty.List. It's not working under TinyGo while both examples works fine in regular Go.
Error 1:
panic: runtime error: type assert failed
Uncaught (in promise) RuntimeError: unreachable
at runtime.runtimePanic (<anonymous>:wasm-function[64]:0x454d)
at runtime.interfaceTypeAssert (<anonymous>:wasm-function[89]:0x5f2d)
at (github.com/hexops/vecty.jsObject).Equal (<anonymous>:wasm-function[179]:0xdabd)
at (*github.com/hexops/vecty.HTML).reconcileChildren.resume (<anonymous>:wasm-function[209]:0x133f1)
func (p *PageView) Render() vecty.ComponentOrHTML {
items := make(vecty.List, 2)
items = append(items, elem.Div(vecty.Text("Item 1")))
items = append(items, elem.Div(vecty.Text("Item 2")))
return elem.Body(
elem.Div(vecty.Text("Hello Vecty!")),
items,
)
}
Error 2:
panic: runtime error: slice out of range
Uncaught (in promise) RuntimeError: unreachable
at runtime.runtimePanic (<anonymous>:wasm-function[64]:0x454d)
at runtime.slicePanic (<anonymous>:wasm-function[112]:0x74cb)
at (*github.com/hexops/vecty.HTML).reconcileChildren.resume (<anonymous>:wasm-function[209]:0x136b9)
func (p *PageView) Render() vecty.ComponentOrHTML {
items := make(vecty.List, 2)
items = append(items, elem.Div(vecty.Text("Item 1")))
items = append(items, elem.Div(vecty.Text("Item 2")))
return elem.Body(
elem.Div(vecty.Text("Hello Vecty!")),
elem.Div(items),
)
}
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!
Things here have improved quite considerably on the TinyGo side:
- Much of the reflection API support has been improved: https://github.com/tinygo-org/tinygo/pull/1727
-
reflect.New
support has been added: https://github.com/tinygo-org/tinygo/pull/1787
I haven't yet had a chance to try out this, but if someone wants to:
- Remove
dom_tinygo.go
in this repository. - Remove this line from
dom_no_tinygo.go
: https://github.com/hexops/vecty/blob/main/dom_no_tinygo.go#L1 - Try running the examples in this repository with latest TinyGo.
I suspect many things will 'just work' now.
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:
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.
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.)
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
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?
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.
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.
@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.
I've just tried to run the hellovecty example.
Should I have followed these instructions?
- Remove dom_tinygo.go in this repository.
- Remove this line from dom_no_tinygo.go: https://github.com/hexops/vecty/blob/main/dom_no_tinygo.go#L1
- 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]]()
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]]()
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)