Initialization and Cleanup

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, WebExtensions will be the only supported extension type. Desktop Firefox and Firefox for Android will not load other extension types.

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 WebExtensions 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.

Android add-ons don't have to be restartless, but with Firefox for Android you can't use XUL overlays to create your user interface, so there's much less incentive to write overlay-based add-ons.

Restartless add-ons must contain a file named bootstrap.js to handle initialization and cleanup. In this guide we'll present a template implementation of bootstrap.js that simplifies initialization and cleanup tasks such as adding and removing the add-on's user interface.

To read more about restartless extensions (also known as bootstrapped extensions), refer to the bootstrapped extensions documentation.

If you are using add-on SDK, to read about Listening for Load and Unload.

bootstrap.js

The bootstrap.js file must contain implementations of two functions: startup() and shutdown().

startup()

startup()is called by the host application when the add-on is installed or enabled, or when the host application is launched.

Inside startup() the add-on should put all the code needed to initialize the add-on, including any code to construct persistent user interface elements like menu items.

shutdown()

shutdown() is called by the host application when the add-on is uninstalled or disabled, or when the host application shuts down. Inside shutdown() the add-on needs to undo any persistent changes it's made.

Template code

Here's a version of bootstrap.js that implements startup() and shutdown():

const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import('resource://gre/modules/Services.jsm');
function loadIntoWindow(window) {
  if (!window)
    return;
  // Add any persistent UI elements
  // Perform any other initialization
}
function unloadFromWindow(window) {
  if (!window)
    return;
  // Remove any persistent UI elements
  // Perform any other cleanup
}
var windowListener = {
  onOpenWindow: function(aWindow) {
    // Wait for the window to finish loading
    let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
    domWindow.addEventListener("UIReady", function onLoad() {
      domWindow.removeEventListener("UIReady", onLoad, false);
      loadIntoWindow(domWindow);
    }, false);
  },
  onCloseWindow: function(aWindow) {},
  onWindowTitleChange: function(aWindow, aTitle) {}
};
function startup(aData, aReason) {
  // Load into any existing windows
  let windows = Services.wm.getEnumerator("navigator:browser");
  while (windows.hasMoreElements()) {
    let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
    loadIntoWindow(domWindow);
  }
  // Load into any new windows
  Services.wm.addListener(windowListener);
}
function shutdown(aData, aReason) {
  // When the application is shutting down we normally don't have to clean
  // up any UI changes made
  if (aReason == APP_SHUTDOWN)
    return;
  // Stop listening for new windows
  Services.wm.removeListener(windowListener);
  // Unload from any existing windows
  let windows = Services.wm.getEnumerator("navigator:browser");
  while (windows.hasMoreElements()) {
    let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
    unloadFromWindow(domWindow);
  }
}
function install(aData, aReason) {}
function uninstall(aData, aReason) {}

loadIntoWindow()

To use this template you just implement loadIntoWindow() to initialize your add-on. You can use the window argument to access the NativeWindow and BrowserApp objects, which you can use to add user interface elements and interact with the browser.

For example, the loadIntoWindow() implementation here initializes an add-on that remembers the URL for the last closed tab, and adds a menu item to reload that tab:

var nativeWindow;
var browserApp;
var menuId;
var lastURI;
function rememberURI(event) {
  let browser = event.target;
  lastURI = browser.currentURI.spec;
}
function reopenTab() {
  if (lastURI)
    browserApp.addTab(lastURI);
}
function loadIntoWindow(window) {
  if (!window)
    return;
  nativeWindow = window.NativeWindow;
  browserApp = window.BrowserApp;
  menuId = window.NativeWindow.menu.add("Reopen Tab", null, reopenTab);
  browserApp.deck.addEventListener("TabClose", rememberURI, false);
}

unloadFromWindow()

Conversely, you implement unloadFromWindow() to remove any UI elements and perform any other cleanup. To clean up the example add-on above we could implement unloadFromWindow() as follows:

function unloadFromWindow(window) {
  if (!window)
    return;
  nativeWindow.menu.remove(menuId);
  browserApp.deck.removeEventListener("TabClose", rememberURI, false);
}

Document Tags and Contributors

 Contributors to this page: rebloor, andrewtruongmoz, wbamberg, backy0175, leibovic, Maroosko, kmaglione
 Last updated by: rebloor,