ぷろじぇくと、みすじら。

Filtered by Tag: Edge

EdgeでWebAssemblyを動かしてみる

Created at: | Tag: Edge WebAssembly

A peek into the WebAssembly Browser PreviewChakraCore v1.4.0からEnable WebAssembly browser preview support under experimental flagとあるようにWebAssemblyのプレビューサポートがEdgeとChakraCoreに入ったので試してみようというお話です。

WebAssemblyのバイナリを作る

WebAssemblyはJavaScriptのようにテキストではなくバイナリの形をとります。つまり実行したいJavaScriptのコードをバイナリに変換する必要があります。 とはいえ何でも変換できるわけではありません。

基本的には低レベルなコード、要するにasm.jsのコードを変換することになります。将来的にはWebAPIやその他オブジェクト類も視野にあるようですが現状では扱えません。 Emscriptenなどのコンパイラはasm.jsのコードを吐くので一旦それで十分ということでしょう。

asm.jsなコードをWebAssemblyに変換すればよいので早速ツールを準備します。本当はEmscriptenでC言語のコードを変換する方が面白いのですがいろいろビルドする準備がとても面倒なのでとりあえずasm.jsをダイレクトに変換してみます。

asm.jsをWebAssemblyにコンパイルするためのツールとしてBinaryenというものが提供されています。 このbinaryenはC++で書かれているasm.jsやLLVM Emscripten出力を変換するためのコンパイラツールチェインです。 残念ながらWindows向けバイナリが提供されているわけではないので結局ビルドが必要ですが Visual Studio 2015とCMakeさえあれば大丈夫です。

Visual StudioとCMakeが揃ったらリポジトリを git clone し、コマンドプロンプトで cmake . を実行すると Binaryen.sln が生成されます。このソリューションファイルを開き、ALL_BUILD プロジェクトをビルドすれば出来上がりです。意外と簡単です。

ビルド後に bin フォルダにいくつかの実行ファイルが生成されます。その中で今回使うのは以下の二つのツールです。

asm.jsをWebAssemblyに変換してみる

というわけでasm.jsなコードをWebAssemblyの形に変換します。変換するコードはBinaryenのREADMEにある以下のシンプルな足し算するだけのコードで試してみます。コードは適当な名前(sample.js など)で保存してください。

function () {
  "use asm";
  function add(x, y) {
    x = x | 0;
    y = y | 0;
    return x + y | 0;
  }
  return { add: add };
}

Binaryenのフローではasm.jsからWebAssemblyのバイナリフォーマット(.wasm)へは直接変換できないので一度テキストフォーマット(wast)に変換して、それをバイナリフォーマットへ変換するという手順が必要です。

というわけでasm.jsをwast形式に変換するasm2wasmコマンドを実行します。しかしwastに変換するのにasm2wasmなのは納得いかないものがあります。

.\asm2wasm.exe test.js

コマンドを実行するとwastへ変換した結果が標準出力に出力されます。 wastはいわゆるS式で単純なコードであれば何となく雰囲気はつかめるのではないでしょうか。

(import "env" "memory" (memory $0 256 256))
  (import "env" "table" (table 0 0 anyfunc))
  (import "env" "memoryBase" (global $memoryBase i32))
  (import "env" "tableBase" (global $tableBase i32))
  (export "add" (func $add))
  (func $add (param $x i32) (param $y i32) (result i32)
    (return
      (i32.add
        (get_local $x)
        (get_local $y)
      )
    )
  )
)

標準出力に出力されても困るのでファイルに保存するように -o オプションでファイル名を指定して出力しましょう。

.\asm2wasm.exe test.js -o test.wast

これで test.wast に変換結果が書き込まれます。次はバイナリに変換…と行きたいところなのですがその前に出力結果を少し変更します。test.wastファイルを適当なテキストエディタで開いて import セクションを削除します。

本当はモジュールを読み込む際にimportするべきものをちゃんと渡してあげれば動くのではと思うのですがEdgeやChromeでうまく動かせず、間違ってるのか仕様と実装が違うのかよくわからないこともありとりあえずなくていいので削除します。出力されているimportは主にEmscriptenを想定している気がします。

で、importセクションを削るとこんな感じです。メソッドをexportしているだけになりました。

