Restartless Add-ons – More Resources

After playing around with bootstrap (restartless) add-ons a bit more, I came to the point where I needed some extra resources in the add-on. For images, I could have stuck with the data: URI approach I mentioned previously, but I also wanted to add an options UI for my add-on. Turns out it was pretty simple. Thanks to Vlad for getting the ball rolling.

The trick I am using now is to programmatically add a resource: alias for my add-on. A resource: alias creates a handy way for you to create URIs pointing to resources, like scripts and images, in your add-on bundle. It’s pretty simple to add a resource: URI pointing to the add-on’s root folder or XPI bundle. Here is the code snippet taken from my bootstrap.js file:


function startup(aData, aReason) {
  let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
  let alias = Services.io.newFileURI(aData.installPath);
  if (!aData.installPath.isDirectory())
    alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
  resource.setSubstitution("myaddonpackage", alias);
  ...
}

function shutdown(aData, aReason) {
  if (aReason == APP_SHUTDOWN) return;

  let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
  resource.setSubstitution("myaddonpackage", null);
  ...

The isDirectory check is needed because it is possible for add-ons to be installed in folders or XPI bundles, which require the jar: URI syntax. The code adds a resource alias, after which you can use URIs like this:


resource://myaddonpackage/images/someimage.png
resource://myaddonpackage/content/somescript.js

In these examples, images and content are folders inside your add-on bundle. Now you can add URI-based resources to your install.rdf like this:


  ...
  resource://myaddonpackage/content/icon.png
  resource://myaddonpackage/content/options.xul
  ...

Yes, the em:optionsURL works just fine for providing an options UI in your add-on. I hope this tip gives you more help converting your traditional add-on to a restartless add-on.

Updated: I added the removal of the resource: alias on shutdown based on feedback from Nils in comments. Check out his link to some great bootstrap add-on information too. The part about stale caches after an add-on update presents a painful problem. Waldimir has also previously posted about the limitations of bootstrapped add-ons.

16 Replies to “Restartless Add-ons – More Resources”

  1. Your code isn’t correct unfortunately.
    The XUL/XPC cache will be used, and hence when you update the addon in session, the resources will return stale cache entries from your previous addon version.
    Please see e.g. the section about js modules, which should apply to XUL as well.
    http://maglione-k.users.sourceforge.net/bootstrapped.xhtml
    You must register your resource substitution under different package names for each version.
    Memory leaks and growing on-disk xul cache still included… Jetpack basically does the same, btw.

    Don’t forget to close your xul windows (your prefwindow) on |shutdown|.

    Registering chrome would have the same limitations + you cannot unregister the chrome again.

  2. @Nils – When you mention caching issues related to XUL, by what means is the XUL getting cached? In Fennec, for example, we load the options UI by doing an XHR GET on the XUL (resource://foo/bar.xul in this case). Then we append the DOM nodes from the XHR.responseXML to the main document DOM. I don’t think the XUL cache comes into play in that scenario. We do the same thing for importDialog:

    http://mxr.mozilla.org/mobile-browser/source/chrome/content/bindings/extensions.xml#101
    http://mxr.mozilla.org/mobile-browser/source/chrome/content/browser.js#2305

    In these cases, removing the resource: alias when shutting down and adding it back when the new version updates might be fine.

  3. I’m getting the following error when I try to do this:
    Warning: WARN addons.xpi: Exception running bootstrap method startup on jid0-QVXoZN2I0qxeM6fXf1FoJU0cO7I@jetpack: ReferenceError: Services is not defined
    Source File: resource://gre/modules/XPIProvider.jsm -> file:///C:/Users/admin/AppData/Roaming/Mozilla/Firefox/Profiles/zwexmy17.x64prof/extensions/jid0-QVXoZN2I0qxeM6fXf1FoJU0cO7I@jetpack/bootstrap.js
    Line: 142

  4. Followup to my previous comment for anyone who cares (aside from mfinkle, who helped me with this on IRC):

    You need to import Services.jsm in bootstrap.js to solve that error.

    Beyond that, apparently you can’t use XUL in this with Firefox 4,triggers the Disabled Remote XUL error page when you try to load the resource (eg, click the Options button for the addon), as it doesn’t have Fennec’s XHR GET behavior to work around this.

    I filed https://bugzilla.mozilla.org/show_bug.cgi?id=628089 in the hopes that this can be worked around (or more likely explained away and marked invalid).

  5. Thanks for writing this up; this removes one of the major roadblocks I was hitting in trying to restartless-ify some of my extensions.

  6. When I try statements like:
    Components.utils.import(“resource://firebug/firebug-trace-service.js”);

    in bootstrap.js I get exceptions. Is this supposed to work?

    jjb

  7. I use Components.utils.import(“resource://gre/modules/Services.jsm”); without any trouble. I have seen Components.utils.import(“resource://gre/modules/XPCOMUtils.jsm”); used too.

    What kind of exceptions? I assume the bootstrapped add-on using Firebug and Firebug is already installed?

  8. Yes, I can load Services.jsm. I can’t load any of mine,even ones that I load in other JS code and which load into the browser.

    Error: bootstrap 0 ERROR [Exception… “Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIXPCComponents_Utils.import]” nsresult: “0x80070057 (NS_ERROR_ILLEGAL_VALUE)” location: “JS frame :: resource://gre/modules/XPIProvider.jsm -> file:///C:/jjb/eclipse/fbugWorkspace/fbug/extensions/moduleloader/branches/moduleloader0.1/bootstrap.js :: :: line 6” data: no]
    Source File: resource://gre/modules/XPIProvider.jsm -> file:///C:/jjb/eclipse/fbugWorkspace/fbug/extensions/moduleloader/branches/moduleloader0.1/bootstrap.js
    Line: 11

  9. I followed your method and could successfully load my images provided they are placed as is in my xpi.

    Is it possible to create the resource: alias if the image and js files are packaged in a jar file within my extension xpi?

    This is my directory structure:
    SampleExtension.xpi
    Install.rdf
    chrome.manifest
    bootstrap.js
    chrome\tb.jar

    How will I go about creating the resource: alias to access my images and javascript files located within tb.jar?

Comments are closed.