ウェブ上でWebAssemblyを第一級言語にする

2026/03/11 13:44

ウェブ上でWebAssemblyを第一級言語にする

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

(欠落しているポイントを組み込む):**

要約

WebAssembly(Wasm)は2017年のデビュー以来、共有メモリ、SIMD、例外処理、テールコール、64ビットメモリ、ガベージコレクション、大量メモリ命令、複数戻り値、および参照値などの機能を追加しながら進化してきました。これらの技術的進歩にもかかわらず、Wasmは「二次的」なウェブ言語として位置づけられ続けています。というのも、すべてのモジュールが依然としてJavaScriptを介してロードされ、ブラウザAPIにバインドされる必要があるからです。

主な障壁は2つあります:

  1. 面倒なロード – JavaScript が
    WebAssembly.instantiateStreaming
    を使って手動でモジュールをフェッチし、インスタンス化する必要があります。
  2. APIアクセスにはグルーコードが必要 – WasmメモリとJSオブジェクト間の変換は言語固有であり、ビルドの複雑さを増加させ、実行時にオーバーヘッド(例:TodoMVCベンチマークで45%の遅延)が発生します。

esm-integration
の提案では、
.wasm
モジュールを
<script type="module" src="/module.wasm">
で直接インポートできるようにし、ロードを簡素化しますが、グルーコード問題は解決されません。Clang/LLVMなどのコンパイラは依然としてベアWasmを出力し、開発者は JavaScript を埋め込む非公式ツールチェーンに頼ることが多いです。

WebAssembly コンポーネントモデル は解決策を提示します:コンポーネントは高レベルのIDL(WIT)と低レベルのWasmコードをバンドルし、ブラウザや他言語がインターフェースを直接インポートできるようにします。例えば、Rust コンポーネントは WIT を介して

import std:web/console
し、
console::log
を呼び出すことができます。そのコンパイル済みコンポーネントは
<script type="module" src="component.wasm">
でブラウザにロードされます。JavaScript はエクスポートされたインターフェース(例:画像デコーダ)をネイティブモジュールとして消費できます(
import { Image } from "image-lib.wasm"
)。

Mozilla と Google がこのモデルの構築に協力しており、Jco や Wasmtime などのツールはすでに開発者が実験できるようになっています。プラットフォーム統合のための JavaScript 依存を排除することで、コンポーネントモデルはビルドの複雑さ低減、パフォーマンス向上、および言語間相互運用性の拡大を約束し、WebAssembly のウェブエコシステム全体での採用を加速させる可能性があります。

本文

この投稿は、2025年ミュンヘンで開催された WebAssembly CG(コア開発者グループ)の会議で行ったプレゼンテーションを拡張したものです。

WebAssembly は 2017 年の初リリース以来、大きく進化しました。
最初のバージョンは C や C++ のような低レベル言語にすぐに適合し、ウェブ上で効率的に動作する新しい種類のアプリケーションを実現できました。

それ以降、WebAssembly CG は言語のコア機能を大幅に拡張し、共有メモリ、SIMD、例外処理、テイル・コール、64 ビットメモリ、GC サポートなどを追加しました。さらに、バルクメモリ命令や複数戻り値、参照値といった小さな改善も加えられました。
これらの拡張により、より多くの言語が WebAssembly を効率的にターゲットできるようになりました。スタックスイッチングやスレッド化などまだ重要な作業は残っていますが、WebAssembly はネイティブと比較して多くの面でギャップを縮めています。

それでも、何かが足りず WebAssembly がウェブ上で広く採用されることを妨げているように感じます。
その原因は複数ありますが、核心は「WebAssembly はウェブ上で二級言語になっている」点です。新しい言語機能が追加されたにもかかわらず、WebAssembly はウェブプラットフォームと十分に統合されていません。

結果として開発者体験が悪く、必要な場合以外は WebAssembly を使わないという選択肢が多く、JavaScript の方が「簡単で十分」というケースがほとんどです。こうしたユーザーは大規模企業に限られやすく、WebAssembly の恩恵はウェブコミュニティ全体ではなく一部の大手企業へと限定されてしまいます。

