WebExtensions — Cross-Browser kompatible Erweiterungen

Ob Adblocker, Video Downloader oder Entwicklungstool — Browsererweiterungen sind überaus beliebt. Mit WebExtensions gibt es erstmals die Bestrebung der wichtigsten Browserhersteller hin zu einer gemeinsamen Schnittstelle. Was verspricht die kompatible API und wo sind die Nachteile?

Am 14. November 2017 wird Firefox 57 alias Firefox Quantum veröffentlicht. Ab dann werden nur noch Add-ons unterstützt, welche die WebExtensions API verwenden. Dieser Schritt ist radikal, zumal Hunderte von Add-ons umgeschrieben werden müssen — natürlich nicht nur zur allgemeinen Begeisterung. Allen Nachteilen zum Trotz wird dies aber erstmals ermöglichen, Browsererweiterungen (zumindest mit minimalen Anpassungen) für alle gängigen Browser zu entwickeln: Mozilla Firefox, Google Chrome, Microsoft Edge, Opera.

Was sind WebExtensions?

Mozilla’s WebExtension API ist grösstenteils kompatibel mit der extension API von Google Chrome, wobei auch Opera und sogar Microsoft Edge Teile dieser API unterstützen. Formalisiert wird die API durch die W3C Draft Community Group «Browser Extensions».

Ziel der Spezifikation ist:

  • sowohl eine API und als auch Browserverhalten zu definieren, welche die Entwicklung von browserunabhängigen Erweiterungen erlauben
  • ein Paketierungsformat zu definieren, das für diese Erweiterungen verwendet werden kann
  • die Entwicklung von Erweiterungen mit Hilfe von Web Technologien zu ermöglichen (primär mit JavaScript und dessen Web APIs)

Dabei werden Schnittstellen in folgenden Bereichen festgelegt:

  • Veränderung von Seiteninhalten
  • Erweiterung von Browser UI
  • Veränderung von Netzwerkanfragen
  • Datentransfer zwischen Extensions
  • Datentransfer zwischen Webseiten und Extensions
  • Zugriff auf Benutzereinstellungen (z.B. Cookies)

Die Vorteile und Nachteile

In einem Artikel über die Migration der «Tree Style Tab» WebExtension, beschreibt der Entwickler Yuki Hiroshi, die Vorteile von WebExtensions:

Basically Firefox is an application like webapp, built from XML + CSS + JavaScript running on the Gecko rendering engine. Inherently a legacy addon is just a „monkey patch“, injecting arbitally scripts into the namespace of Firefox’s scripts.

On the other hand, an WebExtensions-based addon is a small software executed in a sandboxed namespace, and it communicates with Firefox both way via WebExtensions APIs.

Links, die Architektur bisheriger XUL/XPCOM basierter Add-ons, rechts Erweiterungen mit der neuen WebExtensions API. Die WebExtensions Architektur ist erkennbar übersichtlicher, die Erweiterungen werden in einem isolierten Bereich ausgeführt und kommunizieren über die klar definierte WebExtension API mit dem Browser.

Mozilla umschreibt die Nutzen wie folgt (Quelle):

  • Einfachere Portierung von Erweiterungen zu/von anderen Browsern
  • Einfachere Reviews von Erweiterungen (insbesondere für addons.mozilla.org)
  • Kompatibel mit Multiprozess-Firefox
  • Kleinere Wahrscheinlichkeit, dass Änderungen an Firefox‘ internem Code, Erweiterungen betreffen
  • Die WebExtension API ist einfacher zu verwenden als die existierenden XPCOM/XUL APIs
  • Die WebExtension API hält akzeptierbare Sicherheits- und Datenschutzstandards ein

Auf der anderen Seite sind die Erweiterungsmöglichkeiten mit der WebExtensions API geringer. Nicht alle Funktionen, welche von bisherigen Add-ons angeboten werden konnten, sind möglich umzusetzen. Zudem funktionieren noch nicht alle Features stabil und manche werden erst entwickelt.

Die Inkompatibilitäten

Obwohl das Ideal der Interoperabilität verlockend tönt, sieht die Realität etwas anders aus.

Während die Spezifikation und die meisten Browser den browser.* Namespace, sowie Promises für asynchrone Rückgabewerte verwenden:

browser.cookies.set({ url: 'https://developer.mozilla.org/' })
  .then(c => console.log(c), e => console.error(e));

…verwendet Chrome den chrome.* Namespace und Callbacks:

chrome.cookies.set({ url: 'https://developer.mozilla.org/' },
  (c) => {
    if (chrome.extension.lastError) {
      console.error(chrome.extension.lastError);
    } else {
      console.log(c)
    });

Zur erleichterten Portierung von (Chrome) Extensions unterstützt Firefox beide Varianten. Ausserdem gibt es ein Polyfill, welches es ermöglicht den browser.* Namespace mit Promises im Chrome zu verwenden, was die Portierung von Firefox Extensions nach Chrome vereinfacht.

Die obigen Beispiele sowie weitere Unterschiede sind auf MDN im Artikel Chrome incompatibilities detailliert beschrieben.

Der Usecase: «Tabmarks»

Im Rahmen eines Free/Open Source Puzzle Piece Projects (FOSPPP) habe ich mit der Implementierung einer Alternative meines geliebten (jedoch eingestellten) Tab Groups Add-ons begonnen. Tabmarks ermöglicht den Wechsel zwischen verschiedenen Gruppen von Tabs, zum Beispiel bei der Arbeit an unterschiedlichen Projekten. Die Gruppen werden dabei als Bookmarks persistiert.

https://github.com/hupf/tabmarks

Das UI besteht hauptsächlich aus einer Browser Action mit Popup und einer Options Page, welche im manifest.json eingebunden werden.

In einem Background script werden aufgrund der Tab events diese als Lesezeichen mit Hilfe der Bookmarks API geschrieben.

Zu berücksichtigen ist, dass je nach Kontext (z.B. Background script oder Content script) nicht alle Funktionen zur Verfügung stehen. Um zwischen den verschiedenen Kontexten zu kommunizieren, kann die Messaging API verwendet werden. Diese funktioniert ähnlich, wie die Channel Messaging API wie man sie z.B. für die Kommunikation mit Web Workern kennt.

Beta Tester und Contributions sind herzlich willkommen!

Das Fazit

Mozillas Entscheid voll auf die WebExtension API zu setzen ist ziemlich mutig und wird viele Add-on Entwickler und User vergraulen. Ich denke aber, dass es längerfristig absolut richtig ist, auf die schlichte Erweiterungsarchitektur zu setzen. Auch die einfachere Portierung von Extensions ist insbesondere für Entwicklungstools wie Angular Augury, die React Developer Tools oder den Ember Inspector interessant.

Besonders zu Erwähnen ist die Browser Extensions Seite auf MDN. Dies ein guter Startpunkt, um mit der Entwicklung einer eigenen Extension zu beginnen.

Wer ausserdem wissen möchte, wie es um die Migration seiner Lieblingserweiterung steht, kann dies auf der Seite Are we WebExtensions yet? verfolgen.

Happy browsing!

Foto: «Tangled cables on Modular synthesizer» von Kazuhisa OTSUBO

Kommentare sind geschlossen.