JEP Content scripts

Gozala edited this page May 30, 2012 · 4 revisions

Most of the Add-on SDK APIs are designed around content scripts which are not necessary easy to grok or work with. In addition we ended up adding set of content-script associated options to each API. In some cases it also maybe neat to have an ability to share content script instance in different APIs contexts like PageMod and ContextMenu for example.

Relevant bugs


  • Allow reuse of content scripts
  • Allow sharing of content-scripts for different APIs (PageMod, ContextMenu)


Instead of making each API take content script related options we probably could have an API to create a ContentScript instance instead:

let script = ContentScript({
  uri: contentScriptFile, // file to create content script from 
  // source: code, // Or an option to create from source itself.

// Set up listeners for `message` event for all scripts.
script.port.on('message', function(port, data) {
  // Reply back to the `port` message was received from. 
  port.emit('reply', compute(data));

// Use created content script in a page mod.
let mod = PageMod({
  include: "*.org",
  contentScript: script

// Execute content script in the context of currently active
// tab (Page.mod will use same `spawn` method).

// Execute content script in the context of a hidden page.

// Listen to content script spawns and get a communication
// port.
script.on('spawn', function(port) {
  port.emit('hello !!');

This will allow decoupling of content script logic from rest of the APIs and allow improvements in that area without changing each API individually.

More thoughts

This maybe a great option to solve some of the inherent problems like asynchronous communications with a host add-on. For some operations it's way more convenient to do things async but with less callbacks. Some experiments have being made in ActorJS and TaskJS to make this less painful using generators. We or community would be able to experiment with special flavor of ContentScript that uses generators for example:

let clipboard = require("clipboard");
let Actor = require('other-lib/actors').Actor;

let script = Actor(function() {
  let text = yield this.receive('clipboard.get');
  document.activeElement.value = text;

// Either traditional content-script API
script.port.on('clipboard.get', function(port) {
  port.emit('clipboard.get', clipboard.get());

// Or maybe some library sugar ?

// And maybe even more sugar ?
let script = Actor(function() {
  let clipboard = yield require('clipboard');
  document.activeElement.value = clipboard.get();


Prior art