WebAssembly入門書:WebAssemblyを使い始める

WebAssemblyは、まったく新しい種類のWebを約束します。ユーザーにとってはより高速なパフォーマンスであり、開発者にとってはより柔軟性があります。開発者は、クライアント側のWebインタラクションの唯一の言語としてJavaScriptを使用することに縛られる代わりに、C、TypeScript、Rust、Ruby、Pythonなど、他のさまざまな言語から選択して、最も快適な言語で作業できます。と。

もともと、WebAssembly(または略してWASM)を作成する唯一の方法は、Emscriptenツールチェーンを使用してC / C ++コードをWebAssemblyにコンパイルすることでした。今日、開発者はより多くの言語オプションを利用できるようになっただけでなく、これらの他の言語をWebAssemblyに直接コンパイルすることも簡単になりました。

この記事では、WebAssemblyコンポーネントをWebアプリに実装するために必要な手順を検討します。WebAssemblyは進行中の作業であるため、手順は使用する言語に大きく依存し、ツールチェーンはしばらくの間変更され続ける可能性があります。しかし、現時点では、最小限のWebAssemblyアプリケーションをさまざまな言語で作成してデプロイすることが可能です。

WebAssemblyでサポートされている言語を選択してください

WebAssemblyアプリケーションをデプロイするための最初のステップは、ターゲットとしてWebAssemblyにコンパイルできる言語を選択することです。本番環境で使用している主要言語の少なくとも1つをWebAssemblyに変換できるか、WebAssemblyを発行できるコンパイラーを備えている可能性があります。

これがフロントランナーです:

  • C.明らかに。 CコードをWebAssemblyに変換する一般的な方法は、Emscriptenを使用することです。これは、C-to-Emscripten-to-WebAssemblyが最初のWebAssemblyツールチェーンであるためです。しかし、他のツールが登場しています。コンパイラ全体であるCheerpは、C / C ++コードからWebAssemblyアプリケーションを生成するように特別に設計されています。 Cheerpは、JavaScript、asm.js、または上記の任意の組み合わせをターゲットにすることもできます。 Clangツールチェーンを使用してWebAssemblyペイロードを構築することもできますが、プロセスには依然としてかなりの手動による持ち上げが必要です。 (これが一例です。)
  • さび。安全かつ高速に設計されたMozillaのシステムプログラミング言語は、ネイティブWebAssemblyサポートの主要な候補の1つです。Rustツールチェーンの拡張機能を使用すると、RustコードからWebAssemblyに直接コンパイルできます。nightlyWebAssemblyのコンパイルを実行するには、Rustのツールチェーンを使用する必要があるため、この機能は今のところ実験的なものと見なす必要があります。
  • TypeScript。デフォルトでは、TypeScriptはJavaScriptにコンパイルされます。つまり、WebAssemblyにコンパイルできます。AssemblyScriptプロジェクトは、関連するステップの数を減らし、厳密に型指定されたTypeScriptをWebAssemblyにコンパイルできるようにします。

他のいくつかの言語がWebAssemblyをターゲットにし始めていますが、それらは非常に初期の段階にあります。次の言語を使用してWebAssemblyコンポーネントを構築できますが、C、Rust、およびTypeScriptよりも限定された方法でのみ使用できます。

  • D。D言語は最近、コンパイルとWebAssemblyへの直接リンクのサポートを追加しました。
  • Java。Javaバイトコードは、TeaVMプロジェクトを介してWebAssemblyに事前にコンパイルできます。つまり Javaバイトコードを発行するすべての言語をWebAssemblyにコンパイルできます(Kotlin、Scala、Clojureなど)。ただし、リフレクションAPIやリソースAPIなど、WebAssemblyで効率的に実装できないJava APIの多くは制限されているため、TeaVM、つまりWebAssemblyは、JVMベースのアプリのサブセットにのみ使用されます。 
  • Lua。Luaスクリプト言語は、JavaScriptと同様に、組み込み言語として長い間使用されてきました。ただし、LuaをWebAssemblyに変換する唯一のプロジェクトには、ブラウザー内実行エンジンの使用が含まれます。wasm_luaはLuaランタイムをブラウザーに埋め込み、LuwaJITはLuaをWebAssemblyにコンパイルします。
  • Kotlin / Native。JavaのスピンオフであるKotlin言語のファンは、スタンドアロンバイナリを生成できるKotlinコンパイラのLLVMバックエンドであるKotlin / Nativeの完全リリースを熱心に待っていました。Kotlin / Native 0.4は、コンパイルターゲットとしてWebAssemblyのサポートを導入しましたが、これは概念実証としてのみです。
  • .Net。.Net言語はまだ本格的なWebAssemblyをサポートしていませんが、いくつかの実験が始まっています。Blazorを参照してください。これは、C#およびMicrosoftの「Razor」構文を介して.Netで単一ページのWebアプリを構築するために使用できます。
  • ニム。この新進気鋭の言語はCにコンパイルされるため、理論的には、結果のCをWebAssemblyにコンパイルできます。ただし、nwasmと呼ばれるNimの実験的なバックエンドは開発中です。
  • 他のLLVMを利用した言語。理論的には、LLVMは多くのターゲットの1つとしてWebAssemblyをサポートしているため、LLVMコンパイラフレームワークを利用する任意の言語をWebAssemblyにコンパイルできます。ただし、これは必ずしもLLVMでコンパイルされた言語がWebAssemblyでそのまま実行されることを意味するわけではありません。これは、LLVMによってWebAssemblyのターゲティングが容易になることを意味します。

