把 Go 程式編譯成 WASM 的踩坑筆記

zonble
3 min readApr 14, 2020

--

手上有幾個用 Go 寫成的內部使用的 CLI 工具,上週心血來潮,覺得可以搭個 bootstrap 什麼的,做一個 Web 版本的 UI 來用。

一方面,懶得去弄個機器用 gin 什麼的寫個 web server,再來,Web Assembly 技術出來也好一陣子時間,但一直以來也都沒有碰過,週末就做個練功的小 side project,把手上的 Go 程式編譯成 WASM 來用,有些玩具也是得自己踩過一次,才會知道有哪些坑。

…後來想想,小孩子才做選擇,我應該試試看把一個 web server 編譯成 WASM,然後在瀏覽器裡頭跑 web server。

打開 golang 官方文件,就發現事情跟我想的不一樣。原本以為我只要編譯成 WASM 之後,就可以讓瀏覽器當成某種 library 載入,然後就可以直接去呼叫這個 library 裡頭的 function;但是,把 Go 程式編譯成 WASM 之後呢,反倒像是編譯成某種執行檔,載入之後,你去執行他,就跑進了整個 Go 程式的 main() funtion 裡頭,如果你不特別去做點什麼事情,只要main() 跑完,整個程式就結束了,之後你也無法呼叫裡頭的東西。

要能夠讓 JavaScript 呼叫用 Go 寫成的 function ,把 Go 寫成的 function 暴露到 JavaScript 的世界中,重點就是在 main() 裡頭寫上幾行程式,把 Go 寫成 function 包裝成 JavaScript funciton,註冊到 Global JavaScript context 裡頭,而且不能夠讓 main() 結束,而不要讓 main() 結束的方法,就是在 main() 裡頭建立一個 channel,然後一直不要把 channel 關掉,這個作法怎麼看都有點微妙。

也就是說,如果你一不小心在 Go 程式裡頭製造了一個 exception,那 main() 就會結束;你可能覺得只有一個 function 寫錯,不應該影響整個網頁,但因為 main() 結束了,我們所註冊的 function 就會全部失效,整個網頁用到 WASM 的地方也就全部失效…世道就已經這麼艱難了,有必要把事情搞得這麼激烈嘛。

把 Go function 暴露到 JavaScript 的過程實在有點彆扭,也可能是所有其他程式語言想跟 JavaScript 介接都很彆扭,而在這個小玩具當中,我覺得最彆扭的大概是錯誤處理。

Go 裡頭還頂常見呼叫某個 function 之後回傳正確結果與錯誤,像 result, err := someFunction() 這種寫法,然後如果在某個 function 呼叫另外一個 function 遇到錯誤,就直接回傳錯誤。可是呢,Go 沒辦法把錯誤型態的物件傳遞到 JavaScript 中,只能夠回傳 nil、bool、數字、字串、array 與 map,搞錯物件型態還直接 panic 給你看,結果就是得要把錯誤當成字串回傳,或是包裝成某種 map,然後傳到 JavaScript 裡頭變成某種物件。不舒服啊。

不過程式編出來才 3mb 左右,執行起來速度也還不錯。

--

--

zonble
zonble

Written by zonble

XDDDD - eXtreme Due Date Driven Development

No responses yet