(module
  (export "add" (func $add))
  (func $add (param $x i32) (param $y i32) (result i32)
    (return
      (i32.add
        (get_local $x)
        (get_local $y)
      )
    )
  )
)

wastができたら次はバイナリ形式であるwasm形式に変換します。wasm形式への変換にはwasm-as コマンドを使用します。特に難しいこともないので単に実行するだけです。

.\wasm-as.exe test.wast -o test.wasm

これでWebAssemblyのバイナリが出来上がりです!

WebAssemblyのバイナリをブラウザで実行してみる

というわけでwasmが出来上がったのでさっそく実行してみましょう。今回はEdge (Insider Preview)で実行してみます(Chromeで実行しても大丈夫です)。

適当なHTMLを作って次のようなスクリプトを書いて開いてみましょう。

fetch('test.wasm')
    .then(x => x.arrayBuffer())
    .then(x => WebAssembly.compile(x))
    .then(x => {
        const instance = new WebAssembly.Instance(x, {});
        const retval = instance.exports.add(1, 2);
        alert(retval);
    });

1行目と2行目はfetch APIでバイナリを読み込んでいます。WebAssembly関係ないです。

3行目でwasmバイナリはバイトコードみたいなものなのでコンパイルしてモジュールにします。それが WebAssembly.compile です。

5行目はコンパイルしてモジュールになったものからインスタンス(JavaScript界のオブジェクト)を作ります。WebAssembly.Instanceの第一引数にはモジュール、第二引数にはimportするオブジェクトを指定します。今回はimportするものがないので空です。

6行目はインスタンスからエクスポートされている add メソッドを呼び出しです。ついにWebAssemblyのメソッドにたどり着きました。

7行目はaddの結果を出力しているだけですね。

このスクリプトを実行すると alert で 3 が表示されてWebAssemblyを動かした実感を得られるかどうかはわかりませんが動くことを確認できます。まあ面白くはないですけど…。

まとめ

手で書いたasm.jsから吐いても面白くないというかそもそもasm.jsも人間が書くものではない感じがするので、基本的にはEmscriptenのような何らかのコンパイラが出力するものという感じがしますね。C#もLLVMバックエンドとなるLLILCがちゃんと動くようになったら行けるかも、というかMSILからC++コードを吐いてEmscriptenを通してasm.jsというのはUnityがすでにやっているのでそういう道もありそうです。

触ってみた感じとしてWebAssembly.Instanceを作った後は単なるJavaScriptのオブジェクトとして使えるので、ライブラリとして提供されるというユースケースは良さそうです。例えばzlibとかそういった圧縮ライブラリや暗号化ライブラリ、エンコーダーやデコーダーといったものはWebAssemblyで提供されることで高速に読み込んで動作するとか。

折を見てEmscriptenで何か変換したりしてもう少し動かしてる感のあることをやりたいですね。

拡張をChromeからMicrosoft Edgeに移植する

Created at: | Tag: Edge Translation

これはExtensions: Porting Chrome extensions - Microsoft Edge Developmentの何となく翻訳です

拡張をChromeからMicrosoft Edgeに移植するのはMicrosoft Edge Extension Toolkitの助けを借りれば簡単に行えます。この開発者ツールはAPIをブリッジするとともに manifest.json ファイルにあるエラーを明らかにし、パッケージ化されていないChromeの拡張をパッケージ化されていないMicrosoft Edgeの拡張へと変換します。

API ブリッジ

Chrome APIからMicrosoft EdgeのAPIへシームレスな移植を可能にするため、2つのスクリプトが拡張のフォルダーに追加されます。それらのスクリプトはAPIをブリッジ(必要に応じてpolyfil)するため、バックグラウンドスクリプトまたはコンテンツスクリプトに含まれるChrome固有のコードの変更について心配する必要はないということを意味します。

変換後、拡張のマニフェストファイルに "-ms-preload" キーとともに以下の項目が含まれていることに気がつくでしょう:

"-ms-preload": {
  "backgroundScript": "backgroundScriptsAPIBridge.js",
  "contentScript": "contentScriptsAPIBridge.js"
}

Microsoft Edge Extension Toolkitを利用する

以下の手順はChromeの拡張をWindows 10 Anniversary Update エディションのMicrosoft Edgeでを変換し動かす方法についてです:

  1. Microsoft Edge Extension Toolkitをインストールします
  2. Chromeの拡張のフォルダーを安全のためにコピーします。変換処理はコードを上書きします
  3. Microsoft Edge Extension Toolkit を実行し、拡張のコピーを読み込みます load extension button
  4. ツールのテキストエディターに報告されるすべてのエラーを修正します。修正した後、"Re-validate" を選択してエラーをチェックします
    extension-toolkit finding errors
  5. "Save files" を選択します

これでToolkitを終了して、拡張をMicrosoft Edgeで読み込めます!

既知のプラットフォームの問題をEdgeHTML issue trackerで探すことができます。もし新しい問題を見つけたと思ったらissueをオープンしてください!

まどすた #1 でMicrosoft Edgeの話をしたのとASP.NET CoreをBash on Windowsで起動する話

Created at: | Tag: Edge Event

まどすた #1 ~ //build/ 2016 振り返りというイベントが5月21日にありまして、 Microsoft Edgeのセッションをさせていただきました。

元々Windows Insider MeetupというイベントのLT(15分)の資料を元に、 30分という枠に向けて加筆修正を加えデモを中心としていくつか機能を紹介しました。

