How a Firefox Extension Works

Basic anatomy:

extensions/
  yourextension@example.com/
    install.rdf
    chrome.manifest
    chrome/
      content/
        overlay.xul
        overlay.js
      skin/
        overlay.css
        icon.png
  1. When Firefox starts up, it looks in your profile folder for an extensions folder, which contains a folder called yourextension@example.com.
  2. In there it finds a file called install.rdf, which contains an id element that matches the name of the folder (yourextension@example.com), and some other metadata about the extension.
  3. There's also a file called chrome.manifest, which maps the files in your extension to chrome: urls and lists which overlays and stylesheets to load.
  4. This chrome.manifest says that the XUL file chrome/content/overlay.xul (accessed at chrome://yourextension/content/overlay.xul) overlays the browser's chrome://browser/content/browser.xul.
  5. The overlay file is loaded and mapped onto the source XUL file: if the id attribute of any element in the overlay matches the id attribute of an element in the destination XUL, everything within the source element is inserted into the destination element.
  6. This chrome.manifest also says that the CSS file chrome/skin/overlay.css (accessed at chrome://yourextension/skin/overlay.css) should be attached to the browser's chrome://global/content/customizeToolbar.xul.
  7. The overlay contains a script element which loads a Javascript file, chrome/content/overlay.js, which sets up the functions for your extension.
  8. There's an oncommand attribute on the toolbar button, so when it's clicked your extension's run function will run.

Here are some examples of the files described above:

install.rdf (no idea why this is RDF rather than single-namespaced XML):


<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.mozilla.org/2004/em-rdf#">
  <rdf:Description about="urn:mozilla:install-manifest">
  
    <id>yourextension@example.com</id>
    <version>0.1</version>
    <name>Your Extension</name>
    <description>Description of your extension</description>
    <iconURL>chrome://yourextension/skin/icon.png</iconURL>
	     
    <!-- Firefox --> 
    <targetApplication>
      <rdf:Description>
        <id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</id>
        <minVersion>2.0</minVersion>
        <maxVersion>3.0.*</maxVersion>
      </rdf:Description>
    </targetApplication>
   	  
  </rdf:Description>      
</rdf:RDF>

chrome.manifest:


# chrome path     # chrome root             # relative path
content           yourextension             chrome/content/
skin              yourextension classic     chrome/skin/
# type  # destination                                 # source
overlay chrome://browser/content/browser.xul          chrome://yourextension/content/overlay.xul
style   chrome://global/content/customizeToolbar.xul  chrome://yourextension/skin/overlay.css

overlay.xul:


<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="yourextension-overlay">
  <script type="application/x-javascript" src="chrome://yourextension/content/overlay.js"/>
  <toolbarpalette id="BrowserToolbarPalette">
      <toolbarbutton id="yourextension-toolbar-button" class="toolbarbutton-1" oncommand="YourExtension.run()"/>
  </toolbarpalette>
</overlay>

overlay.css:


@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
#yourextension-toolbar-button {
	list-style-image: url(chrome://yourextension/skin/buttons.png);
	-moz-image-region: rect(0 33px 24px 0);
}
#yourextension-toolbar-button:hover {
	-moz-image-region: rect(0 66px 24px 33px);
}
toolbar[iconsize="small"] #yourextension-toolbar-button {
	-moz-image-region: rect(0 88px 16px 66px);
}
toolbar[iconsize="small"] #yourextension-toolbar-button:hover {
	-moz-image-region: rect(0 110px 16px 88px);
}

overlay.js:


var YourExtension = {
  run: function(){
    // do something
  },
}

See this del.icio.us posting extension for a working example. It's just a zip file, so you can open it and look inside.

Here's a bash script that might be useful for compiling the extension into an XPI file for distribution:


APP_NAME=yourextension # edit this
rm "$APP_NAME.xpi"
# generate the XPI by zipping everything in the current directory, excluding .DS_Store files
zip -r "$APP_NAME.xpi" `find . -path -prune -o -type f -print | grep -v 'build.sh' | grep -v 'DS_Store'`