Description
Proposal Details
I don't know if this is a thing that already exists or not. I want to be able to import ESM modules in Go. I can do this in JavaScript via the dynamic import()
expression. Right now the only way I know how to do this without extra modifications (where I expect the consumer to just copy-paste wasm_exec.js
, wasm_exec_node.js
, or wasm_exec.html
into their source tree and use that) is to use eval()
which seems... not ideal.
package main
import (
"syscall/js"
"log"
)
// import is a function-like keyword, not a global function
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import
var jsImportFunc = js.Global().Get("eval").Invoke("(s,o)=>import(s,o)") // 🟥🟥🟥
func jsImport(specifier string, options any) js.Value {
return jsImportFunc.Invoke(specifier, options)
}
// https://stackoverflow.com/questions/68415674/await-js-async-function-promise-inside-a-go-function
func jsAwait(promise js.Value) js.Value {
c := make(chan js.Value)
jsOnResolve := js.FuncOf(func(this js.Value, args []js.Value) any {
c <- args[0]
return nil
})
jsOnReject := js.FuncOf(func(this js.Value, args []js.Value) any {
// act the same as if a function threw
panic(&js.Error{Value:args[0]})
return nil
})
promise.Call("then", jsOnResolve, jsOnReject)
return <-c
}
func main() {
jsPrettier := jsAwait(jsImport("prettier", js.Value{}))
jsFormatted := jsAwait(jsPrettier.Call("format", "hello();world();", map[string]any{
"parser": "typescript", // https://prettier.io/docs/en/options#parser
}))
log.Print(jsFormatted.String())
}
The eval()
breaks when a user of the Go wasm blob disallows unsafe eval()
via Content-Security-Policy.
I know, I know. I could just do globalThis.import = (s,o)=>import(s,o)
in JavaScript before I run the Go test.wasm
blob. But I don't control how the user uses my WASM blob and it would be really nice if I didn't have to ask them to "hey please add this thing when you use the wasm_exec.js
to load this wasm file".
A cool minor change to do this would be to add a Go.prototype._import()
method that is just this:
class Go {
_import(specifier, options) {
return import(specifier, options)
}
}
and then in the syscall/js Go code:
func Import(specifier string, options any) js.Value {
return whateverThePrivateGoRuntimeVariableIsCalled.Call("_import", specifier, options)
}
or you could add it to the importObject
thing instead. The point is that this syntax thing (not a global function) is currently unobtainable without resorting to eval()
or forcing the user of the my-cool-go-thing.wasm
to include a special snippet in addition to the wasm_exec.js
standard Go wasm+js runtime.
Metadata
Metadata
Assignees
Type
Projects
Status