Go から MoonBit へ #
このブログは、もともと Go の標準ライブラリだけで作り、Workers では TinyGo の wasm として動かしていた。
同じサイトを MoonBit で作り直し、今は blog という Worker で MoonBit の wasm が動いている。
今読んでいるこのページも、MoonBit が組み立てた HTML だ。
何を移したか #
Go 版のパッケージを、ほぼ一対一で moonbit/ に移した。
| Go | MoonBit |
|---|---|
pkg/el、pkg/picoel | moonbit/el、moonbit/picoel |
pkg/tinymarkdown | moonbit/tinymarkdown |
pkg/tinyfrontmatter | moonbit/tinyfrontmatter |
go:embed | moon.pkg の dev_build で生成するソース |
examples/blog/internal/site | moonbit/site |
- Go のテストのケースは、同じ構文木、同じ出力になることを
moon testで確かめている。 - MoonBit には
go:embedがないので、記事や文書を(ファイル名, 本文)の組として MoonBit のソースに書き出して埋め込む。生成したソースはコミットしない。 - 移植のあいだは、Go 版と MoonBit 版に同じパスを取りにいき、ステータス、
Content-Type、本文を比べる CLI(make compare)を物差しにした。切り替える前に、記事、文書、それぞれの.md版、リダイレクト、404 まで、30 パスがすべて一致した。
サイズと起動時間 #
| ビルド | アップロード(gzip 後) | 起動時間 |
|---|---|---|
| MoonBit(wasm-gc) | 237.41 KiB(78.50 KiB) | 2 ms |
| TinyGo | 2117.89 KiB(757.41 KiB) | 8 ms |
アップロードは TinyGo 版のおよそ 9 分の 1 になった。 このうち少なくない部分は、埋め込んだ記事や文書の本文だ。 Go のランタイムを抱えない分、言語の側の重さはほとんど残っていない。
JS ではなく wasm で #
MoonBit は JS にもビルドできる。 Workers は JS が本来の住人なので、そちらのほうがずっと素直に動くはずだ。 それでも wasm にしたのは、ロマンだ。
その代わり、少し工夫が要った。
- MoonBit の wasm-gc は、
use-js-builtin-stringを使うと JS の文字列をそのまま受け渡せる。ただしこれはコンパイル時のオプションが前提で、Workers では import した wasm にそのオプションを渡せない。 - そこで、文字列を UTF-16 のコード単位ごとに 1 つずつ受け渡す小さな ABI にした。ステータスとヘッダーも同じ ABI で返す。
- 1 文字ごとに JS と行き来するので遅そうに見えるが、このサイトでいちばん大きいページ(約 54 KB)でも、ローカルの
wrangler devでの往復は/より 0.5 ms 遅いだけだった。
Go 版はどうなるか #
Go 版は消していない。
go run ./examples/blog はローカルで記事を書くときのサーバーで、MoonBit 版と比べるときの基準でもある。
記事もまだ Go 版の posts/ に置いてあり、MoonBit 版はそこから埋め込んでいる。
Workers の blog を Go 版に戻したければ、Go 版をもう一度デプロイすればいい。
詳しくは 調査メモ にまとめてある。