この問題を解決することは難しく、CG は WebAssembly 言語そのものの拡張に注力してきました。言語が十分に成熟した今、この点をより深く掘り下げる時です。本稿ではまず問題点を詳細に検討し、その後 WebAssembly コンポーネントがどのように改善策になるかを説明します。


なぜ WebAssembly は二級言語なのか?

ウェブプラットフォームのスクリプト層は次のように構造化されています:

  • JavaScript は直接ウェブプラットフォームと対話できます。
  • WebAssembly は JavaScript と直接対話し、さらに JavaScript を介してウェブプラットフォームと対話します。
    WebAssembly はウェブプラットフォームにアクセスできますが、JavaScript の特殊な機能を使わない限りは不可能です。
    JavaScript はウェブ上で一次言語であり、WebAssembly はそうではありません。

これは意図的・悪意ある設計決定ではなく、JavaScript がウェブの最初のスクリプト言語として存在し、プラットフォームと共進化した結果です。しかし、この設計は WebAssembly のユーザーに大きな影響を与えます。

JavaScript の特殊機能とは?

本稿で取り上げる主なものは 2 つです:

  1. コードのロード
  2. Web API の使用

コードのロード

WebAssembly コードは必要以上に面倒にロードされます。JavaScript コードを読み込むには単純に

<script>
タグを書けば済みます。

<script src="script.js"></script>

一方、現在 WebAssembly は

<script>
タグで直接サポートされていないため、開発者は WebAssembly JS API を使って手動でロード・インスタンス化する必要があります。

let bytecode = fetch(import.meta.resolve('./module.wasm'));
let imports = { /* ... */ };
let { exports } = await WebAssembly.instantiateStreaming(bytecode, imports);

この一連の API 呼び出しは煩雑で、同じ処理を行う方法はいくつか存在し、それぞれにトレードオフがあります。ほとんどの開発者は覚えることができず、ツールによって自動生成されるケースが多いです。

幸いにも、

esm-integration
という提案(既にバンドラーで実装済み、Firefox でも積極的に取り入れられている)が、JS モジュールシステムを使って WebAssembly モジュールをインポートできるようにします。

import { run } from "/module.wasm";
run();

また

type="module"
を指定した
<script>
タグから直接ロードすることも可能です。

<script type="module" src="/module.wasm"></script>

これにより、WebAssembly モジュールのロードとインスタンス化で最も一般的なパターンが簡素化されます。しかし、この解決策は初期の難しさを和らげるだけで、本質的な問題には直結していません。


Web API の使用

JavaScript から Web API を呼び出すのは次のように非常にシンプルです:

console.log("hello, world");

WebAssembly では状況が格段に複雑になります。WebAssembly は Web API に直接アクセスできず、JavaScript を介さなければなりません。

単行

console.log
の例を示します。

JavaScript 側

// Wasm コードの生メモリへアクセスするため、ここで作成してインポートとして渡す。
let memory = new WebAssembly.Memory(/* ... */);

function consoleLog(messageStartIndex, messageLength) {
  // メッセージは Wasm のメモリに格納されているが、
  // JS 文字列へデコードする必要がある(DOM API が要求)。
  let messageMemoryView = new Uint8Array(
      memory.buffer, messageStartIndex, messageLength);
  let messageString =
    new TextDecoder().decode(messageMemoryView);

  // Wasm は `console` グローバルにアクセスできないため、ここで行う。
  return console.log(messageString);
}

// インポートとして Web API を渡す。
let imports = {
  "env": {
    "memory": memory,
    "consoleLog": consoleLog,
  },
};

let { instance } =
  await WebAssembly.instantiateStreaming(bytecode, imports);

instance.exports.run();

WebAssembly 側

(module
  ;; JS コードからメモリをインポート
  (import "env" "memory" (memory 0))

  ;; JS consoleLog ラッパー関数をインポート
  (import "env" "consoleLog"
    (func $consoleLog (param i32 i32))
  )

  ;; run 関数をエクスポート
  (func (export "run")
    (local i32 $messageStartIndex)
    (local i32 $messageLength)

    ;; Wasm メモリに文字列を作成し、ローカルへ格納
    ...

    ;; consoleLog を呼び出す
    local.get $messageStartIndex
    local.get $messageLength
    call $consoleLog
  )
)

