Chrome Worker Modules

by 2 contributors:

The preferred way to define and load modules for Chrome Workers is to use the Chrome Worker Module Loader. This module loader should not surprise developers familiar with CommonJS, as it implements a minimal CommonJS require().

Loading modules

Loading a module is simple. Start by importing the module loader. You only need to do it once for each worker, from within the chrome worker itself:

importScripts("resource://gre/modules/workers/require.js");

Note: Although you only need to do this once for each worker, it doesn't hurt if you do it more than once.

This defines a global value require(), that you may now use as follows:

// Import the module
// (here, we import the core of OS.File)
let Core = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");

// We may now use module Core.
Core.declareFFI(...)

Note that, for the moment, require() only accepts absolute URIs. If the your module URI ends with “.js”, you can omit the extension.

Creating modules

Creating a module is just as simple.

A module is a file, whose filename generally ends with either “.js” or “.jsm”, and designed to be opened through require(). Any value you define in that file is private by default. To make the value public, you just have to add it to either global value exports, as follows:

/* File myModule.js */
let secretKey = "this is a secret";
let publicKey = "this is public";
exports.key = publicKey;
// secretKey is not exported
// publicKey is exported with name "key"

Alternatively, if you prefer that style, you may write

// variable |module| is a special global introduced by require()
module.exports = {
  key: publicKey
};

Once this is done, we may load the module and use the values that have been exported

// Assuming that myModule.js is installed to resource://gre/modules/myModule.js
let Module = require("resource://gre/modules/myModule.js")

foo(Module.key); // Module.key == "this is public";
// However, secretKey is not exported and cannot be used

For the installation of resources, please see the documentation on moz.build (if your code is part of the platform) or on chrome manifests (if your code is part of an add-on).

Stack traces

Unfortunately, the module loader doesn’t play nicely with error stack traces. That is, the following will not show human-readable stacks:

try {
    MyModule.foo();
} catch (ex) {
    log("Exception raised at " + ex.fileName)
    log("Stack: " + ex.stack);
}

Rather, you should use properties moduleName and moduleStack, as follows:

try {
    MyModule.foo();
} catch (ex) {
    log("Exception raised at " + ex.moduleName)
    log("Stack: " + ex.moduleStack);
}

Subtleties

You shouldn’t mix both styles exports.foo = bar and module.exports = {foo: bar}. If you do, know that any call to module.exports will overwrite all calls to `exports.foo = bar.

You should not modify exports or module.exports once your module initialization is complete.

The module loader supports cyclic calls to require(). However, if you have cyclic requirements, some of the modules involved in the cyclic requirements may become visible by the other modules before they are fully evaluated.

No attempt is made to fully isolate modules from each other. In particular, globals (String, Math, Object, self) and the worker global scope itself (this) are shared between workers. In other words, the true isolation unit is the worker itself, not the module.

Document Tags and Contributors

Contributors to this page: Sheppy, Yoric
Last updated by: Sheppy,