SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Rust言語で作るWebバイナリファイル「WebAssembly」入門

Rust/WebAssemblyのトラブルに効くデバッグ&高速化テクニック

Rust言語で作るWebバイナリファイル「WebAssembly」入門 第5回

  • X ポスト
  • このエントリーをはてなブックマークに追加

 本連載では、Webブラウザー上でJavaScriptとともに動作できるバイナリ形式のプログラムファイル「WebAssembly」を、Rustプログラミング言語で実装する方法を説明していきます。前回はRust/WebAssemblyとJavaScriptとのデータ交換について説明しました。今回は、ログ出力とファイルサイズ縮小の方法、および、成果物をパッケージにして世界に公開する方法を説明していきます。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 本連載では、Webフロントエンド開発において注目されているバイナリ形式のプログラムファイルWebAssemblyを、Rustで実装して活用する方法を説明しています。

 より本格的にプログラムを開発するには、正しく動作させるまでにデバッグを行う必要があります。本記事ではデバッグ時に利用できるログ出力について説明します。また、アプリの読み込み速度をより速くできる、ファイルサイズ縮小方法についても述べます。

 完成したプログラムの再利用に備えて、実装したWebAssemblyをパッケージとして世界に公開しておくと便利です。本記事の後半では、WebAssemblyのプログラムを、Node.jsのパッケージマネージャーnpmで利用できるパッケージとして世界に公開する方法と、パッケージを参照して利用する方法を紹介します。

対象読者

  • Rust/WebAssemblyのプログラムが思う通りに動かず試行錯誤している方
  • 速度を追求するためファイルサイズを縮小したい方
  • 実装成果を再利用したり、世界に公開したりしたい方

必要な環境

 本記事のサンプルコードは、以下の環境で動作を確認しています。

  • Windows 10 64bit版
  • Microsoft Edge 111.0.1661.54
  • rustup 1.25.2
  • wasm-pack 0.11.0
  • Node.js v18.15.0 64bit版

 今回のサンプルコード(p004-use-image-processor以外)では、WebAssemblyをビルドするRustのプロジェクトの内部に、WebAssemblyを参照するWebページのプロジェクト(wwwサブフォルダー)を含めています。プロジェクトを実行するには「wasm-pack build」コマンドでWebAssemblyをビルド後、wwwサブフォルダーで「npm install」コマンドを実行してライブラリーをインストールし、「npm run start」コマンドでプログラムを実行します。実行内容はWebブラウザーで「http://localhost:8080」を表示して確認できます。プロジェクトの生成法については、第1回も参考にしてください。p004-use-image-processorサンプルは「npm install」→「npm run start」で実行できます。

 なお、Node.jsに含まれるOpenSSLと、Webページプロジェクトが利用するwebpackとの非互換により「npm run start」が失敗する場合があるので、そのときは環境変数「NODE_OPTIONS」に「--openssl-legacy-provilder」を設定してください。PowerShellの場合は、リスト1のコマンドで環境変数を設定できます。

[リスト1]環境変数NODE_OPTIONSを設定するPowerShellのコマンド
$env:NODE_OPTIONS = "--openssl-legacy-provider"

デバッガーとログ出力

 Rust/WebAssemblyの公式Webページに掲載されたデバッグについての記述では、Rust/WebAssemblyのデバッガー環境がまだ成熟していないことに言及されています。Webブラウザーの開発者ツールを利用しても、Rustのコードではなく生のWebAssembly命令がステップ実行されるため、わかりづらいのが現状です。

図1 生のWebAssembly命令をステップ実行するWebブラウザーの開発者ツール(p001-logging)
図1 生のWebAssembly命令をステップ実行するWebブラウザーの開発者ツール(p001-logging)

 現在現実的に利用できる方法として、ログを出力する処理をソースコードに追加して、Webブラウザーの開発者ツール(コンソール)でそのログを確認する方法があります。Rust/WebAssenbly開発でログ出力を利用する例を、図2のサンプルで説明します。console.logとconsole.errorによるログ出力をRust/WebAssemblyから実行します。

