Earlier this week, I wrote my first Firefox extension, a port of the “Millennials to Snake People” Chrome extension, which you might’ve read about in the Huffington Post, or The Verge, or quite a few other outlets. It simply takes the word “millennials” and re-writes it to “snake people.” It also rewrites quite a few other things, such as replacing “digital native” to “parseltongue” – you can read all the replacements in the source.
My writing of the port came out of a Facebook conversation where a friend was disappointed that she couldn’t use the extension because it didn’t exist for Firefox, and I had a port up and running in about an hour.
Now, when people say “I did this in 30 seconds!” I’m pretty skeptical, but it was quite easy to port to Firefox using the jpm tool, but there are a few gotchas I found and thus hello, here’s a blog post.
Build you a Firefox extension
This tutorial is to use jpm, which stands for “jetpack manager”. This only works for versions of Firefox 38+, and at this writing we’re on Firefox … 39 🙂 However, since Firefox (hopefully) updates automatically, people should get on the newer versions and be able to use your plugin, because jpm was wonderfully simple to use once I got it.
1. Install jpm GLOBALLY
I have a bias against the -g
flag on npm install
.
If we can agree that namespaces are a good idea, then can all y’all stop wanting packages installed globally? (ಠ_ಠ)
— Pam Selle (@pamasaur) June 28, 2015
I prefer to install packages in my project and then use npm
to run those binaries by adding a command to the scripts object of package.json
.
You CANNOT do this with jpm. It will mess up the packaging of your project. You have to install it globally 🙁 So run npm install -g jpm
.
2. Set up your package.json file
This is fairly similar to working with say, NW.js. Your package.json file needs a main
attribute and engines
. jpm comes with an init
command that will make your package.json for you, but you can edit your existing package.json if you made one to include the necessary attributes.
Here’s what a package.json from jpm init
looks like:
{
"title": "My Jetpack Addon",
"name": "addon-example",
"version": "0.0.1",
"description": "A basic add-on",
"main": "index.js",
"author": "",
"engines": {
"firefox": ">=38.0a1",
"fennec": ">=38.0a1"
},
"license": "MIT"
}
3. Tell your main script what to do
The main script for Millennials to Snake people is very simple – it injects JavaScript onto any web page. As far as I could tell, this is what the Chrome extension does.
Aside: BE CAREFUL ABOUT WHAT EXTENSIONS YOU INSTALL.
The longer I program, the more I get paranoid about just how much shit there is out there and how easily we install it without knowing what we have, without reading the source, and even if we have the source, how do we KNOW that the source is the input that generates the output that we install unless we compile it ourselves? And there’s even problems from there!
Anyhow, back to code.
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: "*",
contentScriptFile: data.url("content-script.js")
});
We load the data and pageMod modules and use those to say “we’re going to modify the page” and use data to get the location of the script I want loaded on any webpage (that matches *, aka, every webpage).
Now that I’ve told the main file to load this JavaScript file, the extension is done.
4. Package it!
This is why you need jpm installed globally. jpm appears to run a command that wraps up your whole folder into a package (.xpi) that Firefox can understand, but it wraps your _whole_ project, including your node_modules folder.
Run jpm xpi
and it will generate a .xpi file for you.
5. Submit it!
The submission process is really quite simple. There’s a form, you upload your package, and it runs some automated verifications on it.
It’s pretty cool! After that, it’s what you’d expect along the lines of linking to your source (if you’re going to), writing a description, etc.
Once you’ve submitted, while it’s pending review, it will still have its own web page (not sure if that goes away eventually or if the package is rejected?) and people can install the plugin right away.
jpm was quite easy to get going once I figured some of it out (there are about 3+ places to find jpm docs, but this one was my favorite), and maybe this little tutorial will help people port plugins they like (or made!) for Chrome!
Hi Pam
One question, when setting the path to the icon in package.json file where is the path relative from?
I have an extension that was sourcing the icon fine until recently. Wondering if it was something I changed or the base of the path has changed in the SDK?
Thanks
Hey, I didn’t set an icon in the package.json, I set that via the form on the Add-ons store. Don’t know if that helps at all ¯\_(ツ)_/¯
Hi,
can you tell me how do i add external packages like this “https://github.com/Gozala/q” .. I copied the q.js to the development directory (where i’m developing the add-one) but there should a way to add it using node “npm” can you tell me .. i’m just started last night ,please ..
Mehedee, check out https://docs.npmjs.com/getting-started/installing-npm-packages-locally
Hi,
can you tell me how do i add id for package.json file. Is it necessary to add id?
Hi,
i am trying out firefox add-on sdk, i am confused about one thing. I am adding some npm packages and they work without giving any errors. But some packages fails giving error message:
Message: Module `xxx` is not found at resource://gre/modules/commonjs/xxx.js
Some examples would be ‘net’ and ‘util’ modules.
Is there a way to make firefox add-ons use at least core nodejs modules (like ‘net’) ?
while running command npm install -g jpm it is not getting installed in my laptop.
it always shows ‘normalizetree->install \ |——————————-‘. like this
What type of review did you choose and how long did it take?
I think I chose pre-review, and it happened over maybe 3 days.