Oleksii Vasyliev, Railsware
Brought to you by Alexey Vasiliev, Railsware
The Emscripten tool is able to take just about any C/C++ source code and compile it into a .wasm module, plus the necessary JavaScript "glue" code for loading and running the module, and an HTML document to display the results of the code
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
int fib(int n) {
if(n <= 0){
return 0;
}
int i, t, a = 0, b = 1;
for (i = 1; i < n; i++) {
t = a + b;
a = b;
b = t;
}
return b;
}
emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' fib.c
<script src="a.out.js"></script>
<script>
Module.onRuntimeInitialized = _ => {
const fib = Module.cwrap('fib', 'number', ['number']);
console.log(fib(12));
};
</script>
<script>
(async function() {
const imports = {
env: {
memory: new WebAssembly.Memory({initial: 1}),
STACKTOP: 0,
}
};
const {instance} = await WebAssembly.instantiateStreaming(
fetch('/a.out.wasm'),
imports
);
console.log(instance.exports._fib(12));
})();
</script>
emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \
-I libwebp \
webp.c \
libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c
cargo install wasm-pack
npm install -g wasm-pack
yarn global add wasm-pack
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
$ wasm-pack build
[INFO]: 🎯 Checking for the Wasm target...
[INFO]: 🌀 Compiling to Wasm...
Compiling proc-macro2 v1.0.32
Compiling unicode-xid v0.2.2
Compiling log v0.4.14
Compiling syn v1.0.82
Compiling wasm-bindgen-shared v0.2.78
...
Compiling js-sys v0.3.55
Compiling console_error_panic_hook v0.1.7
Compiling web-sys v0.3.55
Compiling wasm-game-of-life v0.1.0 (/Users/leo/Downloads/wasm_game_of_life)
Finished release [optimized] target(s) in 17.17s
[INFO]: ⬇️ Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary,
but recommended
[INFO]: ✨ Done in 21.55s
<script type="module">
import init, {greet} from "./pkg/hello_wasm.js";
init()
.then(() => {
greet("WebAssembly")
});
</script>
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World")
// Prevent the function from returning, which is required in a wasm module
<-make(chan bool)
}
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
GOOS=js GOARCH=wasm go build -o main.wasm
const loadWasm = (path) => {
const go = new Go()
return new Promise((resolve, reject) => {
WebAssembly.instantiateStreaming(fetch(path), go.importObject)
.then(result => {
go.run(result.instance)
resolve(result.instance)
})
.catch(error => {
reject(error)
})
})
}
// Load the wasm file
loadWasm("main.wasm").then(wasm => {
console.log("main.wasm is loaded ")
}).catch(error => {
console.error("ouch", error)
})
package main
import (
"syscall/js"
)
func main() {
message := "Hello World"
document := js.Global().Get("document")
h2 := document.Call("createElement", "h2")
h2.Set("innerHTML", message)
document.Get("body").Call("appendChild", h2)
<-make(chan bool)
}
func MyGoFunc() js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
// Get the current time as a Go time.Time object
now := time.Now()
// Get the Date object constructor from JavaScript
dateConstructor := js.Global().Get("Date")
// Return a new JS "Date" object with the time from the Go "now" variable
// We're passing the UNIX timestamp to the "Date" constructor
// Because JS uses milliseconds for UNIX timestamp, we need to multiply the timestamp by 1000
return dateConstructor.New(now.Unix() * 1000)
})
}
| Go | JavaScript |
| ---------------------- | ---------------------- |
| js.Value | [its value] |
| js.Func | function |
| nil | null |
| bool | boolean |
| integers and floats | number |
| string | string |
| []interface{} | new array |
| map[string]interface{} | new object |