このようなコードは「バインディング」または「グリューコード」と呼ばれ、ソース言語(C++、Rust など)と Web API の橋渡しをします。データのエンコーディング/デコードを行うため、非常に面倒で定型的です。そのため

embind
wasm-bindgen
といったツールで自動生成されるケースが多いです。

ただし、このグリューコードは実行時コストも伴います。JavaScript オブジェクトの確保とガベージコレクション、文字列の再エンコード、構造体のデシリアライズなどが発生します。この境界でのオーバーヘッドは、呼び出し自体が高速でも存在します。

「Wasm が DOM サポートをいつ持つか?」という質問は、このようなグリューコードに依存しているためです。実際には WebAPI にアクセスできるものの、JavaScript の橋渡しが必要です。


それが重要なのはなぜ?

技術的には現状でも動作します。WebAssembly はウェブ上で稼働し、多くのプロジェクトが成功裏にデリバリーされています。

しかし平均的なウェブ開発者にとっては、現状は不十分です。WebAssembly を使うこと自体が複雑すぎて、二級体験を避けたくなるケースが多いです。結果として WebAssembly は「パワーユーザー向け機能」になり、平均的な開発者は使わない傾向にあります。

一般的な開発者の旅路

JavaScript

プロジェクトの規模が増すにつれて、徐々に複雑な機能を学んでいく滑らかな曲線があります。

WebAssembly

すぐに「壁」を越える必要があり、多くの要素をまとめて動かさないといけません。結果として大規模プロジェクト向きになりやすいです。


なぜこのようになるのか?

主な理由は以下で、全て WebAssembly がウェブ上で二級言語であることに起因します。

  1. コンパイラが一次体験を提供しづらい
    ウェブをターゲットする言語は、Wasm ファイルだけでなく、JS 伴奏ファイル(ロード・WebAPI アクセス・その他の処理)も生成する必要があります。これは各言語ごとに再実装が必要で、非ウェブプラットフォームでは再利用できません。

  2. 標準コンパイラはウェブ向け WebAssembly を生成しない
    Clang/LLVM などの上流コンパイラは JS やウェブプラットフォームを意識せず、すべてのプラットフォームで動く単一バイナリを生成したいだけです。そのため、WebAssembly 用の「公式」ツールチェーンが不足しています。

  3. ウェブドキュメントは JavaScript 向け
    ほとんどの資料が JavaScript 開発者向けに書かれています。JavaScript を知らない場合、Web API の使い方を理解するのが非常に難しくなります。

  4. Web API 呼び出しは遅いこともある

    console.log
    1 回でさえ多くのオーバーヘッドがあります。エンジン側は最適化していますが、問題は残ります。すべてのワークロードに影響するわけではありませんが、注意が必要です。

  5. 常に JavaScript レイヤーを理解しなければならない
    各言語は自前でウェブプラットフォームへの抽象化を構築します。この抽象化はリークしており、真剣に WebAssembly を使うと最終的には JavaScript を直接読む・書く必要があります。


どうすれば解決できるか?

これは技術的にも社会的にも複雑な問題で、一つの解決策だけでは不十分です。まず「理想的に何があれば助けになるだろう?」と問ってみます。

  • 標準化された自己完結型実行アーティファクト
  • 複数言語・ツールチェーンでサポートされる
  • WebAssembly コードのロード・リンクを担う
  • Web API の使用もサポートする

そのようなものがあれば、言語はこのアーティファクトを生成し、ブラウザは JavaScript を介さずに実行できます。標準上流コンパイラやランタイム、ツールチェーン、人気のあるパッケージでサポートされる可能性があります。


WebAssembly コンポーネントモデル

WebAssembly コンポーネントモデルはこれらを目指す提案であり、長年にわたり開発が進められています。高レベル API を低レベル WebAssembly コードの束として実装します。

現時点でできること

  • 複数言語からコンポーネントを作成
  • ブラウザ(多くはポリフィル)やその他ランタイムで実行
  • コンポーネント間でリンクし、コード再利用を可能に
  • WebAssembly コードが直接 Web API を呼び出せる

詳細は Component Book や「What is a Component?」をご覧ください。


例:コンポーネントで
console.log

以下は実装の一例(チュートリアルではありません)。

  1. WIT(WebAssembly Interface Types)で必要な API を宣言
