Comments

edited

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

Go 1.11

Does this issue reproduce with the latest release?

Yes

What did you expect to see?

GopherJS supports the option to bundle raw JavaScript in the compiled output by including files named *.inc.js in the Go source directory. Go's wasm support doesn't offer anything comparable, as far as I am aware.

What did you see instead?

I would like to see the functional equivalent included when compiling to a wasm target.

I say functionally equivalent, because identical might be dangerous, in that it could make isomorphic GopherJS/GoWASM packages difficult, if there are ever incompatibilities. It is likely that one might need a particular *.inc.js file for GopherJS support, and a separate one for Go/WASM support. And at least at present, build tags in these files are broken for GopherJS (see gopherjs/gopherjs#468), so unless that is resolved, or some other mutual-exclusion scheme is provided, the simplest path forward may be to use an entirely different convention for Go/WASM.

No doubt, many lessons from CGO can also be applied here, but this is an area where I have no direct experience.

flimzy
changed the title from
cmd/compile: Provide some way to include raw JavaScript during wasm compilation
to
cmd/compile: Provide some way to bundle raw JavaScript during wasm compilationSep 11, 2018

ianlancetaylor
changed the title from
cmd/compile: Provide some way to bundle raw JavaScript during wasm compilation
to
cmd/compile: provide some way to bundle raw JavaScript during wasm compilationSep 12, 2018

ianlancetaylor
changed the title from
cmd/compile: provide some way to bundle raw JavaScript during wasm compilation
to
cmd/go: provide some way to bundle raw JavaScript during wasm compilationSep 12, 2018

This comment has been minimized.

Is there some trick that can be performed here using eval in JavaScript? You'd want to avoid any sort of string encoding conversions, i.e. have pre-compiled the correct encoding within the .wasm output, but feels like it would be possible?

That way we could avoid the go tool needing to do anything special; a go generate-r could do the bundling and encoding, with an init()-time function then being responsible for calling eval.

This comment has been minimized.

This comment has been minimized.

edited

I've just read the CGO introduction, to familiarize myself with the approach taken there. Based on that, my more specific proposal would be the following:

A new special import package (akin to import "C") would be added. Name to be determined, but for the purpose of this proposal, let's assume we use import "WASM".

When the Go tool sees this special import is used in a package, then any *.js files in the same directory will be included in the wasm output. At runtime, this code is to be executed before package initialization (that is to say, the Go code should be able to safely assume that all included *.js files have been successfully executed).

The contents of each *.js file should be wrapped in a context to provide access to a special this variable. Exmaple:

(function() {
// Contents of a single *.js file here
}).call(goWASM)

This goWASM variable would then be accessible from Go via the WASM package.

This allows the included *.js files to define variables or functions which can be accessed from Go, without polluting the global namespace.

Build constraints for the *.js files ought to be followed, as per usual rules.

This differs from GopherJS's implementation in two key ways:

*.js files would not be included automatically, but rather only if the WASM package is imported. This would be more in-line with CGO's behavior.

Each *.js file would be executed with access to a package-specific this variable, exposed to Go via WASM.This. In GopherJS, this was the global object, requiring any special variables to pollute the global namespace.

A few additional thoughts I haven't fully considered:

The import package name (WASM above) and the single exported symbol (WASM.This) should be considered. No doubt better alternatives for one or both exist.

Execution order of *.js files, when there are multiples, may be important, so should probably be defined.

This could break compatibility with GopherJS (as mentioned in the original issue description above). To resolve this, go could ignore *.inc.js files, as a special case.

This comment has been minimized.

The Go compiler generates wasm binaries. The only way to include JavaScript code in a wasm binary is to use eval, but it is incompatible with a secure CSP. If you accept this, then you can use eval right now, there is no extra support necessary in the Go compiler.

I see no simple way on how something like the *.inc.js files of GopherJS can be possible with wasm. The logic you describe above might be possible, but I think it should not be part of the Go compiler itself. The best way would probably be to use require with some existing JS bundler and maybe have this JS bundler scan for .js files in the Go tree.