github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/examples/wasm/README.md (about)

     1  # TinyGo WebAssembly examples
     2  
     3  The examples here show two different ways of using WebAssembly with TinyGo:
     4  
     5  1. Defining and exporting functions via the `//export <name>` directive. See
     6  [the export folder](./export) for an example of this.  Additionally, the Wasm
     7  module (which has a default value of `env`) can be specified using
     8  `//go:wasm-module <module>`.
     9  1. Defining and executing a `func main()`. This is similar to how the Go
    10  standard library implementation works. See [the main folder](./main) for an
    11  example of this.
    12  
    13  ## Building
    14  
    15  Build using the `tinygo` compiler:
    16  
    17  ```bash
    18  $ tinygo build -o ./wasm.wasm -target wasm ./main/main.go
    19  ```
    20  
    21  This creates a `wasm.wasm` file, which we can load in JavaScript and execute in
    22  a browser.
    23  
    24  Next, choose which example you want to use:
    25  * [callback](callback): Defines and configures callbacks in Wasm.
    26  * [export](export): Defines callbacks in Wasm, but configures them in JavaScript.
    27  * [invoke](invoke): Invokes a function defined in JavaScript from Wasm.
    28  * [main](main): Prints a message to the JavaScript console from Wasm.
    29  * [slices](slices): Splits an Array defined in JavaScript from Wasm.
    30  
    31  Let's say you chose [main](main), you'd build it like so:
    32  ```bash
    33  $ make main
    34  ```
    35  
    36  ## Running
    37  
    38  Start the local web server:
    39  
    40  ```bash
    41  $ go run server.go
    42  Serving ./html on http://localhost:8080
    43  ```
    44  
    45  Use your web browser to visit http://localhost:8080.
    46  
    47  * Tip: Open the browser development tools (e.g. Right-click, Inspect in
    48    FireFox) to see console output.
    49  
    50  ## How it works
    51  
    52  Execution of the contents require a few JavaScript helper functions which are
    53  called from WebAssembly.
    54  
    55  We have defined these in [wasm_exec.js](../../../targets/wasm_exec.js).  It is
    56  based on `$GOROOT/misc/wasm/wasm_exec.js` from the standard library, but is
    57  slightly different. Ensure you are using the same version of `wasm_exec.js` as
    58  the version of `tinygo` you are using to compile.
    59  
    60  The general steps required to run the WebAssembly file in the browser includes
    61  loading it into JavaScript with `WebAssembly.instantiateStreaming`, or
    62  `WebAssembly.instantiate` in some browsers:
    63  
    64  ```js
    65  const go = new Go(); // Defined in wasm_exec.js
    66  const WASM_URL = 'wasm.wasm';
    67  
    68  var wasm;
    69  
    70  if ('instantiateStreaming' in WebAssembly) {
    71  	WebAssembly.instantiateStreaming(fetch(WASM_URL), go.importObject).then(function (obj) {
    72  		wasm = obj.instance;
    73  		go.run(wasm);
    74  	})
    75  } else {
    76  	fetch(WASM_URL).then(resp =>
    77  		resp.arrayBuffer()
    78  	).then(bytes =>
    79  		WebAssembly.instantiate(bytes, go.importObject).then(function (obj) {
    80  			wasm = obj.instance;
    81  			go.run(wasm);
    82  		})
    83  	)
    84  }
    85  ```
    86  
    87  If you have used explicit exports, you can call them by invoking them under the
    88  `wasm.exports` namespace. See the [`export`](./export/wasm.js) directory for an
    89  example of this.
    90  
    91  In addition to the JavaScript, it is important the wasm file is served with the
    92  [`Content-Type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)
    93  header set to `application/wasm`.  Without it, most browsers won't run it.
    94  
    95  ```go
    96  package main
    97  
    98  import (
    99  	"log"
   100  	"net/http"
   101  	"strings"
   102  )
   103  
   104  const dir = "./html"
   105  
   106  func main() {
   107  	fs := http.FileServer(http.Dir(dir))
   108  	log.Print("Serving " + dir + " on http://localhost:8080")
   109  	http.ListenAndServe(":8080", http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
   110  		resp.Header().Add("Cache-Control", "no-cache")
   111  		if strings.HasSuffix(req.URL.Path, ".wasm") {
   112  			resp.Header().Set("content-type", "application/wasm")
   113  		}
   114  		fs.ServeHTTP(resp, req)
   115  	}))}
   116  ```
   117  
   118  This simple server serves anything inside the `./html` directory on port
   119  `8080`, setting any `*.wasm` files `Content-Type` header appropriately.
   120  
   121  For development purposes (**only!**), it also sets the `Cache-Control` header
   122  so your browser doesn't cache the files.  This is useful while developing, to
   123  ensure your browser displays the newest wasm when you recompile.
   124  
   125  In a production environment you **probably wouldn't** want to set the
   126  `Cache-Control` header like this.  Caching is generally beneficial for end
   127  users.
   128  
   129  Further information on the `Cache-Control` header can be found here:
   130  
   131  * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control