component {
  import std:web/console;
}
  1. Rust でインポートを利用
use std::web::console;

fn main() {
  console::log("hello, world");
}
  1. ブラウザにコンポーネントを読み込む
<script type="module" src="component.wasm"></script>

ブラウザは自動的にコンポーネントをロードし、ネイティブ Web API を直接バインドして実行します。


ハイブリッドアプリケーション

WebAssembly の利用は多くの場合 JavaScript と併用されるハイブリッドアプリです。コンポーネントはクロス言語相互運用をサポートすることでこの課題にも対処します。

例:画像デコーダーコンポーネント

interface image-lib {
  record pixel {
    r: u8;
    g: u8;
    b: u8;
    a: u8;
  }

  resource image {
    from-stream:
      static async func(bytes: stream<u8>) -> result<image>;
    get: func(x: u32, y: u32) -> pixel;
  }
}

component {
  export image-lib;
}

任意の言語で実装したコンポーネントは、JavaScript から次のように利用できます。

import { Image } from "image-lib.wasm";

let byteStream = (await fetch("/image.file")).body;
let image = await Image.fromStream(byteStream);
let pixel = image.get(0, 0);

console.log(pixel); // { r: 255, g: 255, b: 0, a: 255 }

次のステップ

WebAssembly コンポーネントは、ウェブ上で WebAssembly に一次体験を与える有望な進歩です。Mozilla は WebAssembly CG と協力してコンポーネントモデルを設計中であり、Google も評価しています。

試したい方は以下から始めてください:

  • 最初のコンポーネントをビルドする方法を学ぶ
  • Jco(ブラウザ)や Wasmtime(CLI)でテストする
  • フィードバックやコードを貢献し、ツールはまだ発展途上です

開発中の仕様は component-model プロポーザルリポジトリにあります。

WebAssembly は 2017 年以降大きく進歩しました。今後も「パワーユーザー向け機能」から平均的な開発者が恩恵を受けられるものへと変わる可能性があります。

同じ日のほかのニュース

一覧に戻る →

2026/03/12 0:35

**Temporal:JavaScript で時間を直すための9 年間の旅**

## Japanese Translation: > Bloomberg の JavaScript インフラストラクチャチームは、Chromium(ブラウザ用)、Node.js(サーバー用)、SpiderMonkey(埋め込み用途)という統一されたランタイムスタックを提供し、そのエンジニアリングワークフォースを支援しています。 > このチームは TC39 を通じて Temporal の提案を推進する上で重要な役割を果たしており、Igalia と緊密に協力し代表者として活動しています。Promise.allSettled、Arrow Functions、BigInt、Class Fields などへの貢献で知られる Jason Williams がこの取り組みを主導しました。 > Temporal は JavaScript の可変 Date オブジェクトを不可変型(PlainDate、PlainTime、ZonedDateTime、Instant)に置き換え、明示的なタイムゾーンとカレンダーのサポート、およびナノ秒精度を提供します。2024 年 6 月に Stage 4 に達し、現在は ES2026 スペックの一部となっています。 > Bloomberg の金融ユースケースでは、設定可能なタイムゾーン、最新の IANA tzdata、そして高精度のタイムスタンプが必要であり、これが Temporal の開発を推進しました。この提案は Google Internationalization チーム、Boa、Kevin Ness、Manish Goregaokar、Jose Espina によって構築された Rust ライブラリ *temporal_rs* を通じて協力的に実装され、現在約 4,500 件の Test262 テストに合格しています。 > ブラウザサポートのマイルストーンは次のとおりです:Firefox v139(2025 年 5 月)、Chrome v144 & Edge v144(2026 年 1 月);Node.js v26 および TypeScript 6.0 Beta(2026 年 2 月)も近々期待されています。Safari は部分的なプレビューを提供しています。 > 主な実装上の課題には、提案サイズ(ECMA‑402 より大きい)、仕様の揺らぎ、パフォーマンス要求、および大規模テストスイートの必要性が含まれます。 > 今後の作業は Temporal を既存の Web API(デートピッカー、DOMHighResTimeStamp、クッキー有効期限など)と統合し、従来の Date ベースのライブラリとの後方互換性を確保することに焦点を当てています。 > Microsoft、Google、Mozilla、Bloomberg、Igalia、Boa、および独立した貢献者間の協力は、重複を減らし JavaScript エコシステム全体でイノベーションを加速させる共有インフラストラクチャモデルを示しています。 この改訂された概要はすべての主要ポイントを保持し、不当な推論を排除し、明確で曖昧さのない物語を提示します。

