2023-01-11
WebAssemblyが使われているRubyParserESモジュール化するために作った、バイナリデータをJavaScriptに変換するオープンソースbin2js」。エンコード方式「Base64」によって1.33倍(4/3)に増えてしまうサイズが気になり調べたところ、1.14倍(8/7)に抑えるBase122を発見し対応。ただ、Base122はgzip圧縮と相性が悪いので、場合によっては引き続きBase64が有効と分かりました。

Base64は64種類の文字を使って8bitのバイナリデータを6bitにエンコードしますが、Base122は可変長文字列エンコード方式UTF-8を使った7bitでエンコードする方式です。変換後の文字列はなかなかスゴイことになります。


「test.base122.js」

GitHubにNode.js用のソースコードがあったので、forkしてESモジュール化しました。(詳細、エンコード方式 base-122 | POSTD


「Base122」

オリジナルからencode/decodeのみを抽出し、文字列とUint8Arrayの相互変換に変更。JavaScriptのソースコード、ヒアドキュメントを使った文字列へと変換するための関数encodeJSStringを追加し、encodeJSを追加しました。(Base122.js on GitHub) const encodeJSString = (s) => "`" + s.replace(/\\/g, '\\\\').replace(/\$/g, "\\$").replace(/`/g, '\\`') + "`"; const encodeJS = (s) => encodeJSString(encode(s));

Base64変換していたbin2jsを、Base122に変えて実験!

順当にサイズが小さくなっています(左図)。が、GitHub Pagesでは標準となっているgzip圧縮をかけたところ、Base64がBase122より小さくなるという結果に。エンコード方式が複雑なためかgzip圧縮との相性が悪いようです。(計測データとChartBar.jsを使った棒グラフ作図プログラムon ES-Jam

そこでESモジュール化したzlib.jsのgzip.js/gunzip.jsを使って、元のデータから圧縮するオプションをbin2jsに追加し再度実験!

左図、元のWASMバイナリデータのgzip圧縮が177KB(元720KB)、Base122で216KB、Base64で248KBとなかなかいい効率です。ただ、右図、この出力をgzip圧縮するとやはりBase64が逆転してしまいます。わずかな差なので、幅広い運用を考えてBase122で統一するのも悪くはなさそう。圧縮オプションを使った場合、12KBあるgunzipするコードをimportするので、もともと圧縮されているファイル、小さいファイル、常時gzip圧縮する環境では圧縮しない方が良いでしょう。

ということで、そこそこ大きいサイズでgzip圧縮されるGitHub Actionsに置く、RubyParserのWASMは、gzip圧縮オプション付きBase64で変換して公開しています。(src on GitHub)

bin2jsで手軽になったWebAssemblyや、Mochi言語を使って実装して比較し、より快適なアプリ環境を目指したいですね。

Tweet
クリエイティブ・コモンズ・ライセンス
本ブログの記事や写真は「Creative Commons — CC BY 4.0」の下に提供します。記事内で紹介するプログラムや作品は、それぞれに記載されたライセンスを参照ください。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / 「一日一創」画像 / RSS