Support for extensions using XUL/XPCOM or the Add-on SDK was removed in Firefox 57, released November 2017. As there is no supported version of Firefox enabling these technologies, this page will be removed by December 2020.
Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.
Starting from Firefox 53, no new legacy add-ons will be accepted on addons.mozilla.org (AMO) for desktop Firefox and Firefox for Android.
Starting from Firefox 57, only extensions developed using WebExtensions APIs will be supported on Desktop Firefox and Firefox for Android.
Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to use WebExtensions APIs if they can. See the "Compatibility Milestones" document for more information.
A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.
One of Firefox's great advantages is its extreme extensibility. Extensions can do almost anything. There is a down side to this: poorly written extensions can have a severe impact on the browsing experience, including on the overall performance of Firefox itself. This article offers some best practices and suggestions that can not only improve the performance and speed of your extension, but also of Firefox itself.
Extensions are loaded and run whenever a new browser window opens. That means every time a window opens, your extension can have an impact on how long it takes the user to see the content they're trying to view. There are several things you can do to reduce the amount of time your extension delays the appearance of the user's desired content.
Don't load things during startup that are only needed if the user clicks a button, or if a given preference is enabled when it's not. If your extension has features that only work when the user has logged into a service, don't load the resources for those features until the user actually logs in.
You can create your own JavaScript code modules incorporating sets of features that are only needed under specific circumstances. This makes it easy to load chunks of your extension on the fly as needed, instead of loading everything all at once.
While JavaScript modules can be extremely useful, and provide significant performance benefits, they should be used wisely. Loading modules incurs a small cost, so breaking code up to an unnecessary degree can be counter-productive. Code should be modularized to the extent that doing so increases clarity, and loading of large or expensive chunks of code fragments can be significantly deferred.
Most extensions have a load event listener in the main overlay that runs their startup functions. Do as little as possible here. The browser window is blocked while your add-on's load handler runs, so the more it does, the slower Firefox will appear to the user.
If there is anything that can be done even a fraction of a second later, you can use an nsITimer
or the window.setTimeout()
method to schedule that work for later. Even a short delay can have a big impact.
Memory leaks require the garbage collector and the cycle collector to work harder, which can significantly degrade performance.
Zombie compartments are a particular kind of memory leak that you can detect with minimal effort. See the Zombie compartments page, especially the Proactive checking of add-ons section.
See Common causes of memory leaks in extensions for ways to avoid zombie compartments and other kinds of leaks.
As well as looking for these specific kinds of leaks, it's worth exercising your extension's functionality and checking the contents of about:memory for any excessive memory usage. For example, bug 719601 featured a "System Principal" JavaScript compartment containing 100s of MBs of memory, which is much larger than usual.
DOM mutation event listeners are extremely expensive and, once added to a document even briefly, significantly harm its performance. As mutation events are officially deprecated, and there are many alternatives, they should be avoided at all costs.
The XPCOMUtils JavaScript module provides two methods for lazily loading things:
defineLazyGetter()
defines a function on a specified object that acts as a getter which will be created the first time it's used. See examples.defineLazyServiceGetter()
defines a function on a specified object which acts as a getter for a service. The service isn't obtained until the first time it's used. Look through the source for examples.Many common services are already cached for you in Services.jsm.
This cannot be stressed enough: never do synchronous I/O on the main thread.
Any kind of I/O on the main thread, be it disk or network I/O, can cause serious UI responsiveness issues.
Avoid using mouse event listeners, including mouseover, mouseout, mouseenter, mouseexit, and especially mousemove. These events happen with high frequency, so their listeners can trivially create very high CPU overhead.
When these events cannot be avoided, computation during the listeners should be kept to a minimum and real work throttled. The listeners should be added to the most specific element possible, and removed when not immediately necessary.
Animated images are much more expensive than generally expected, especially when used in XUL tree
elements..
You can use a ChromeWorker
to execute long running tasks or do data processing.