2026/03/12 4:29

生成・AI で編集されたコメントを投稿しないでください。HN は人と人との対話の場です。

## 日本語訳: (すべての重要ポイントを含む)** このポリシーは明確な使命を示しています。ハッキング、スタートアップ、および関連技術テーマに関する好奇心駆動型ディスカッションを開催し、政治・犯罪・スポーツ・有名人ゴシップ(新たな現象が明らかでない限り)は厳格に除外します。 この焦点を維持するため、ガイドラインはオントピックとオフトピックのコンテンツを区別し、投稿にはオリジナルソースの使用(再投稿時は引用)を求め、タイトルで宣伝的言語を禁止します。タイトルは大文字・感嘆符・過剰な数字や形容詞を避け、サイト名を含まないようにし、代わりに強調のためにアスタリスクを使用できます。動画またはPDF投稿の場合、タイトルに「[video]」または「[pdf]」を付加します。 コメントは思慮深く実質的であることが期待されます。皮肉・浅い軽蔑・炎上誘発・政治/イデオロギー戦争は排除し、人物ではなく議論に対処すべきです。AI生成または編集されたコメントは禁止されており、全てのディスカッションは人間同士で行われることを意図しています。アップボートやコメントの要請は禁じられており、投票とコメントは真剣な関心から生まれるべきです。 モデレーションは過度に差し控えめな発言をフラグ付けすることに重点を置き、形式ルールを強化し、イデオロギー対立を会話から排除します。その結果、誤情報・センセーション主義・宣伝活動を抑制しつつ、集中した技術的探求を奨励するプラットフォームが実現されます。

2026/03/12 5:56

多くのSWE bench‑passing PR はマージされることがないでしょう。

## Japanese Translation: **概要:** 本研究では、2024年中頃から2025年末までに提出された296件のAI生成プルリクエスト(PR)を、scikit‑learn、Sphinx、および pytest の3つの主要なソフトウェア工学ベンチマークリポジトリで、4名の活発なメンテナーから検証しました。これらの PR の約半分は、メンテナーの判断にノイズを加えてもメインブランチへマージされませんでした。平均して、自動評価者(グレーダー)の合格率はメンテナーのマージ率より 24.2 パーセントポイント高く、統計的に有意であることが示されました。メンテナーの年次改善率はグレーダーのそれを約 9.6 pp/yr 遅れ、弱いながらも統計的に有意な結果でした。 メンテナーは主にコード品質(スタイル不備やリポジトリ標準への非準拠)を理由に PR を拒否しました。他の失敗要因としては既存コードの破損、コア機能の喪失、および自動グレーダーの失格が挙げられます。Claude 3.5 Sonnet から Claude 3.7 Sonnet へのモデルアップグレードにより合格率は上昇しましたが、同時にコア機能拒否も増加し、後続のアップグレードでは主にコード品質の改善が見られました。GPT‑5 は Anthropic モデルと比べてコード品質で顕著に劣り、マージ率を低下させました。 ヒューマン「ゴールデン」パッチは 68 % のメンテナー マージ率と約 90 % のマージ可能性向上率を示し、このベースラインがモデルスコアの正規化に使用されました。PR を再評価して ≥80 % のマージ可能性進捗に達した場合、結果は合格率分析と同様であり、AI パッチの約 50 % が閾値を満たし、ゴールデンパッチでは約 100 % に相当しました。時間軸解析では、自動グレーダーがメンテナー評価に対してモデル能力を約7倍過大評価していることが明らかになりました。 制限点としては、リポジトリカバレッジの限定(検証済みリポジトリ 3/12)、レビュー時の継続的インテグレーションの欠如、および静的評価に留まるパッチ評価が挙げられます。著者は、ベンチマークスコアからの単純な外挿は誤解を招くと結論付けており、メンテナーによるレビューこそがエージェント有用性をより現実的に測定する手段であると示しています。