run-wasm icon indicating copy to clipboard operation
run-wasm copied to clipboard

Go language support

Open zackradisic opened this issue 2 years ago • 18 comments

Hey, I recently found the goscript package which is a Go interpreter written in Rust which can be compiled to wasm and used to interpret and run Go code in the browser. I whipped up a quick demo you can try out here.

There are some considerations though:

  1. Only the fmt package from the Go std lib is supported at this time, this is kind of a big deal but the project maintainer now seems to be focused on completing the rest of the packages
  2. Differences in implementation details means that there may be edge cases where there are behavioural discrepancies between running Go code interpted by goscript vs compiled by the actual Go compiler. This probably won't be too big a concern and of course as the project matures these problems will be resolved
  3. goscript uses the filesystem which means it must be compiled to the wasm32-wasi target, which requires a wasm runtime that supports WASI (most browser's dont support it right now). However it's a trivial process to setup wasmer.js which supports WASI (I used this for the demo I linked above)

What is everyone's thoughts on this? If there is interest I would be happy to make a PR to implement this 👍

zackradisic avatar Sep 24 '21 00:09 zackradisic

Your demo is slick! I don't use Go yet, but would love to see this supported!

jsjoeio avatar Sep 24 '21 01:09 jsjoeio

How does using this compare to something like https://github.com/tinygo-org/tinygo?

kennethcassel avatar Sep 24 '21 01:09 kennethcassel

The main thing that compelled me to bring up goscript is that it is an interpreter so the Go code doesn't have to be compiled. If you try the tiny-go playground and open the network tab its compiling the code on a server and sending back the wasm for the client to run. This can be very appealing since it means getting Go to work with the library is painless.

That being said, goscript is missing a lot from Go's standard lib. Like I think at this point it would only be maybe viable for an introductory Go course on Slip for example. Obviously, tiny-go is a much more mature project supporting more features so it comes down to how much we value supporting a larger feature set at this time and if we don't mind the users of the library to have to setup a server to compile the Go code.

Or we could go halfway and have users of the library by default use goscript and can opt in to tiny-go + server side compilation if their needs demand it. What do you guys think?

zackradisic avatar Sep 24 '21 03:09 zackradisic

The tiny-go docs say it's compiling and running in the browser image

kennethcassel avatar Sep 24 '21 13:09 kennethcassel

Hmm that's weird, think it's just vague wording on the docs, I poked around the TinyGo playground's source code and I see that they setup an /api/compile route here which runs the tinygo cli on the server.

Here's the network tab of Chrome devtools where I see the wasm being spit out:

Spoiler warning Screen Shot 2021-09-24 at 7 37 10 PM

Think to get TinyGo working solely in the browser we would have to compile the TinyGo compiler to wasm so we can compile Go to wasm inside wasm 🤯

If we choose the TinyGo server-side compilation route I guess it wouldn't be too difficult to pull some of the code from the playground to get it working

zackradisic avatar Sep 26 '21 01:09 zackradisic

Why not have the actual go compiler compile to wasm? Go does have wasm support!

quackduck avatar Sep 26 '21 02:09 quackduck

TinyGo is preferred because it strips some of the runtime bloat since go wasm binaries are known to be c h o n k y, but none of these can be used if we want to only run Go in the browser without any server-side compilation. For that we would need a Go interpreter (goscript), or some Go compiler that can be compiled to wasm so we can compile the Go code on the client side in the browser.

zackradisic avatar Sep 26 '21 03:09 zackradisic

I think we just ship goscript and then long term experiment on figuring out a way to either add more libs or find support for tinygo!

Ship and iterate is the move 🥷

kennethcassel avatar Sep 26 '21 14:09 kennethcassel

Sounds like a good plan 🚢 ♻️

I can port over some of my existing code from my demonstration, any specific way you want me to do it? Perhaps we should setup a monorepo multiple-package type structure, I think it would be good to have each of these languages in its own package because wasm binaries can be a bit big

zackradisic avatar Sep 26 '21 14:09 zackradisic

Yeah that's a good question.

I think having a common api across languages is good but that shipping the whole binary for every language is a little unnecessary for folks who want to only execute Python for example.

Maybe we should make the user load the binaries via cdn on the front end and they can choose which they want to import?

Or we could look at patterns that other similar libraries do this (similar in that they have heavy dependencies and let a user choose which to use).

Could you explain your option a bit more? Would it still be one npm library? Or multiple? I'd prefer one, with an option to reduce the total size based on a users preference somehow

kennethcassel avatar Sep 26 '21 15:09 kennethcassel

So what I was thinking is we have @slip/run-wasm which is the "core" package and has the main RunWasm component, then each language can expose a class or an object that can interface with that component, imported like @slip/run-wasm-go or @slip/run-wasm-ts.

Then when using the library you do something like this:

import RunWasm from `@slip/run-wasm`
import ts from `@slip/run-run-wasm-ts`

const Code = () => {
  const [code, setCode] = useState('const fn = () => console.log("hello wasm!")')

 return (
    <RunWasm language={ts} code={code} />
  )
}

What do you guys think about this?

zackradisic avatar Sep 26 '21 16:09 zackradisic

Yeah I'm down with this approach!

kennethcassel avatar Sep 26 '21 17:09 kennethcassel

OOh, found this on the Gopher slack: https://github.com/open2b/scriggo

Do you think that could come in handy?

quackduck avatar Sep 26 '21 23:09 quackduck

Amazing find @quackduck !! Scriggo has far more complete support for Go's stdlib. Scriggo's playground is already using wasm so I'll definitely try taking a look at that and getting it working 👍

zackradisic avatar Sep 27 '21 10:09 zackradisic

Is anyone working on this?

ntindle avatar Nov 04 '21 11:11 ntindle

I dont think so @ntindle, feel free to tackle it!

kennethcassel avatar Nov 04 '21 15:11 kennethcassel

Is there any docs on integration of new langs or should I play it by ear?

ntindle avatar Nov 05 '21 16:11 ntindle

RE: the above

Go ships with a wasm runner that we should use independent of the compiler (unless the compiler ships their own). It can be found at $(go env GOROOT)/misc/wasm/wasm_exec.js for Linux systems.

This means that we only need to set up a Go -> WASM compiler. Based on the above discussions and my own research, I found a few things.

There are two options above and one I found: TinyGo:

  • Cons:
    • Does not implement a WASM-based Go compiler. It can compile go to wasm.
    • Is a subset of Go
  • Pros:
    • Very Small

Scriggo:

  • Cons:
    • Does not implement a WASM-based Go compiler. It can compile go to wasm.
    • Is a subset of Go
    • The playground would require us to compile Scriggo to wasm ourselves.
  • Pros:
    • It has an example of how to implement a playground that compiles and runs go

wasm-go-playground:

  • Cons:
    • It is out of date for the latest release of go (hasn't been updated since Apr 2020)
    • It doesn't support the full go lib set, yet
    • No published license
  • Pros;
    • We wouldn't need to support our own compiled Go wasm binaries (hopefully)
    • it is using the real go compiler

I would prefer to use wasm-go-playground due to it using the go compiler itself, not a reimplementation. I opened an issue to address some of the concerns I had.

If we can't get wasm-go-playground, I would recommend having a Github action that periodically runs the Scriggo compile from the Playground and updates it in the repo. We would then be able to use Scriggo in a very similar way as wasm-go-playground without using the official go compiler.

If we wanted to support running pre-compiled Go wasm blobs, it would be trivial to get up. The compilation is the difficult part.

Nicholas

ntindle avatar Nov 26 '21 05:11 ntindle