One of the main objectives of Project Async is to encourage Firefox developers and Firefox add-on developers to use Chrome Workers to ensure that whatever they do doesn’t block Firefox’ UI thread. The main obstacle, for the moment, is that Chrome Workers have access to very few features, so one the tasks of Project Async is to add features to Chrome Workers.

Today, let me introduce the Module Loader for Chrome Workers.

This module loader should not surprise developers familiar with CommonJS, as it implements a minimal CommonJS require() .

Loading modules

Loading a module is trivial.

Firstly, import the module loader:

// Import the module loader. // You only need to do this once per worker, but doing it several times is ok. importScripts("resource://gre/modules/workers/require.js");

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 osfile_shared_allthreads. Since it exports a value |declareFFI|, let's try it: 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 trivial.

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

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); }

This is all you need to know to use the module loader. Have fun!

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.