Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm: global functions from wasm not working from node #29845

Closed
mattetti opened this issue Jan 20, 2019 · 18 comments
Closed

wasm: global functions from wasm not working from node #29845

mattetti opened this issue Jan 20, 2019 · 18 comments
Labels
arch-wasm WebAssembly issues FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@mattetti
Copy link
Contributor

What version of Go are you using (go version)?

$ go version
go version go1.12beta2 Darwin/amd64

Does this issue reproduce with the latest release?

Yes

What did you do?

I am trying to call registered functions (aka callbacks) defined in the WebAssembly file from node js. I use the provided wasm_exec.js which does call into the main function without any issues. From what I could gather, we are missing a way to expose the registered functions in JS. But unfortunately I am not familiar enough with the implementation details nor did I find a lot of information online on the matter.

What did you expect to see?

I expected to be able to call my exposed functions from js outside of the browser.

What did you see instead?

A js exception

@mattetti
Copy link
Contributor Author

@neelance you might know if that's a user error, a missing feature or a bug. Any feedback or pointer to solve the challenge for would be greatly appreciated.

@agnivade
Copy link
Contributor

I believe this is something that you are trying to do ?

fn := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    // do your stuff here
})

js.Global().Set("myFunc", fn)

Now from JS, call myFunc().

@mattetti
Copy link
Contributor Author

@agnivade that's exact what I do, but myFunc isn't defined in the scope. At least not when try to call it after the wasm binary was instantiated. Some languages seem to out the functions in the instance.exports but I am a bit lost with what we are doing in Go and my node knowledge is limited. Thanks for looking into it and trying to help though, very much appreciated!

@agnivade
Copy link
Contributor

Ah yes, that just might be the case. In the browser, we have window as global. I am not sure how to define functions in the global scope for node from wasm.

@agnivade agnivade changed the title WebAssembly - can't called registered functions from node wasm: how to define global functions from wasm and call them from node Jan 21, 2019
@neelance
Copy link
Member

In Node.js the global object is called global instead of window.

@agnivade
Copy link
Contributor

So then shouldn't js.Global().Set("myFunc", fn) work transparently for the browser and node both ?

@mikioh
Copy link
Contributor

mikioh commented Jan 21, 2019

@agnivade,

It might be better to have a look at https://github.com/tc39/proposal-global.

@neelance
Copy link
Member

So then shouldn't js.Global().Set("myFunc", fn) work transparently for the browser and node both ?

Yes.

@agnivade
Copy link
Contributor

But that's not what's happening

but myFunc isn't defined in the scope.

That is why I thought setting an object in the global scope might not work for Node.js.

But if that's supposed to work, then I am not sure why myFunc doesn't get defined in the global scope. Or probably I have misunderstood the question somehow.

@neelance
Copy link
Member

It should definitely be possible to call global.myFunc();. Someone please post some concrete code that is failing, otherwise we're just guessing about the issue.

@mattetti
Copy link
Contributor Author

mattetti commented Jan 21, 2019

I was traveling with very limited internet and could not upload a repro case. I did test calling global.myFunc() but it wasn't defined. I'm back home and will out together a quick example ASAP. Thanks everyone

@mattetti
Copy link
Contributor Author

@neelance here is the repro example: https://github.com/mattetti/go-node-wasm

The main Go file is here: https://github.com/mattetti/go-node-wasm/blob/master/src/wasm/main.go
JS code change: https://github.com/mattetti/go-node-wasm/blob/master/src/node/wasm_exec.js#L506

To run the code I use the following command: GOOS=js GOARCH=wasm go run -exec=./src/node/go_js_wasm_exec ./src/wasm/main.go

Error:

(node:40122) UnhandledPromiseRejectionWarning: TypeError: global.add is not a function
    at WebAssembly.instantiate.then (/Users/mattetti/Code/go-node-wasm/src/node/wasm_exec.js:506:28)

@agnivade agnivade added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. arch-wasm WebAssembly issues and removed Question labels Jan 22, 2019
@agnivade agnivade changed the title wasm: how to define global functions from wasm and call them from node wasm: global functions from wasm not working from node Jan 22, 2019
@neelance
Copy link
Member

The go.run(result.instance); is returning earlier than you expect. If you do this:

	fmt.Println("loading")
	fmt.Println("loading 2")
	js.Global().Set("add", js.FuncOf(add))

then you get:

loading
(node:85999) UnhandledPromiseRejectionWarning: TypeError: global.add is not a function
    at WebAssembly.instantiate.then (/Users/richard/Repos/go-node-wasm/src/node/wasm_exec.js:506:28)
loading 2

Instead, have your Go code call some JS global after it is done with setup.

@mattetti
Copy link
Contributor Author

@neelance thanks for looking into my issue. Moving the js global declaration into init() did indeed solve the declaration problem. Is that the expected behavior tho? I'm going to eventually update the wiki and I'm curious to know if that's a side effect of the implementation, that might be revisited or if that pattern is the definite medium term answer.

@neelance
Copy link
Member

Using init does not make any difference. If you add fmt.Println before your call, you would still see the same issue.

In general you are not supposed to modify wasm_exec.js. This is internal code and if you edit it then there are no guarantees about the outcome. So this issue is invalid since it involves editing wasm_exec.js.

@mattetti
Copy link
Contributor Author

@neelance I still don't quite understand the issue and agree that it would be best to not have to modify wasm_exec.js, but then I'm still unclear on how to use go compiled wasm from node. Is there a way to do that without modifying wasm_exec.js, is that just not officially supported by the go implementation? I'm not trying to give you a hard time or complain, I'd just love to provide some guidance to anyone who might be interested in making their Go code available into a node app by using the WebAssembly compilation target.

@neelance
Copy link
Member

Instead, have your Go code call some JS global after it is done with setup.

Essentially your JS code has to wait until your Go code is done with preparations.

Btw: Have you joined the #webassembly channel on the Gophers Slack? You can also get advice there.

@mattetti
Copy link
Contributor Author

Went there and got great feedback, what I was missing was how to let the js code know that the go code is ready. This comment is meant to help anyone finding this issue:

Agniva De Sarker shared the following solution:

So currently, your JS code starts after go.run(...). What I am saying is move all that code to a separate function, name it startCb or sth. And then after all your js.Global().Set() calls are done, call startCb using js.Global().Call("startCb")

In your main.go, do this -

func main() {
	js.Global().Set("add", js.FuncOf(add))
	js.Global().Call("startCb")
	fmt.Println("loading")
	wait()
}

And have this at the start of wasm_exec.js

global.startCb = () => {
  console.log(global.add(1, 1));
  console.log("...");
};
$GOOS=js GOARCH=wasm go1.12beta1 run -exec=./src/node/go_js_wasm_exec ./src/wasm/main.go 
2
...
loading

@golang golang locked and limited conversation to collaborators Jan 23, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-wasm WebAssembly issues FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants