Tokyo WebExtensions Meetup #3 - 2018-11-02 - ククログ

ククログ

株式会社クリアコード > ククログ > Tokyo WebExtensions Meetup #3

Tokyo WebExtensions Meetup #3

クリアコードでFirefoxやThunderbirdの法人サポートに従事している結城です。

去る10月30日、御茶ノ水・デジタルハリウッド大学院の1教室をお借りして、Firefox(やその他様々なブラウザ)の拡張機能に関心を持つ人達の交流イベントであるTokyo WebExtensions Meetup #3が開かれました。日にちが日にちだったため、会場にはハロウィン的な仮装のための小道具が用意されていたり、Mozillaのスポンサードにより提供されたピザがハロウィン仕様(黒い生地にオレンジのチーズ)だったりと、ささやかながらお祭り気分を味わいつつの進行でした。

筆者も発表者の一人として参加しましたので、このエントリでは発表の内容の概要をお伝えします。

発表1:タブの複数選択APIのつかいかた

最初は筆者による、Firefox 63以降で使える「タブの複数選択機能」に関する発表です。発表資料のスライドはQiitaにて公開中です。また、公開に際しては口頭で発表した詳細な説明も書き加えてあります。

タブの複数選択機能はFirefox 64からの新機能(予定)ですが、基本的な機能はFirefox 63の時点でも既に使える状態になっています。about:configを開いてbrowser.tabs.multiselectを検索し、値をtrueに設定すれば、機能が使えるようになります1

筆者は予てよりマルチプルタブハンドラというアドオンを個人的に開発しています。これはFirefox 56以前においては、Firefoxのタブにまさにそのような性質を加える物でした。しかしWebExtensionsではFirefox自体のタブの振る舞いを変えることはAPIの制約上できません。そのため、WebExtensions移行に際しては、このアドオンの内部でタブの選択状態を管理し、browser.runtime.sendMessage()による明示的なAPI呼び出しに対してその情報を返すという形で、他のアドオンに対して「タブの複数選択」相当の事ができるようにするAPIプロバイダのように振る舞う2アドオンとして再出発したという経緯があります。

今回、Firefox本体にタブの複数選択機能が入り、同時にその機能を呼び出すためのWebExtensions APIが追加された事によって、アドオン同士がお互いの存在を知らないまま暗黙的に連携しあえる場面がまた一つ増えたと言う事ができます。また、次のリリースとなるFirefox 64ではタブやブックマークのコンテキストメニューに機能を追加するアドオン同士の暗黙的な連携も可能になる予定です。このように暗黙的な連携が図られる場面が増えることで、各アドオンが単独で動作するだけの状態に比べて、機能の有用さは何倍にも高まります。

XUL時代のアドオンの有用性を支えていた要素の一つであったその性質が、WebExtensionsへの移行で大きく失われてしまった、という体験をした身としては、今後もこういった形でアドオン同士の暗黙的な連携が促進されるような改良が続く事を切に期待するばかりです。

発表2:Webページ中のテキストの動的な置換

2番目の発表は、あきみね氏による「Webページ中に現れる特定の文字列を、任意の文字列に強制的に置き換える」アドオンの紹介でした。

このアドオンでは、コンテントスクリプトでDOMツリーを走査して個々のテキストノードを編集するという基本の処理に加えて、MutationObserverを使って動的に挿入されるテキストも編集するという工夫により、Facebookなどのような「スクロールに応じてページの内容が次々と継ぎ足されていく」形式のWebサービスにも対応できるようにした事が特長であるという紹介がありました。

ただ、Webページ中の全テキストノードを走査するという事は、それだけ処理に時間がかかるという事でもあります。そのため、処理に時間がかかるようなページのための対策には悩まれているそうです。

これについて、browser.findのAPIを使用すればより効率よく指定の文字列の置き換えができるのではないかという情報提供を筆者から行いましたが、このAPIは今のところFirefoxが対応しているのみのため、Chromeの使用を考えると残念ながら使う事はできないとの事でした3

ブラウザを問わずに行えそうな別方向での最適化としては、worker-domを活用するという方法も考えられます。これはDOMツリーを丸ごとWorker上に再現して、ボトルネックになりがちなDOMの操作を別スレッドに逃がしてしまうという試みです。一般的なWebページの処理にどこまで使えるかというのは未知数ですが、もし使えるのであれば、Webページの内容と密接に関わる種類のアドオンの大幅な高速化が可能になるかも知れず、興味深い技術です。

発表3:WebExtensionsとテスト

3番目の発表は、Firefox上でvim風の操作体系を実現するアドオンの一つであるVim Vixenの作者のUeoka氏による、アドオンの自動テストの実現方法についてのお話でした。 こちらは発表資料がSpeakerDeckにて公開されています

Vim Vixenの開発にあたっては一般的なJavaScriptでのアプリケーション開発のノウハウが活かされていて、自動テストもKarmaMochaWebExtensionsの各種APIをモックするライブラリを組み合わせて大量のユニットテストを行っているそうです。また、自動テストやESLintによる検証をCircleCIで継続的に実行されているとの事でした。

プロダクト自体を自動テストが容易になるように設計するという事は、純粋なロジック部分と外部要因になる部分とをなるべく切り離すという事です。例えばタブを指定の条件でフィルタリングしてリストアップするためのフィルター処理自体browser.tabsに一切触れておらず、その自動テストも純粋なロジックのみに特化して検証できています。Vim Vixenでは全体をこのように設計し、テストをなるべくしやすいようにされているとのことでした。

発表の後半はE2Eテスト(ユーザーの実操作に近いテスト)にフォーカスした話でした。Vim Vixenでは163あるE2Eテスト項目のうち現時点で45件を自動化できているとのことですが、その実現にあたっては、ambassadorと名付けられたテスト実行専用のアドオンを使われているそうです。WebExtensionsベースのアドオンの開発・テスト支援ツールであるweb-extの改造版を用いてVim Vixenとambassadorを同時に読み込ませ、テストケース内で指示された操作をambassadorで行ってVim Vixenの動作をテストしているとの事でした。

ユーザーの入力を再現するような箇所は非同期処理が多くなりがちですが、スクロール操作のE2Eテストなどを見ると分かるように、非同期処理が絡む自動テストもawaitを使うとシーケンシャルに記述できます。async/awaitはテストの実装にも有用という事を示す一例と言えるでしょう。

Vim Vixenはコンテンツ領域内にUIを挿入する設計のためこのようなテスト手法が可能となっているそうですが、言い換えると、サイドバーやツールバー上のポップアップ内でUIを提供するアドオンについては、このアプローチでのテストは行えないという事でもあります。Ueoka氏自身も、より広い範囲のE2Eテストを自動化する方法について試行錯誤を続けられているそうです。

アドオンの自動テストについては、Firefox本体におけるWebExtensions APIそのものの自動テストの実装方法が参考になりそうな所ではあるのですが、Firefox内のWebExtensions APIのテスト群は専用のテストランナー上で専用のユーティリティを使って実行する形を取っており、しかもその内容はFirefoxの名前空間上で動作するという、現状のFirefoxの実装に強く依存した形式となっています。web-extやその後継ツールには、Firefox本体の内部事情に詳しくなくても同等の事ができるような自動テスト支援の仕組みを提供してくれる事が期待されます。

ambassadorや実際の自動テストも含めて、この発表の中で紹介された要素はすべてVim Vixenのリポジトリで公開されています。拡張機能の自動テストに関心がある方は必見ですね。

11月8日追記:発表をされたUeokaさんご自身による発表内容の解説記事も併せてご覧下さい。

発表4:開発ツールを拡張しよう!

最後の発表は、Mozillaで主にJavaScriptエンジンの開発を担当されているarai氏による、Webページのソースを任意の内容で置き換えるDITMというアドオンの紹介でした。

DITMとは「Developer In The Middle」の略ですが、これは「Man In The Middle Attack(中間者攻撃)」という攻撃手法をもじった物です。

MITM攻撃では、ユーザーが操作するクライアントとWebサーバの間に何らかの方法で中継者が入り込み、ユーザーが送るリクエストの内容を書き換えてWebサーバーに送ったり、Webサーバーから返された内容を書き換えてクライアントに送ったりすることで、ユーザーが入力したパスワードやクレジットカード番号などの機密情報を盗み出したり、ユーザーを望ましくない行動に誘導したりといった事が行われます。昨今のいわゆる「常時SSL化」は、このような攻撃を防ぐ事を目的の1つとしています。

このようにMITM攻撃を防ぐ事のできるSSL(TLS)ですが、アドオンの権限ではTLSで通信して取得した後の内容を任意の物に置き換える事ができます4。これを応用して、Webサーバー上のファイルを実際に編集せず手元で書き換えてデバッグするという事を可能にするのが、DITMです。

発表では、「Minifyされたライブラリのソースを一旦スクラッチパッドに貼り付けてpretty printし、それを元のファイルの代わりに使うようにDITMで設定した上で、任意のコードをそこに追加して実行してみる」というデモが行われていました5。「Firefoxでだけ動かないページ」に遭遇した時の原因調査などに活用できるかもしれません。

DITMの主要な機能はbrowser.webRequest.filterResponseData()によって実現されているため、Web上のコンテンツをクライアント側で置き換える6実装の例と言う事ができます。また、開発ツールに独自のタブを追加する例としても参考になるでしょう。

次回以降のイベントについて

メインの発表が終わった後は、このイベント自体の今後の方向性についてヒアリングも兼ねたディスカッションが行われました。以下はその中で聞かれた意見です。

  • 一般的なセミナー形式ではなくワークショップをやりたい。

    • アドオンを作ってみたい、という初心者向けの内容はどうか。

    • 既存のアドオンの不具合の修正や機能追加のプルリクエスト、WebExtensionsに移行できていないアドオンの移行をやってみるのはどうか。

    • 日本語ロケールが無いアドオンを翻訳してプルリクエストするのはどうか。

    • Firefox本体に対するWebExtensionsの新しいAPIの提案や、実装が行われないまま停止しているAPI案へのパッチの提供など、やや高度な事に挑戦してみるのはどうか。

    • モブプログラミング形式(手を動かす人一人に対し周囲に複数人が集まって意見を出し合う形式)にしてはどうか。

  • 温泉旅館などでハッカソンのように泊まりがけてディープな事をやってみたい。

  • セミナー形式のイベントにニーズが無いわけではない。今回の発表も刺激的な内容だった。

ひとまず、次回開催は1月下旬から2月上旬頃を目標として、どのようなイベントが望まれているかのアンケートなどを近日中にMozilla Japan コミュニティのSlackで行う事を予定しています。次回の参加を検討されている方は、自分が参加したいと思えるイベントにしていく機会として、是非Slack上で意見を表明してみて下さい。

また、「OSSであるFirefoxやアドオンにフィードバックしてみたいが、やり方が分からなかったり、恐怖感があったりして、一人でやるのは尻込みしてしまう」という人向けに、Firefox関係に限らず広くOSS一般を対象にしたOSS Gateという取り組みも行っています。こちらはワークショップが定期的に開催されていますので、開催予定のイベント一覧から、参加しやすいエリア・日次のワークショップを探してビギナーとして参加してみてはいかがでしょうか。

まとめ

以上、Tokyo WebExtensions Meetup #3で行われた発表やディスカッションの内容をご紹介しました。

  1. なお、タブの複数選択機能はChromeには遅くとも2013年頃の時点で既に実装されていた模様です。

  2. とはいえ実際には、大多数の他のアドオンはこのアドオンの存在自体を知らないために、明示的な連携が図られる事はほぼ無く、「アドオン同士の連携」といってもほとんど絵に描いた餅に過ぎないという状態が長く続いていました。

  3. 同様の事をクロスブラウザで行う物ための技術としては、かつてW3Cで提案されていたRangeFinder APIという仕様もありますが、こちらは現在の所実装しているブラウザは存在しません。

  4. そのため、怪しいアドオンを不用意にインストールするのは非常に危険な事と言えます。

  5. Minifyやコンパイルされたコードに対するデバッグ方法としては、変換前のソースとの対応表を提供するSource Mapという技術もあります。Source Mapが提供されていない場合でもそれと同様の事を行えるというのが、DITMの利点の一つという事になります。

  6. あきみね氏の発表はDOMツリーが構築された後の置き換えなのに対し、arai氏のDITMはDOMとして解釈されるより前の時点での置き換えという違いがあります。