上記のプロジェクトはすべて、元のプログラムまたは生成されたバイトコードをWebAssemblyに変換します。ただし、RubyやPythonなどのインタープリター言語の場合は、別のアプローチがあります。アプリ自体を変換する代わりに、言語ランタイム をWebAssemblyに変換します。その後、プログラムは変換されたランタイムでそのまま実行されます。多くの言語ランタイム(RubyやPythonを含む)はC / C ++で記述されているため、変換プロセスは基本的に他のC / C ++アプリケーションと同じです。

もちろん、これは、アプリケーションを実行する前に、変換されたランタイムをブラウザーにダウンロードする必要があることを意味し、ロードと解析時間が遅くなります。アプリの「純粋な」WebAssemblyバージョンはより軽量です。したがって、ランタイム変換は、より多くの言語がエクスポートまたはコンパイルターゲットとしてWebAssemblyをサポートするまで、せいぜい一時的な手段です。

WebAssemblyをJavaScriptと統合する

次のステップは、選択した言語でコードを記述し、そのコードがWebAssembly環境とどのように相互作用するかに注意を払い、それをWebAssemblyモジュール(WASMバイナリ)にコンパイルして、最後にそのモジュールを既存のモジュールと統合することです。 JavaScriptアプリケーション。

コードをWebAssemblyにエクスポートする正確な手順は、ツールチェーンによって大きく異なります。また、その言語用に通常のネイティブバイナリが構築される方法から多少逸脱します。たとえば、Rustでは、いくつかの手順を実行する必要があります。

  1. ツールチェーンを使用nightly して、Rustのビルドをセットアップしwasm32-unknown-unknownます。
  2. として宣言された外部関数を使用してRustコードを記述します#[no-mangle]
  3. 上記のツールチェーンを使用してコードをビルドします。

(上記の手順の詳細については、GitHubのThe Rust and WebAssembly Bookを参照してください。)

使用している言語が何であれ、コードをHTMLフロントエンドと統合するには、少なくともJavaScriptの習熟度が最低限必要であることに注意してください。The Rust and WebAssembly Bookのこの例のページはめ込みJavaScriptスニペットがギリシャ語に思える場合は、そこで何が起こっているのかを理解するのに少なくとも十分なJavaScriptを学習するための時間を取っておきます。

WebAssemblyとJavaScriptの統合は、JavaScriptのWebAssemblyオブジェクトを使用してWebAssemblyコードへのブリッジを作成することによって行われます。Mozillaには、これを行う方法に関するドキュメントがあります。これはRustの別のWebAssemblyの例であり、Node.jsのWebAssemblyの例です。

現在のところ、WebAssemblyバックエンドとJavaScript / HTMLフロントエンドの統合は、プロセス全体の中で最も面倒で手動の部分です。たとえば、Rustでは、JavaScriptへのブリッジを生データポインターを介して手動で作成する必要があります。

ただし、ツールチェーンのより多くの部分がこの問題に対処し始めています。Cheerpフレームワークを使用すると、C ++プログラマーは専用の名前空間を介してブラウザーのAPIと通信できます。また、Rustはwasm-bindgenを提供します。これは、JavaScriptとRustの間、およびJavaScriptとWebAssemblyの間の双方向のブリッジとして機能します。

さらに、ホストへのバインディングを処理する方法についての高レベルの提案が検討されています。完成すると、WebAssemblyにコンパイルされる言語がホストと対話するための標準的な方法が提供されます。この提案の長期戦略には、ブラウザーではないホストへのバインディングも含まれますが、ブラウザーバインディングは、短期間の即時のユースケースです。

WebAssemblyアプリのデバッグとプロファイリング

WebAssemblyツールがまだ初期段階にある領域の1つは、デバッグとプロファイリングのサポートです。 

JavaScriptソースマップが登場するまで、JavaScriptにコンパイルされた言語は、元のコードとコンパイルされたコードを簡単に関連付けることができなかったため、デバッグが困難なことがよくありました。WebAssemblyにも同じ問題がいくつかあります。Cでコードを記述してWASMにコンパイルすると、ソースコードとコンパイルされたコードの間に相関関係を描くのが困難になります。

JavaScriptソースマップは、ソースコードのどの行がコンパイルされたコードのどの領域に対応するかを示します。Emscriptenなどの一部のWebAssemblyツールは、コンパイルされたコードのJavaScriptソースマップを発行することもできます。WebAssemblyの長期計画の1つは、JavaScriptで利用できるものを超えたソースマップシステムですが、それはまだ提案段階にあります。

現在、WASMコードを実際にデバッグする最も直接的な方法は、Webブラウザのデバッグコンソールを使用することです。WebAssemblyCodeのこの記事では、ソースマップを使用してWASMコードを生成し、ブラウザーのデバッグツールで使用できるようにして、コードをステップ実行する方法を示します。説明されている手順は、emccツールを使用してWASMを発行することに依存していることに注意してください。特定のツールチェーンによっては、手順を変更する必要がある場合があります。