Skip to content

Instantly share code, notes, and snippets.

@Noitidart
Last active July 22, 2018 03:30
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save Noitidart/9045387 to your computer and use it in GitHub Desktop.
Save Noitidart/9045387 to your computer and use it in GitHub Desktop.
ff-addon-template: Template for how to create a JSM module.
const {utils: Cu} = Components;
const chromeModulesPath = 'chrome://bootstrap-jsm/content/';
Cu.import('resource://gre/modules/Services.jsm');
//Cu.import(chromeModulesPath + '/helloWorld.jsm'); //we CANNOT import it here we must do it in startup otherwise we get this error: "WARN addons.xpi: Error loading bootstrap.js for Bootstrap-JSM@jetpack: [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 -> jar:file:///C:/Documents%20and%20Settings/blah%20blah/Application%20Data/Mozilla/Firefox/Profiles/de83bb0q.default/extensions/Bootstrap-JSM@jetpack.xpi!/bootstrap.js :: <TOP_LEVEL> :: line 3" data: no]"
function startup(aData, aReason) {
Cu.import(chromeModulesPath + '/helloWorld.jsm'); //startup is the earliest we can import it
//BEGIN EXAMPLE USAGE
var rWin = Services.wm.getMostRecentWindow(null);
rWin.alert('foo = ' + foo);
rWin.alert('bar = ' + bar);
rWin.alert('bar.size = ' + bar.size);
rWin.alert('bar.theDummy = ' + bar.theDummy);
rWin.alert('bar.theLastVar = ' + bar.theLastVar);
//rWin.alert('dummy = ' + dummy); //dummy was not exported so it will throw this error: "WARN addons.xpi: Exception running bootstrap method startup on Bootstrap-JSM@jetpack: ReferenceError: dummy is not defined (resource://gre/modules/XPIProvider.jsm -> jar:file:///C:/Documents%20and%20Settings/blah%20blah/Application%20Data/Mozilla/Firefox/Profiles/de83bb0q.default/extensions/Bootstrap-JSM@jetpack.xpi!/bootstrap.js:16)"
//END EXAMPLE
}
function shutdown(aData, aReason) {
if (aReason == APP_SHUTDOWN) return;
Cu.unload(chromeModulesPath + '/helloWorld.jsm');
//we get rid of it here, of course on shutdown of our
//addon it will be unloaded, however
//if helloWorld.jsm was imported in another privelaged scope it will
//persist there, until restart of browser.
//after running unload however, all instances of helloWorld.jsm can now be deleted? (im not sure about this last line)
}
function install() {}
function uninstall() {}
/* //do this if want to make it a resource uri instead of a chrome (chrome://bootstrap-jsm/content/hellowWorld.jsm)
// Import Services.jsm unless in a scope where it's already been imported
Components.utils.import('resource://gre/modules/Services.jsm');
var resProt = Services.io.getProtocolHandler('resource')
.QueryInterface(Components.interfaces.nsIResProtocolHandler);
var aliasFile = Components.classes['@mozilla.org/file/local;1']
.createInstance(Components.interfaces.nsILocalFile);
aliasFile.initWithPath('/some/absolute/path');
var aliasURI = Services.io.newFileURI(aliasFile);
resProt.setSubstitution('myalias', aliasURI);
// assuming the code modules are in the alias folder itself
*/
content bootstrap-jsm ./
//https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/
var EXPORTED_SYMBOLS = ['foo', 'bar'];
function foo() {
return 'foo';
}
var dummy = 'dummy is a string';
var bar = {
name: 'bar',
size: 3,
theDummy: dummy,
theLastVar: lastVar //when you import this jsm and try to get bar.theLastVar you will find that it is 'undefined', this is because 'lastVar' was not defined at the time this object was created
};
var lastVar = 'this is the last var its a string';
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>Bootstrap-JSM@jetpack</em:id>
<em:version>initial</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack>
<!-- Firefox -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>7.0</em:minVersion>
<em:maxVersion>27.0</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>Bootstrap JSM</em:name>
<em:description>Template for how to create a JSM module.</em:description>
<em:creator>Noitidart</em:creator>
<em:contributor>Pat for Icon</em:contributor>
<em:optionsType>2</em:optionsType>
</Description>
</RDF>
@Noitidart
Copy link
Author

README

Why chrome and why not resource?

At least as of Firefox 27.0.1, we cannot use resources in bootstrap.js, if we had put in our chrome.manifest file this code:

resource bootstrap-jsm ./

It would give us this error:

Bootstrapped manifest not allowed to use 'resource' directive.

Important things to learn in each commit

Revision 1

It's bugged don't look at it.

Revision 2

Fixed. The problem was the path in the manifest file was wrong. So download XPI and install it then import helloWorld.jsm like this:

Cu.import('chrome://bootstrap-jsm/content/helloWorld.jsm');

To demonstrate that theLastVar is undefined in the bar object because var lastVar was defined after that object do the following:

  • Open Scratchpad
  • Go to Environment menu and pick Browser
  • Import the module and alert bar.theLastVar, see code below
Cu.import('chrome://bootstrap-jsm/content/helloWorld.jsm');
Services.wm.getMostRecentWindow(null).alert(bar.theLastVar);
  • You will see that it alerts undefined

Revision 3

I put the example into the bootstrap file. It was important because it shows you cannot import the JSM module until startup() or after startup.

You can still do the experiment mentioned in Revision 2 section as JSM files can be imported anywhere.

Revision 4

  • Moved the Services.jsm import to outside of startup as there is no reason for it to be inside

@gregglind
Copy link

This is a great example! I will be referencing it a lot in the Shield Study (Legacy Addon) documentation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment