I’m also not a WASM expert. But - syscall/js
is calling JavaScript, which is why the JavaScript you are calling can manipulate the DOM. You know how you have to add this to your index.html to make things work?
<script src="wasm_exec.js"></script>
Take a look at the contents of wasm_exec.js
. For example, here is the Call implementation:
// func valueCall(v ref, m string, args []ref) (ref, bool)
"syscall/js.valueCall": (sp) => {
sp >>>= 0;
try {
const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32);
const result = Reflect.apply(m, v, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 56, result);
this.mem.setUint8(sp + 64, 1);
} catch (err) {
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 56, err);
this.mem.setUint8(sp + 64, 0);
}
},
… and then note in the syscall/js
package the following:
// Call does a JavaScript call to the method m of value v with the given arguments.
// It panics if v has no method m.
// The arguments get mapped to JavaScript values according to the ValueOf function.
func (v Value) Call(m string, args ...any) Value {
argVals, argRefs := makeArgSlices(len(args))
storeArgs(args, argVals, argRefs)
res, ok := valueCall(v.ref, m, argRefs)
runtime.KeepAlive(v)
runtime.KeepAlive(argVals)
if !ok {
if vType := v.Type(); !vType.isObject() { // check here to avoid overhead in success case
panic(&ValueError{"Value.Call", vType})
}
if propType := v.Get(m).Type(); propType != TypeFunction {
panic("syscall/js: Value.Call: property " + m + " is not a function, got " + propType.String())
}
panic(Error{makeValue(res)})
}
return makeValue(res)
}
I’m not exactly sure how these annotations work with the compiler:
// valueCall does a JavaScript call to the method name m of ref v with the given arguments.
//
// (noescape): This is safe because no references are maintained to the
// Go string m after the syscall returns. Additionally, the args slice
// is only used temporarily to collect the JavaScript objects for
// the JavaScript method invocation.
//
//go:wasmimport gojs syscall/js.valueCall
//go:nosplit
//go:noescape
func valueCall(v ref, m string, args []ref) (ref, bool)
Anyway, the short answer is: in order to use Go WASM in the browser, you have to have that interop js file that is handling interop for you. It allows you to call JavaScript. JavaScript is able to manipulate the DOM.