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.
jpm is a command-line tool that enables you to test, run, and package add-ons.
This is the reference page for jpm. See also jpm tutorial for getting started.
jpm usage is:
jpm [command] [options]
jpm supports the following global options:
-h, --help - show a help message and exit -V, --version - print the jpm version number --addon-dir - directory for your source code, defaulting to the current directory
Installation
jpm is distributed with the node package manager npm.
Installing npm
There are two ways to get npm.
- Download and install Node.js from nodejs.org. Node.js includes npm.
- Or, if you have a package manager like APT, install npm via that. For example, in an Ubuntu or Debian terminal window, enter
sudo apt-get install nodejs nodejs-legacy
npm
.
To test your installation, run:
/usr/bin/env node -v
If you get an error message saying /usr/bin/env: node: No such file or directory and you have installed nodejs through a package manager, nodejs may have been installed under a different executable name. To ensure compatibility with jpm, however, it must be present in your PATH under the name node
. On Debian and Ubuntu, this can be remedied by ensuring you installed the compatibility package, nodejs-legacy
:
sudo apt-get install nodejs-legacy
On other distributions, you may have to create a local symlink to nodejs manually:
sudo ln -s "$(which nodejs)" /usr/local/bin/node
Installing jpm
After you have npm installed and node
on your PATH, install jpm just as you would any other npm package.
Installing jpm globally
npm install jpm --global
Depending on your setup, you might need to run this as an administrator: sudo npm install jpm --global
Installing jpm locally
If you do not wish to, or are unable to, install jpm globally, you may instead install it locally:
cd $HOME && npm install jpm
To run jpm
from a terminal when installed locally, you must add the directory "$HOME/node_modules/.bin/"
to your terminal's PATH first. Add the following line to the end of the file $HOME/.profile
to add it to your PATH permanently (as the file .profile
is executed every time a new terminal is opened):
export PATH="$HOME/node_modules/.bin/:$PATH"
Installing jpm from git
Alternatively, you can also get the latest version of jpm using git:
git clone https://github.com/mozilla-jetpack/jpm.git cd jpm npm install npm link
After installing jpm
After installation, at the command prompt, type:
jpm
You should see a screen summarizing the available jpm commands. Note that unlike cfx, jpm is available in every command prompt you start, as long as you installed it with the --global
flag.
Install a different version of Firefox
As of Firefox 48, it is not possible to use unsigned add-ons (i.e. any add-on which you are in the process of developing) in the branded release or beta versions of Firefox. Thus, you will need to download and install a different version of Firefox. Assuming you don't want an old version of Firefox, your options are Firefox Developer Edition, Firefox Nightly, Unbranded Beta, or Unbranded Release.
When testing your add-on, you will need to use the -b
option to jpm run.
See Selecting a browser version.
Problems?
If you do not see this, ask for help. SDK users and project team members discuss problems and proposals on the project mailing list. Someone else may have had the same problem you do, so try searching the list. You are welcome to post a question, too. You can also chat with other SDK users in #jetpack on Mozilla's IRC network.
Command reference
jpm supports the following commands:
jpm init |
Create a skeleton add-on as a starting point for your add-on. |
jpm run |
Launch an instance of Firefox with your add-on installed. |
jpm test |
Runs your add-on's unit tests. |
jpm xpi |
Package your add-on as an XPI file, which is the install file format for Firefox add-ons. |
jpm post |
Package your add-on as an XPI file, and then post it to some URL. |
jpm watchpost |
Package your add-on as an XPI file whenever there is a file change and post that to some URL. |
jpm sign |
Package your add-on as an XPI file, and then retrieve a new XPI signed by Mozilla. |
jpm init
This command initializes a new add-on from scratch.
Create a new directory, change into it, and run jpm init
.
mkdir my-addon cd my-addon jpm init
You'll then be asked to supply some information about your add-on: this will be used to create your add-on's package.json file.
- title
- name: this defaults to the name of the directory in which you are running
jpm init
. Unless anid
field is present in package.json, jpm prepends "@" toname
and use the result as theid
field in the add-on's install manifest. - version
- description
- entry point (which maps to "main" in package.json)
- author
- engines (supported applications)
- license
Most of these fields have a default, which is shown in brackets after the question. If you just press Enter, your add-on gets the default value.
Once you've supplied a value or accepted the default for these properties, you'll be shown the complete contents of "package.json" and asked to accept it.
Then jpm creates a skeleton add-on, as a starting point for your add-on development, with the following file structure:
- my-addon
- index.js
- package.json
- test
- test-index.js
jpm run
This command runs a new instance of Firefox with the add-on installed:
jpm run
jpm run
accepts the following options:
-b --binary BINARY |
Use the version of Firefox specified in BINARY. BINARY may be specified as a full path or as a path relative to the current directory. jpm run -b /path/to/Firefox/NightlySee Selecting a browser version. |
--binary-args CMDARGS |
Pass extra arguments to Firefox. For example, to pass the jpm run --binary-args -jsconsole To pass multiple arguments, or arguments containing spaces, quote them: jpm run --binary-args '-url mzl.la -jsconsole' |
--debug |
Run the Add-on Debugger attached to the add-on. |
-o --overload PATH |
Rather than use the SDK modules built into Firefox, use the modules found at PATH. If See Overloading the built-in modules for more information. |
-p --profile= |
By default, jpm uses a clean temporary Firefox profile each time you call jpm run. Use the The PROFILE value may be a profile name or the path to the profile. See Using profiles for more information. |
-v --verbose |
Verbose operation. |
--no-copy |
Use with caution because
jpm run|test changes many preferences, never use with your main profile.This only applies when
Disables the copying of the profile used, which allows one to reuse a profile.--profile is used. |
jpm test
Use this command to run an add-on's unit tests. The command:
- Looks for a directory called "test" within the current directory (or
--addon-dir
). - Opens every file in there whose name starts with "test-". Make note of the hyphen after "test" in the filename.
jpm test
include a file called "test-myCode.js", but will exclude files called "test_myCode.js" or "testMyCode.js") - call every function exported from that file whose name starts with "test".
jpm test
See the tutorial on unit testing and the reference documentation for the assert
module for more details on this.
jpm test
accepts the following options:
-b --binary BINARY |
Use the version of Firefox specified in BINARY. BINARY may be specified as a full path or as a path relative to the current directory. jpm test -b /path/to/Firefox/Nightly |
--binary-args CMDARGS |
Pass extra arguments to Firefox. For example, to pass the jpm test --binary-args -jsconsole To pass multiple arguments, or arguments containing spaces, quote them: jpm test --binary-args '-url mzl.la -jsconsole' |
--debug |
Run the Add-on Debugger attached to the add-on. |
-f --filter FILE[:TEST] |
Only run tests whose filenames match FILE and optionally match TEST, both regexps. jpm test --filter base64:btoa The above command only runs tests in files whose names contain "base64", and in those files only runs tests whose names contain "btoa". |
-o --overload PATH |
Rather than use the SDK modules built into Firefox, use the modules found at PATH. If See Overloading the built-in modules for more information. |
-p --profile |
By default, jpm uses a clean temporary Firefox profile each time you call jpm run. Use the The PROFILE value may be a profile name or the path to the profile. See Using profiles for more information. |
--stop-on-error |
By default, jpm test keeps running tests even after tests fail. Specify jpm test --stop-on-error |
--tbpl |
Print test output in Treeherder format |
--times NUMBER |
Run tests NUMBER of times: jpm test --times 2 |
-v --verbose |
Verbose operation. |
--no-copy |
Use with caution because
jpm run|test changes many preferences, never use with your main profile.This only applies when
Disables the copying of the profile used, which allows one to reuse a profile.--profile is used. |
jpm xpi
This command packages the add-on as an XPI file, which is the install file format for Mozilla add-ons.
jpm xpi
It looks for a file called package.json
in the current directory (or --addon-dir
) and creates the corresponding XPI file. It ignores any ZIPs or XPIs in the add-on's root, and any test files. It includes all other files. If you want to exclude extra files, see the .jpmignore file.
Once you have built an XPI file, you can distribute your add-on by submitting it to addons.mozilla.org.
jpm xpi
accepts the following option:
--dest-dir |
Optional destination directory for the generated XPI file. The current working directory is the default destination. |
-v --verbose |
Verbose operation: jpm xpi -v |
jpm post
This command packages the add-on as an XPI file then posts it to some URL.
jpm post
It looks for a file called package.json
in the current directory (or --addon-dir
) and creates an XPI file with which to post to the --post-url
.
jpm post
accepts the following options:
--post-url URL |
The URL to post the extension to after creating an XPI. jpm post --post-url http://localhost:8888/ See Using Post and Watchpost for more information. |
-v --verbose |
Verbose operation: jpm post --post-url http://localhost:8888/ -v |
jpm watchpost
This command packages the add-on as an XPI file then posts it to some URL whenever a file in the current working directory changes.
jpm watchpost
Creates an XPI whenever a file changes in the current working directory (or --addon-dir
) and posts that to the --post-url
.
jpm watchpost
accepts the following options:
--post-url URL |
The URL to post the extension to after creating an XPI. jpm watchpost --post-url http://localhost:8888/ See Using Post and Watchpost for more information. |
-v --verbose |
Verbose operation: jpm watchpost --post-url http://localhost:8888/ -v |
jpm sign
This feature is only supported from jpm 1.0.4 onwards.
This command retrieves a new XPI for your add-on signed by Mozilla. This allows you to self-host your add-on so that users can install it without error when signed add-ons are required.
You can sign an XPI you've already generated by passing the XPI file in the --xpi
argument, like this:
jpm sign --api-key ${JWT_ISSUER} --api-secret ${JWT_SECRET} --xpi <xpi file>
Alternatively, you can omit the --xpi
argument, in which case jpm sign
will generate an XPI from the current directory (or --addon-dir
).
jpm sign --api-key ${JWT_ISSUER} --api-secret ${JWT_SECRET}
This submits an XPI it to the addons.mozilla.org signing API, then downloads a signed XPI to the working directory if it passes validation.
To get values for --api-key
and --api-secret
, you will need to create API credentials on addons.mozilla.org. On the AMO key management page, these values are labeled "JWT_Issuer" and "JWT_Secret".
Here are some possible outcomes of running the sign
command:
- Your add-on passed validation, was signed by Mozilla, and a new signed XPI was downloaded to your working directory.
- Your add-on failed validation, was not signed, and you got a link to a detailed report. After fixing the validation errors, you can run the command again.
- You add-on passed validation but it could not be automatically signed because your add-on is listed. Listed add-ons will require a manual review before they can be signed.
- Your add-on at this exact version number already exists, so it was not signed. Increment the version number in your package.json file and run the command again.
Under the hood, jpm sign
creates an unlisted add-on inside addons.mozilla.org, which means you must distribute the XPI file yourself for your users to install it. If you need to create a listed add-on, just submit it directly to addons.mozilla.org where it is signed automatically. See the debugging section if you are experiencing difficulty installing a signed add-on.
jpm sign
accepts the following options:
--api-key=JWT_ISSUER |
API access key (string) generated on the addons.mozilla.org key management page. On the AMO key management page, this value is labeled "JWT Issuer". |
--api-secret=JWT_SECRET |
API access secret (string) generated on the addons.mozilla.org key management page. This value should be guarded with care and never checked into version control. If your secret is compromised, another developer could upload add-ons to your account. You should revoke and regenerate compromised API credentials immediately. On the AMO key management page, this value is labeled "JWT Secret". |
--api-url-prefix=http://.../api |
An optional API URL prefix in case you'd like to use a pre-production signing API. For example, you could pass |
--xpi=/path/to/file.xpi |
An XPI file to sign. When no file is specified, a new XPI will be generated from the current directory (or |
Techniques
Selecting a browser version
By default, jpm run
and jpm test
runs the release version of Firefox. You can instruct jpm to use a different version in one of two ways:
-
You can use the
-b
or--binary
option to instruct jpm to run a different version of Firefox. You can supply a path to a specific binary:jpm run -b /path/to/Firefox/Nightly
As a shorthand for this, you can pass "nightly", "firefoxdeveloperedition", "aurora", "beta", or "firefox" and jpm will look in the default location for these Firefox versions [Note: As of Firefox 48, the shorthands "firefox" and "beta" will resolve to versions of Firefox which will not run your add-on. This is due to Firefox 48, and later, not having the option to run add-ons which are unsigned.]:
jpm run -b nightly
-
You can set the
JPM_FIREFOX_BINARY
environment variable with the path to the version of Firefox you want to run. When you invokejpm run
orjpm test
without the-b
option, jpm first checksJPM_FIREFOX_BINARY
, and use this as the path if it is set.
Using .jpmignore
to ignore files
Using .jpmignore
is similar to using .gitignore
with git
, .hgignore
with Mercurial, or .npmignore
with npm
. By using this file, you can let jpm
know which files you would like it to ignore when building a .xpi
file with jpm xpi
.
Here is an example:
# Ignore .DS_Store files created by mac .DS_Store # Ignore any zip or xpi files *.zip *.xpi
A .jpmignore
file with the above contents would ignore all zip files and .DS_Store
files from the xpi generated by jpm xpi
.
Using profiles
By default, jpm run
uses a new profile each time it is executed. This means that any profile-specific data entered from one run of jpm
is not, by default, available in the next run.
This includes, for example, any extra add-ons you installed, or your history, or any data stored using the simple-storage API.
To make jpm
use a specific profile, pass the --profile
option, specifying the name of the profile you wish to use, or the path to the profile.
jpm run --profile boogaloo
jpm run --profile path/to/boogaloo
Use the profile manager to create a new profile if needed.
If you need changes to the profile to persist, add the --no-copy
argument. However beware that jpm might also apply changes to the profile, setting some preferences that will make it unusable for daily usage.
Developing without browser restarts
Because jpm run
restarts the browser each time you invoke it, it can be a little cumbersome if you are making very frequent changes to an add-on. An alternative development model is to use the Extension Auto-Installer add-on: this listens for new XPI files on a specified port and installs them automatically. That way you can test new changes without needing to restart the browser:
- make a change to your add-on
- run
jpm post --post-url http://localhost:8888/
, to make an XPI and post it.
You could even automate this workflow with a simple script. For example:
jpm watchpost --post-url http://localhost:8888/
Note that the logging level defined for the console is different when you use this method, compared to the logging level used when an add-on is run using jpm run
. This means that if you want to see the output from console.log()
messages, you have to tweak a setting. See the documentation on logging levels for the details on this.
Overloading the built-in modules
The SDK modules you use to implement your add-on are built into Firefox. When you run or package an add-on using jpm run
or jpm xpi
, the add-on uses the versions of the modules in the version of Firefox that hosts it.
As an add-on developer, this is usually what you want. But if you're developing the SDK modules themselves, of course, it isn't. In this case you need to:
- Get a local copy of the SDK modules that you want: this usually means checking out the SDK from its GitHub repo
- Set the
JETPACK_ROOT
environment variable to your local copy - Pass the
-o
option tojpm run
orjpm xpi
:
jpm run -o
This instructs jpm to use the local copies of the SDK modules, not the ones in Firefox. If you do not want to set the JETPACK_ROOT
environment variable, you can pass the location of your copy of the SDK modules along with -o
:
jpm run -o "/path/to/addon-sdk/"
The path must be an absolute path and point to the SDK's root (not addon-sdk/sdk
or addon-sdk/sdk/lib
, for instance).
Supporting updates for self-hosted add-ons
This feature is only supported from jpm 1.0.3 onwards.
When you make updates to your add-on to add features or fix bugs, you'll want any previously installed versions of the add-on to update themselves to the new version.
If you list your add-on on addons.mozilla.org, then all you have to do here is submit the new version; add-ons default to checking addons.mozilla.org for new versions of themselves. You can stop reading this section.
If you do not list your add-on on addons.mozilla.org, you need to generate a Mozilla-signed XPI and tell Firefox where it can find new versions of your add-on. The way this works is:
- you run jpm sign anytime you need to create a new version
- you host the signed add-on XPI and update it when you need to
- you host an "update manifest", which, among other things, contains a URL pointing to the XPI
- your add-on tells Firefox where it can find the update manifest
To do this, include two extra keys in package.json:
updateURL
: This URL is included in the install manifest of the XPI file thatjpm xpi
builds. It points to your update manifest. TheupdateURL
value may be HTTPS. If it is not, then you'll also need to sign the update manifest, and then include the public key using theupdateKey
field in package.json. See Securing updates for more on this.updateLink
: This URL is included in the update manifest file. It points to the XPI, and must be an HTTPS URL.
If you include updateURL
and updateLink
(and also updateKey
in case updateURL
is not HTTPS), then jpm xpi
will:
- Embed the value you supplied for
updateURL
in the XPI it generates. - Generate an update manifest alongside the XPI, and embed the value you supplied for
updateLink
in the manifest.
You then host the update manifest at updateURL
, and host new versions of the XPI at updateLink
.
For some more details on this, see Automatic Add-on Update Checking.