TL;DR: Firefox used to have a great extension mechanism based on the XUL and XPCOM. This mechanism served us well for a long time. However, it came at an ever-growing cost in terms of maintenance for both Firefox developers and add-on developers. On one side, this growing cost progressively killed any effort to make Firefox secure, fast or to try new things. On the other side, this growing cost progressively killed the community of add-on developers. Eventually, after spending years trying to protect this old add-on mechanism, Mozilla made the hard choice of removing this extension mechanism and replacing this with the less powerful but much more maintainable WebExtensions API. Thanks to this choice, Firefox developers can once again make the necessary changes to improve security, stability or speed.
During the past few days, I’ve been chatting with Firefox users, trying to separate fact from rumor regarding the consequences of the August 2020 Mozilla layoffs. One of the topics that came back a few times was the removal of XUL-based add-ons during the move to Firefox Quantum. I was very surprised to see that, years after it happened, some community members still felt hurt by this choice.
And then, as someone pointed out on reddit, I realized that we still haven’t taken the time to explain in-depth why we had no choice but to remove XUL-based add-ons.
So, if you’re ready for a dive into some of the internals of add-ons and Gecko, I’d like to take this opportunity to try and give you a bit more detail.
For a very long time, Firefox was composed of a very small core on top of which everything was implemented as extensions. Many of these extensions were written in C++, others in JavaScript and many involved the XUL interface language and the XBL binding language. C++ and JavaScript code were connected thanks to a technology called XPCOM. Whenever an extension developer wished to customize Firefox, it was simple and extremely powerful, as the exact same building blocks used to power Firefox could be used to customize it.
This is how Session Restore (the technology that lets you resume Firefox where you left it the last time, even in case of crash) or the Find Bar were first implemented in Firefox, among other features. This is the technology that powers Firefox and Thunderbird. This is how tools such as Songbird (an open-source iTunes competitor) or Instantbird (a chat client) were developed. This is also how I customized Firefox to become an eBook reader a long time ago. And this is how thousands of Firefox add-ons were developed.
Many people call this extension mechanism “XUL-based Add-Ons”, or sometimes “XPCOM-based Add-Ons”, and I’ll use both terms in this blog entry, but I often think of this as the “Promiscuous Extension Mechanism”, for several reasons:
- very quickly, add-on developers realized that anything they did could break anything else in the system, including other add-ons and Firefox itself, and they often had no way to prevent this;
- similarly, anything Firefox developers did could break add-ons, and they often had no way to prevent this;
- also, some of the changes that Firefox needed to be as fast, as stable and as secure as possible were going to break most add-ons immediately, possibly all add-ons in the longer term;
- oh, and by the way, since add-ons could do everything, they could very easily do anything to the operating system, from stealing passwords to pretending to be your bank.
Note: Having read in comments that some users apparently do not care about security, let me add that being secure is a really, really important point for Mozilla and has been since the first day. Regardless of add-ons, not having security means that an exploit is eventually going to show up that will steal user’s passwords and use them to steal their bank accounts – and that exploit will get sold around and will soon show up everywhere. Firefox developers fight this threat daily by all sorts of means, including code reviews, defensive programming, crash scene investigations, several types of sandboxing, static analysis, memory-safe languages, … Consequently, for Mozilla, if a feature prevents us from achieving great security, we always pick security over features.
I’ll return to these points in more details later. For the moment, suffices to say that it had been clear to Firefox developers for a long time (at least since 2010) that this situation was untenable. So Mozilla came up with a backup plan called the Firefox Jetpack.
Firefox Jetpack was a very different manner of extending Firefox. It was much cleaner. It finally had a permissions mechanism (something that had been suggested even before Firefox was called Firefox and that was generally considered too hard to implement). Out of the box, add-ons could not break each other or Firefox (I seem to remember that it was still sometimes possible by exploiting the observer service, but you had to work hard at it), it made extensive use of async programming (which was great to achieve a feeling of high-performance) and thanks to the fact that it had a finite API, it could be tested, which meant that when Firefox developers broke add-ons, they knew about it immediately and could fix the breakages! That was several enormous steps forward. This came at the cost of a more limited API but in most cases, the tradeoff seemed worth it.
Unfortunately, it turned out that there was an unexpected incompatibility between the design of Jetpack and some of the major changes that were needed in Firefox. I’m not entirely clear about what this incompatibility was but this meant that we had to abandon Jetpack.
Instead, we introduced WebExtensions. Overall, WebExtensions had a similar objective as Jetpack-based add-ons, with a similarly restricted API and the added bonus that they could be made to work on both Chromium-based browsers and Firefox.
If you needed very advanced APIs, switching from the promiscuous extension mechanism to Jetpack or WebExtensions was not always possible, but for most extensions, the transition was simple – in my personal experience, it was even pleasant.
Firefox introduced WebExtensions in time for Firefox Quantum because this is when the promiscuous add-on model was scheduled to break.
At this stage, we’re done with the historical overview. I hope you’re ready for a more technical dive because that’s how I’m going to explain to you exactly which problems were solved as we switched from the promiscuous extension model to WebExtensions.
How it started
XPCOM, the Xross-Platform Component Object Model, is perhaps the feature of Firefox that can best be described as the core (for people who know Gecko in-depth, I’m counting XPConnect and the Cycle Collector as part of XPCOM), alongside SpiderMonkey, our JavaScript Virtual Machine.
XPCOM is a technology that lets you write code in two languages and have each other call the other. The code of Firefox is full of C++ calling JavaScript, JavaScript calling C++ and a long time ago, we had projects that added Python and .Net in the mix. This piece of machinery is extremely complicated because languages do not share the same definitions (what’s a 64-bit integer in JavaScript? what’s a JavaScript exception in C++?) or the same memory model (how do you handle a JavaScript object holding a reference to a C++ object that C++ might wish to delete
from memory?) or the same concurrency model (JavaScript workers share nothing while C++ threads share everything).
Gecko itself was originally designed as thousands of XPCOM components that could each be implemented in C++ or in JavaScript, tested individually, plugged, unplugged or replaced dynamically and it worked. In addition, the XPCOM architecture made for much cleaner C++ programming than was available at the time, worked on dozens of platforms, and let us combine the convenience of writing code in JavaScript and the raw speed permitted by C++.
To write a XPCOM component, you typically define an interface, then write the implementation in either C++ or JavaScript (or Rust, nowadays, and maybe soon Wasm). Some boilerplate is needed, but hey, it works.
When early Firefox developers decided to open the platform to extensions, XPCOM was immediately picked as the base technology for add-ons. Firefox just had to let add-on authors plug anywhere within the code and they would have tremendous power at their disposal.
And add-on developers (including myself) certainly did and had lots