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