You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Gopherjs runtime on frontend - inspired by gopherjs playground #76
I've been experimenting these past 2 weeks on my spare time, trying to expose a runCode global at the frontend, that will allow users to run arbitrary Go code, purely on the client side, it is heavily inspired by the gopher playground.
I removed the UI parts, and made some modifications, but I seem to be hitting a roadblock,
when trying to use
this error originates from fmt.Println function only, other fmt functions I've tested work as expected.
Also, I've noticed that in the original code, there's a loading phase first, and then a run, it seems necessary in my case too, (running the code seems to be doing the loading phase + running, which throws some errors, but running again, will just run the code without loading, and result with no console errors) I'm just not sure as to how to implement it.
I haven't tried to run your code, but I see at least one significant misunderstanding, which is probably causing at least some of your issues.
There aren't two phases per se. You provide the compiler with the main package and the importContext object. That object is supposed to load precompiled archives of imported packages on demand and return them to the compiler. The regular gopherjs compiler uses this to recursively compiler the whole import tree starting with the main package.
So instead of running one attempt to compiler, collecting dependencies, loading them, and making the next attempt you should just load the package when the compiler asks for it, completing the whole thing in a single pass.
GopherJS supports the standard net/http client, you could use that instead of the honnef.co/go/js/xhr package to load imported packages.
Instead of js.Global.Call("eval", js.InternalObject("console.log('code: "+string(escaped)+"')")) you can use println(code) to print to the debug console. fmt.Printf() works for that purpose too. To call console.error() you can simply do js.Global.Get("console").Call("error", "my message").
So instead of running one attempt to compiler, collecting dependencies, loading them, and making the next attempt you should just load the package when the compiler asks for it, completing the whole thing in a single pass.
if I get it right, do you suggest placing the http.get(...) logic for getting the package inside the import context?
Ok, so I spent some time looking at your code today, and there were two main issues:
Your runCodeAsync() function wasn't actually async — you were still blocking on a channel at the end, which is why on the first run it would throw an error after kicking off HTTP requests. The second execution would work because the HTTP request would complete in the background and then no blocking operations would happen.
There was some weird desynchronization between the version of runtime the compiler was outputting and the precompiled packages. Not sure why the compiler was picking up the wrong version, but I was able to fix that by upgrading the go.mod dependency to gopherjs 1.18.0-beta3 and running gopherjs clean.
On a more general note, part of the GopherJS philosophy is that you could try to write your code as you would with normal Go, as much as possible, and confine JS-aware parts to as few places as possible. That tends to yield a much more readable program. I did some refactoring of your code and you can find a working example here:
Activity
nevkontakte commentedon Aug 4, 2023
I haven't tried to run your code, but I see at least one significant misunderstanding, which is probably causing at least some of your issues.
There aren't two phases per se. You provide the compiler with the main package and the
importContextobject. That object is supposed to load precompiled archives of imported packages on demand and return them to the compiler. The regular gopherjs compiler uses this to recursively compiler the whole import tree starting with the main package.So instead of running one attempt to compiler, collecting dependencies, loading them, and making the next attempt you should just load the package when the compiler asks for it, completing the whole thing in a single pass.
nevkontakte commentedon Aug 4, 2023
Besides that, a couple of general tips:
net/httpclient, you could use that instead of thehonnef.co/go/js/xhrpackage to load imported packages.js.Global.Call("eval", js.InternalObject("console.log('code: "+string(escaped)+"')"))you can useprintln(code)to print to the debug console.fmt.Printf()works for that purpose too. To callconsole.error()you can simply dojs.Global.Get("console").Call("error", "my message").naorzr commentedon Aug 5, 2023
if I get it right, do you suggest placing the
http.get(...)logic for getting the package inside the import context?nevkontakte commentedon Aug 6, 2023
Ok, so I spent some time looking at your code today, and there were two main issues:
runCodeAsync()function wasn't actually async — you were still blocking on a channel at the end, which is why on the first run it would throw an error after kicking off HTTP requests. The second execution would work because the HTTP request would complete in the background and then no blocking operations would happen.gopherjs clean.On a more general note, part of the GopherJS philosophy is that you could try to write your code as you would with normal Go, as much as possible, and confine JS-aware parts to as few places as possible. That tends to yield a much more readable program. I did some refactoring of your code and you can find a working example here:
nevkontakte@5408ff2#diff-6639521c1bb3cd1e0ee9891ede42f19a89aab52a1417124481590cf761dfe432