図2 Rust/WebAssemblyからログ出力するサンプル(p001-logging)
図2 Rust/WebAssemblyからログ出力するサンプル(p001-logging)

 また、意図的にパニック(回復不可能なエラー)を発生させたとき、事前に「パニックフックを有効化」ボタンを押しておくと、パニックが発生した場所を出力できます。

図3 パニック発生時のログ出力(p001-logging)
図3 パニック発生時のログ出力(p001-logging)

console.log / errorでRustからログ出力する実装

 JavaScriptのconsole.log / errorを出力する処理は、Rustでリスト2の通り実装します。

[リスト2]console.log / errorを出力するRustの実装(p001-logging/src/lib.rs)
extern crate web_sys; // ... web_sysを利用(1)
(略)
// 引数が1つのconsole.log ...(2)
#[wasm_bindgen]
pub fn console_log(s: &str) {
    web_sys::console::log_1(&s.into());
}
// 引数が2つのconsole.error ...(3)
#[wasm_bindgen]
pub fn console_error(s1: &str, s2: &str) {
    web_sys::console::error_2(&s1.into(), &s2.into());
}

 (1)で、ログ出力処理を含むweb_sysクレートを参照します。(2)がconsole.log、(3)がconsole.errorの処理です。web_sys::console::log_1、web_sys::console::error_2メソッドを利用してログ出力します。各メソッドの「_1」、「_2」は、引数に指定する文字列の数を表します。引数の文字列で「&<変数名>.info()」としているのは、文字列をJavaScriptで利用する値(JsValue)に変換するためです。

 「log_1」~「log_7」および「error_1」~「error_7」の各メソッドが提供されており、ログ出力時に最大で7個の引数を受け取れます。さらに、ログ出力する任意個の文字列を、JsValueの配列で指定できる「web_sys::console::log」「web_sys::console::error」メソッドもあります。ログ出力メソッドの詳細は公式ドキュメントも参照してください。

 これらのメソッドはweb_sysクレートに含まれるので、Cargo.tomlにweb_sysクレートの指定を、リスト3の通り追加します。

[リスト3]web-sysクレートの追加(p001-logging/Cargo.toml)
[dependencies.web-sys]
version = "0.3"
features = [
  "console"
]

パニック時のログ出力

 Rustでは、実行中に回復不可能なエラーが発生したときに「パニック」が発生します。このサンプルでは、リスト4(1)のpanic!マクロで意図的にパニックを発生させます。

[リスト4]パニックを発生させるRustの実装(p001-logging/src/lib.rs)
#[wasm_bindgen]
pub fn exec_panic(s: &str) {
    panic!("パニック発生!詳細は->{}", s); // ...(1)
}

 パニック発生時はWebブラウザーのコンソールにエラーが出力されますが、その内容は図3(a)の通りわかりづらいものです。これを図3(b)の通りわかりやすくするには、リスト5(1)の通り、set_panic_hookメソッドをあらかじめ実行しておきます。

[リスト5]わかりやすいパニック時ログを出力するための処理(p001-logging/src/lib.rs)
#[wasm_bindgen]
pub fn enable_panic_hook() {
    console_log("console_error_panic_hookを有効にしました");
    utils::set_panic_hook(); // ...(1)
}

 set_panic_hookメソッドは、プロジェクトにデフォルトで含まれるutil.rsにリスト6の通り実装されています。

[リスト6]set_panic_hookメソッドの実装(p001-logging/src/utils.rs)
pub fn set_panic_hook() {
    #[cfg(feature = "console_error_panic_hook")] // feature指定 ...(1)
    console_error_panic_hook::set_once();        // パニックフック指定 ...(2)
}

 (1)は、featureに「console_error_panic_hook」が指定されたときに処理を行うことを表します。(2)の処理で、わかりやすいエラーログを出力する機能を有効にします。(1)の「console_error_panic_hook」は、Cargo.tomlにリスト7の通りデフォルト設定されているため、(2)のパニックフック指定が有効になります。

[リスト7]console_error_panic_hookの指定(p001-logging/Cargo.toml)
[features]
default = ["console_error_panic_hook"]

次のページ
プログラムの実行時間を測定するログ出力

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Rust言語で作るWebバイナリファイル「WebAssembly」入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/17936 2023/07/11 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング