Jetpack Page Mods vs. User Scripts

Havi Hoffman

Page mods were introduced to the Jetpack prototype in July of last year, and I haven’t yet seen an article comparing them to user scripts yet, so I’d like outline some of the differences that I’ve been able to discern. However, I will be focusing especially on the non-prototype version of Jetpack Page Mods (JEP 107), rather than the prototype version which was released last July. There are many similarities between the two, and the differences are mainly improvements. The new Page Mods API found in Jetpack Enhancement Proposal (JEP) 107 has not been implemented yet, but it will be soon, so we’ll take a look at what’s in the works.

The purpose of both Jetpack page mods and user scripts is basically to add features and functionality to any website. This means that if you wish to change a website, either by mashing it up with data from another website, improving elements of the site, or whatever else, then you can with an understanding of JavaScript, HTML, and CSS. Both of these APIs have their own set of benefits unique to them, I’ll talk a bit about each and highlight which API is best given your development goals.

Before I discuss Jetpack page mods, let’s take a look at user scripts..

User Scripts

Introduction

Ever since Greasemonkey was created in late 2004, and was introduced to the world in 2005, it has made user scripts very popular and today there are over 40,000 user scripts available at userscripts.org alone, which should show you just how simple they are to write and how many ideas web users have come up with in the time that has past (on average over 20 user scripts are written per day). If you would like to read more about Greasemonkey user scripts then please read the Greasemonkey wiki.

Cross browser adaptations

Greasemonkey’s popularization of user scripts has lead browsers such as Opera and Google Chrome to support user scripts to varying degrees. For Safari there is the GreaseKit plug-in, and user scripts are available in IE 7 with the IE7Pro plug-in. These adaptations do not all fully support the Greasemonkey API, but they do support a large subset of Greasemonkey user scripts. Some user scripts may need to be written in a way that is not as reliant on Firefox’s JavaScript & DOM implementation to fully take advantage of user script compatibility in these browsers.

Greasemonkey API

There are a few chrome privileges user scripts have been granted by the Greasemonkey API thus far, including GM_xmlhttpRequest which allows one to make cross domain requests, GM_getValue/GM_setValue/GM_deleteValue allow one to save simple persistent values, and GM_registerMenuCommand which allow one to create a simple Greasemonkey menu item.

Scripts are reloaded for every page load

User scripts are completely reloaded after every page load, the same way native JavaScript is required to. This means that if a single script is meant to run on every page or a large collection of pages, then the script is completely reloaded for each. In this situation, and others, one might instead want to have a single piece of code that can be referenced by all pages that it is supposed to be run on.

Code reuse

With user scripts one can use the @require header to have external JavaScript downloaded when the user installs the script. More crude methods would be to add a script element to the page to fetch the code (although this would mean that you would have to wait for the script to download and load before you use it), or simply copying & pasting the desired code. In all three cases however, the JavaScript is loaded on every page load and this has the potential to reduce the performance of the user’s browser.

Settings

With user scripts one can set, get, and remove strings, booleans, and integers only with the GM_getValue/GM_setValue/GM_deleteValue functions, but they will need to provide an html interface for the user to change these settings, and there are frameworks that have been built using the aforementioned @require header, such as GM_Config.

I should also mention that if the user script is being run on Greasemonkey for Firefox then the user can also change stored values (which are often settings) by going to about:config, but this method obviously isn’t user friendly.

JavaScript libraries

With user scripts there is not a JavaScript library available by default, one can use the @require header to have one downloaded, but this has the associated issue I previously mentioned, which is that the library will be reloaded on every page for the user, and if the user has other user scripts that are running on the same pages, which also include libraries, then the user could find themselves in a situation where they have jQuery loading 10 times per page load for some pages, or worse.

Jetpack Page Mods

Introduction

The best documentation available for making Jetpack page mods made with Jetpack’s prototype was JEP 17, but now after the reboot, the best documentation for Jetpack page mods that are made with the SDK is JEP 107; although JEP 107 is in progress at the moment it’s preferable to discuss, simply because it’s Jetpack’s future.

Limited to Firefox

Jetpack (and therefore Jetpack page mods) are basically limited to Firefox for the near future, but compatibility may come in later phases of the project.

Chrome privileged code

A Jetpack developer will not only have access to the built-in APIs defined in the JEPs, which offer a great deal of chrome functionality, but they may also create Jetpack Chrome Modules which have access to the browser’s chrome (aka a Privileged Jetpack Module). Therefore a Jetpack page mod has access to a wider variety of  browser methods, functionality, and UI elements.

Multi-page Modding

With Jetpack page mods your JavaScript variables and functions can mod many different pages by registering your script and styles in a single pageMod instance.  This means that you can define a function or variable once and have it used on page load in all the pages you specify. This is preferable to having the same function defined many times for each page you apply your mods to.

Pseudo Example:

// execution counter
var counter = 0;
var mainFunction = function(){
counter++;
// do stuff
};
var myMods = new pageMod({
'include': ['*.google.com'],
'exclude': ['https://mail.google.com/*'],
'script': [ mainFunction ]
});

In this example counter would be equal to number of pages the page mod was executed on during the time that the user had Firefox browser open, only once the user closes Firefox or removes the Jetpack will the counter variable be removed from memory.

Code reuse

With Jetpack you can make modules, which can be reused by other Jetpacks; this wasn’t possible with the Jetpack prototype.

Settings

For the Jetpack prototype there was the Settings JEP 24 which defined a convenient area for users to configure their settings for their Jetpacks. After the reboot however, Jetpacks are Firefox extensions, and they can be given settings in a similar fashion, there is not a JEP proposing a simple API to provide settings any longer, but when everyone can create modules anyone can create a module to solve this problem, so I expect we will see a solution in due time.

JavaScript Libraries

Support for major JavaScript libraries within Jetpack is something that the platform aims to support in future releases.

Summary

Write user scripts for simple problems or when you want/need a cross browser solution, and Jetpack page mods can be used when you need to do what a user script cannot do. Also, consider the fact that some user scripts will perform better as Jetpack page mods because of multi-page modding and the ability to access deeper levels of the browser’s functionality.