特にEdge上でのWindows HelloのデモはWindows Insider Meetupの際にも、 MSの方も初めて見たといっていたので多分日本でデモしたのはそれと今回ぐらいだと思います(エヘン。Edgeで体験できるデモサイトも公開しているので興味のある方はお試しください。

Cutting Edge! - Speaker Deck

ASP.NET CoreをBash on Windowsで起動する

ところでEdgeと関係なく、デモサイトはASP.NET Coreで実装したのですが、折角なのでLinuxで動かしてみよう→ とはいえLinuxでサーバー立ち上げるのめんどくさい…→ここにBash on Windowsがあるじゃろ?ということで"ASP.NET Core for Linux on Bash on Windows"でデモしました(ちなみに使っていたのはbashではなくzshです)。

さすがにそのままでは動かないのですがほどほど簡単に動かせます。動かすための手順はデモの時には触れなかったので少し書いておきます。

まず普通にBash on Windows上で.NET CoreのLinux、Ubuntuでのインストール手順を参考にそのままコピペしてインストールします。

するとdotnetコマンドを実行できるようになりますが、そのままではまだ動作しません。どうも何かのシステムコールでサポートしていないフラグを使っているようです(詳しいことは忘れました)。 そこで以下のコマンドを実行します。

apt-get install execstack # 入ってなければ
execstack -c /usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0-rc2-3002702/libcoreclr.so

さてこれでdotnetコマンドが動くようになります。試しに dotnet init と dotnet restore 、dotnet run を実行するとちゃんと動くことに驚くかもしれません。

ではASP.NET Coreのアプリケーションも?と思い、dotnet restore と dotnet run を実行するとサーバー(Kestrel)が起動しますが、LISTENはしているものの接続できない状態になります。 ネットワーク周りなのかlibuv周りなのかそのあたりがうまく動作しないようです。

そこで Program.cs を開いて WebHostBuilder で UseKestrel にオプションを渡すよう以下のように修正します。

var host = new WebHostBuilder() 
       .UseKestrel(options => 
       { 
           options.ThreadCount = 1; // この設定を足す
       }) 
       .UseContentRoot(Directory.GetCurrentDirectory()) 
       .UseIISIntegration() 
       .UseStartup<Startup>() 
       .Build();

これで dotnet run を実行するとアプリケーションを起動できます。キセキっぽさがありますけど…。

ちょっと手を加える必要がありますがUbuntu向けのCoreCLR、ASP.NET Coreが動作してしまうというのはかなり驚きです。 手軽にLinux環境を用意して色々なものを実行できるBash on Windowsは現状でもすごいのでもっと実装が良くなってくるのが期待できます。

Micorosoft Edge Build 14316 リリース

Created at: | Tag: Edge JavaScript HTML

Windows 10 build 14316のリリースで先日のBuildやEdge Summitで出てきたいろいろなアップデートが入ってきました。

プラットフォームアップデートもいろいろありますが、拡張がパワーアップしたのと、Web Notifications、アクセシビリティーツリービューあたりが気になるところでしょうか。

新しい機能

Webプラットフォーム機能

Web Notifications

Webページから通知を表示できる機能で、Edgeの場合にはWindowsの通知機能と連動することになります。

ページが通知の許可を求める(Notification.requestPermission)と、ページの下の方に確認が出てきます。

スクリーンショット: 通知の許可を求める

許可をした状態でページから通知を発行する(new Notification(...))とWindowsの通知として表示されます。

スクリーンショット: 通知が表示される

もちろんちゃんとAction Centerにも入ります。

スクリーンショット: Action Center内にも通知が表示される

F12: アクセシビリティーツリービュー

F12にアクセシビリティーツリービューというものが増えました。 これはページについているroleやスクリーンリーダーに渡す読み上げテキストをツリー表示できるものです。

ツリービューを開くにはF12のDOM Explorerのカラーピッカーのボタンの横に新しいボタンがあるのでそれを押します。

スクリーンショット: F12のアクセシビリティーツリービューをオンにするボタン

ツリービューを表示すると、どういう名前とロールなのかを一覧でき、選択することでその要素にジャンプできます。

スクリーンショット: F12のアクセシビリティーツリービュー

Micorosoft Edge(プレビュー)の拡張について調べる、デバッグする方法

Created at: | Tag: Edge Chrome Extension JavaScript HTML

Micorosoft Edge(プレビュー)の拡張を作ってみるでは未公開の情報を元にノリと勢いでChrome拡張をEdge拡張にしてみましたが、さっくりとできたわけではなくAPIに関しては当然少し調査してから試しました。

その調査方法兼デバッグ方法についてせっかくなのでメモっておきます。もちろん将来のビルドでは手順が変わる可能性がかなり高いです。

まずはChromeが持っているpermissionをすべて列挙したマニフェストを持つ空の拡張を作ります。JavaScript不要です。

{
    "manifest_version": 2,
    "name": "Dummy Extension",
    "version": "1.0",
    "background": {
        "page": "background.html"
    },
    "permissions": [
        "activeTab",
        "alarms",
        /* 長いので省略 (https://gist.github.com/mayuki/5ae554c8e825f32921c7) */
        "webRequest",
        "webRequestBlocking"
    ]
}

バックグラウンドページはこんな感じでtitle要素だけ。

<!DOCTYPE html>
<!-- 名前は付けておいた方がいい -->
<title>Dummy Extension - BackgroundPage</title>

そしてACLを付けて、

icacls . /grant "*S-1-15-2-3624051433-2125758914-1423191267-1740899205-1073925389-3782572162-737981194":"(OI)(CI)(WDAC,WO,GE)"

Edgeに読み込ませます。

デバッグコンソールを開く

これで拡張は読み込まれましたがEdgeのデバッグする口がありません。Chromeなどでは拡張画面からいろいろ開けるのですがそういうインタフェースは見当たりません。

そこでF12開発者ツールをスタンドアローンで立ち上げます。実は結構前からF12開発者ツールは単体で起動できるようになっています。

単体で起動するにはC:\Windows\SysWOW64\F12にあるF12Chooser.exeを実行します。するとF12開発者ツールをどのインスタンスのEdgeにアタッチするか、という画面が表示されます。

F12Chooser

この画面でさっき作った"Dummy Extension - BackgroundPage"を選択します。すると指定したページ、つまり拡張のバックグラウンドページにアタッチされたF12開発者ツールが起動します。

F12開発者ツールが立ち上がる

そうしたらあとはコンソールでいろいろ試してみます。

windowオブジェクトにbrowserやchromeが生えている

chromeオブジェクトにはほとんど機能がないこと、pageActionの実装が中途半端なこと、webRequest/webNavigationがある(使えたとは言っていない)といったことが分かります。コンテキストメニューを足してみるのもここからできます。

ちなみにこのアタッチする手段を使うことで拡張をデバッグできます。…が、読み込み時のエラーのキャッチはできないのでなかなか厳しいです。そのあたりは将来正式に解放されるときに手段が整うのではないかと思います。