gopherjs / gopherjs.github.io

GopherJS Playground
https://gopherjs.github.io/playground/
23 stars 12 forks source link

Gopherjs runtime on frontend - inspired by gopherjs playground #76

Open naorzr opened 1 year ago

naorzr commented 1 year ago

Hello!

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

runCode(`
package main

import (
    "fmt"
    "syscall/js"
)

func main() {
    fmt.Println("Hello, playground")
    js.Global().Call("alert", "Hello, JavaScript")
    js.Global().Get("console").Call("log", "Hello, JS console")

}

`)

I end up getting

$mapIndex is not defined

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.

the altered code can be found here https://github.com/naorzr/gopherjs-runtime/blob/master/playground/main.go and it can be run and played with by running the index.html from this repo https://github.com/naorzr/gopherjs-runtime/tree/master/playground

nevkontakte commented 1 year ago

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.

nevkontakte commented 1 year ago

Besides that, a couple of general tips:

naorzr commented 1 year ago

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?

nevkontakte commented 1 year ago

Ok, so I spent some time looking at your code today, and there were two main issues:

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:

https://github.com/nevkontakte/gopherjs.github.io/commit/5408ff2dd5db0cbec64f6017f9229a3aac7c8841#diff-6639521c1bb3cd1e0ee9891ede42f19a89aab52a1417124481590cf761dfe432