<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: George</title>
    <description>The latest articles on DEV Community by George (@taterbase).</description>
    <link>https://dev.to/taterbase</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F387612%2F9104059c-1362-4311-b915-5ad3be3bc69e.jpg</url>
      <title>DEV Community: George</title>
      <link>https://dev.to/taterbase</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/taterbase"/>
    <language>en</language>
    <item>
      <title>Running a Go program in Deno via WASM</title>
      <dc:creator>George</dc:creator>
      <pubDate>Sat, 16 May 2020 22:29:47 +0000</pubDate>
      <link>https://dev.to/taterbase/running-a-go-program-in-deno-via-wasm-2l08</link>
      <guid>https://dev.to/taterbase/running-a-go-program-in-deno-via-wasm-2l08</guid>
      <description>&lt;p&gt;&lt;a href="https://deno.land/v1"&gt;Deno v1.0 landed this week&lt;/a&gt; and I just wanted to take a moment to talk about how you can run a Go program in Deno via WASM bytecode. If you don't know what Deno is be sure to click that link and read up on the release as it's incredibly interesting. Long story short it's a Rust runtime that comes bundled with V8 and can interpret JavaScript/TypeScript (and WASM) natively within a secure environment. &lt;/p&gt;

&lt;p&gt;To start, we'll need to write a Go program. Let's do something trivial just to prove it works. We'll write this in a file called &lt;code&gt;main.go&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello deno"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Great, we can run &lt;code&gt;go build -o hello-deno&lt;/code&gt; and we'll get a binary that we can run called &lt;code&gt;hello-deno&lt;/code&gt;. Executing that binary is as easy as &lt;code&gt;./hello-deno&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;main.go
taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;go build &lt;span class="nt"&gt;-o&lt;/span&gt; hello-deno
taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;hello-deno main.go 
taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;./hello-deno
hello deno
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we've confirmed the program will build and run natively. Now, let's generate the WASM bytecode. Go has great &lt;a href="https://github.com/golang/go/wiki/WebAssembly"&gt;docs on how to generate WASM binaries&lt;/a&gt;. I'll cut to the chase and tell you that in order to cross-compile our code to WASM we'll need to set two environment variables. &lt;code&gt;GOOS=js&lt;/code&gt; and &lt;code&gt;GOARCH=wasm&lt;/code&gt;. Typically when cross-compiling Go code you need to specify the target operating system/runtime environment (&lt;code&gt;GOOS&lt;/code&gt;) in this case &lt;code&gt;js&lt;/code&gt; for JavaScript, and the target architecture (&lt;code&gt;GOARCH&lt;/code&gt;) which is &lt;code&gt;wasm&lt;/code&gt;. Let's do that now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;taterbase:~&lt;span class="nv"&gt;$ GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;js &lt;span class="nv"&gt;GOARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wasm go build &lt;span class="nt"&gt;-o&lt;/span&gt; deno.wasm
taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;deno.wasm  hello-deno  main.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have our WASM bytecode we can start setting up the scaffolding needed to execute it within Deno. One important note about running WASM generated from Go code is you must import a support js file that Go provides in its installation directory. You can copy it like so &lt;code&gt;cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .&lt;/code&gt; (this is detailed in the Go WebAssembly docs linked above).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;go &lt;span class="nb"&gt;env &lt;/span&gt;GOROOT&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/misc/wasm/wasm_exec.js"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;deno.wasm  hello-deno  main.go  wasm_exec.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's write the bootstrap js code now. I'm going to call it &lt;code&gt;deno.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./wasm_exec.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;go&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./deno.wasm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;importObject&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here's what's happening line by line.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The import at the top is to just bring the go support js code into the runtime. It attaches a constructor, &lt;code&gt;Go&lt;/code&gt;, to the window object for us to use later. &lt;/li&gt;
&lt;li&gt;We then create &lt;code&gt;go&lt;/code&gt; as an instance of the &lt;code&gt;Go&lt;/code&gt; "class".&lt;/li&gt;
&lt;li&gt;Using a core Deno api, we open the wasm bytecode file. Opening a file is an asynchronous action and we use the &lt;code&gt;await&lt;/code&gt; keyword to the tell the program to let the operation finish before proceeding.&lt;/li&gt;
&lt;li&gt;We then use another built in async operation, &lt;code&gt;readAll&lt;/code&gt; to read the whole buffer from the wasm file. This will give us a &lt;code&gt;Uint8Array&lt;/code&gt; that represents the bytes of the of wasm file.&lt;/li&gt;
&lt;li&gt;We then create a WebAssembly instance, passing in our byte array and the &lt;code&gt;importObject&lt;/code&gt; provided by our Go support code. I'm not completely clear on the value of the &lt;code&gt;importObject&lt;/code&gt; but from what I gather it maps important values/functions that the modules inside the WASM bytecode expect to be available to execute. All I know at this moment is it's required for execution, so pass it in.&lt;/li&gt;
&lt;li&gt;We then use the support &lt;code&gt;go&lt;/code&gt; instance to run instance itself. This executes the wasm code!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's run it and see what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;deno run deno.js
error: Uncaught PermissionDenied: &lt;span class="nb"&gt;read &lt;/span&gt;access to &lt;span class="s2"&gt;"/home/taterbase/wasm-go/deno.wasm"&lt;/span&gt;, run again with the &lt;span class="nt"&gt;--allow-read&lt;/span&gt; flag
    at unwrapResponse &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$deno$/&lt;/span&gt;ops/dispatch_json.ts:43:11&lt;span class="o"&gt;)&lt;/span&gt;
    at Object.sendAsync &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$deno$/&lt;/span&gt;ops/dispatch_json.ts:98:10&lt;span class="o"&gt;)&lt;/span&gt;
    at async Object.open &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$deno$/&lt;/span&gt;files.ts:37:15&lt;span class="o"&gt;)&lt;/span&gt;
    at async file:///home/taterbase/wasm-go/deno.js:3:11
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We've run up against one of Deno's highly touted features, out of the box security. By default Deno won't let us read/write from the filesystem (or even make network calls for that matter). We need to explicitly allow it access to the filesystem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;taterbase:~&lt;span class="nv"&gt;$ &lt;/span&gt;deno run &lt;span class="nt"&gt;--allow-read&lt;/span&gt; deno.js
hello deno
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There you have it. We took Go code, compiled it to wasm bytecode, and ran it within Deno! I hope you find this helpful. Most logic can be cross-compiled and run successfully however things get tricky when you start doing i/o. I've been doing some reading and while I can't get tcp socket listening in a Go program working out of the box I hope to do another writeup in the future showing a solution for that. &lt;/p&gt;

&lt;p&gt;Until then, happy hacking.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>go</category>
      <category>deno</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
