Chrome Worker Modules

  • Revision slug: Mozilla/ChromeWorkers/Chrome_Worker_Modules
  • Revision title: Chrome Worker Modules
  • Revision id: 441333
  • Created:
  • Creator: Yoric
  • Is current revision? No
  • Comment

Revision Content

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 <tt>require()</tt>.

Loading modules

Loading a module is quite simple.


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 <tt>require()</tt>, 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, <tt>require()</tt> 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 <tt>require()</tt>. 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 <tt>exports</tt>, 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 <tt>moduleName</tt> and <tt>moduleStack</tt>, as follows:

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

Subtleties

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

You should not modify <tt>exports</tt> or <tt>module.exports</tt> once your module initialization is complete.

The module loader supports cyclic calls to <tt>require()</tt>. 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 (<tt>String</tt>, <tt>Math</tt>, <tt>Object</tt>, <tt>self</tt>) and the worker global scope itself (<tt>this</tt>) are shared between workers. In other words, the true isolation unit is the worker itself, not the module.

Revision Source

<p style="text-align:justify;">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 <tt>require()</tt>.</p>
<h2 style="text-align:justify;">Loading modules</h2>
<p style="text-align:justify;">Loading a module is quite simple.</p>
<p style="text-align:justify;"><br />
  Firstly, import the module loader:</p>
<div class="container">
  <pre class="line number3 index2 alt2">
<code class="brush: js">// Import the module loader.</code>
<code class="jscript comments">// You only need to do this once per worker, but doing it several times is ok.</code>
<code class="jscript plain">importScripts(</code><code class="jscript string">"<a>resource://gre/modules/workers/require.js</a>"</code><code class="jscript plain">);</code></pre>
</div>
<div>
  &nbsp;</div>
<p style="text-align:justify;">This defines a global value <tt>require()</tt>, that you may now use as follows:</p>
<div>
  &nbsp;</div>
<div class="container">
  <pre class="line number6 index5 alt1">
<code class="brush: js">// Import the module</code>
<code class="jscript comments">// (here, we import the core of OS.File)</code>
<code class="jscript plain">let Core = require(</code><code class="jscript string">"<a>resource://gre/modules/osfile/osfile_shared_allthreads.jsm</a>"</code><code class="jscript plain">);</code>

<code class="jscript comments">// We may now use module osfile_shared_allthreads. Since it exports a value |declareFFI|, let's try it:</code>
<code class="jscript plain">Core.declareFFI(...)</code></pre>
</div>
<p style="text-align:justify;">Note that, for the moment, <tt>require()</tt> only accepts absolute URIs. If the your module URI ends with “.js”, you can omit the extension.</p>
<h2 style="text-align:justify;">Creating modules</h2>
<p style="text-align:justify;">Creating a module is just as simple.</p>
<p style="text-align:justify;">A module is a file, whose filename generally ends with either “.js” or “.jsm”, and designed to be opened through <tt>require()</tt>. 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 <tt>exports</tt>, as follows:</p>
<div>
  <div class="container">
    <pre class="line number6 index5 alt1">
<code class="brush: js">/* File myModule.js */</code>
<code class="jscript spaces"> </code><code class="jscript plain">let secretKey = </code><code class="jscript string">"this is a secret"</code><code class="jscript plain">;</code>
<code class="jscript spaces"> </code><code class="jscript plain">let publicKey = </code><code class="jscript string">"this is public"</code><code class="jscript plain">;</code>

<code class="jscript spaces"> </code><code class="jscript plain">exports.key = publicKey;</code>
<code class="jscript spaces"> </code><code class="jscript comments">// secretKey is not exported</code>
<code class="jscript spaces"> </code><code class="jscript comments">// publicKey is exported with name "key"</code></pre>
  </div>
</div>
<p style="text-align:justify;">Alternatively, if you prefer that style, you may write</p>
<div>
  <div class="container">
    <pre class="line number4 index3 alt1">
<code class="brush: js">// variable |module| is a special global introduced by require()</code>

<code class="jscript plain">module.exports = {</code> 
<code class="jscript plain">  key: publicKey</code>
<code class="jscript plain">};</code></pre>
  </div>
</div>
<p style="text-align:justify;">Once this is done, we may load the module and use the values that have been exported</p>
<div>
  <div class="container">
    <pre class="line number5 index4 alt2">
<code class="brush: js">// Assuming that myModule.js is installed to <a>resource://gre/modules/myModule.js</a></code>
<code class="jscript plain">let Module = require(</code><code class="jscript string">"<a>resource://gre/modules/myModule.js</a>"</code><code class="jscript plain">)</code>

<code class="jscript plain">foo(Module.key); </code><code class="jscript comments">// Module.key == "this is public";</code>
<code class="jscript comments">// However, secretKey is not exported and cannot be used</code></pre>
  </div>
</div>
<h2 style="text-align:justify;">Stack traces</h2>
<p style="text-align:justify;">Unfortunately, the module loader doesn’t play nicely with error stack traces. That is, the following will not show human-readable stacks:</p>
<div>
  &nbsp;</div>
<div class="container">
  <pre class="line number6 index5 alt1">
<code class="brush: js">try</code> <code class="jscript plain">{</code>
<code class="jscript plain">  MyModule.foo();</code>
<code class="jscript plain">} </code><code class="jscript keyword">catch</code> <code class="jscript plain">(ex) {</code>
<code class="jscript plain">  log(</code><code class="jscript string">"Exception raised at "</code> <code class="jscript plain">+ ex.fileName)</code>;
<code class="jscript plain">  log(</code><code class="jscript string">"Stack: "</code> <code class="jscript plain">+ ex.stack);</code>
<code class="jscript plain">}</code></pre>
</div>
<p style="text-align:justify;">Rather, you should use properties <tt>moduleName</tt> and <tt>moduleStack</tt>, as follows:</p>
<div>
  <div class="container">
    <pre class="line number6 index5 alt1">
<code class="brush: js">try</code> <code class="jscript plain">{</code>
<code class="jscript spaces">  </code><code class="jscript plain">MyModule.foo();</code>
<code class="jscript plain">} </code><code class="jscript keyword">catch</code> <code class="jscript plain">(ex) {</code>
<code class="jscript spaces">  </code><code class="jscript plain">log(</code><code class="jscript string">"Exception raised at "</code> <code class="jscript plain">+ ex.moduleName)</code>
<code class="jscript spaces">  </code><code class="jscript plain">log(</code><code class="jscript string">"Stack: "</code> <code class="jscript plain">+ ex.moduleStack);</code>
<code class="jscript plain">}</code></pre>
  </div>
</div>
<h2 style="text-align:justify;">Subtleties</h2>
<p style="text-align:justify;">You shouldn’t mix both styles <tt>exports.foo = bar</tt> and <tt>module.exports = {foo: bar}</tt>. If you do, know that any call to <tt>module.exports</tt> will overwrite all calls to `exports.foo = bar.</p>
<p style="text-align:justify;">You should not modify <tt>exports</tt> or <tt>module.exports</tt> once your module initialization is complete.</p>
<p style="text-align:justify;">The module loader supports cyclic calls to <tt>require()</tt>. 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.</p>
<p style="text-align:justify;">No attempt is made to fully isolate modules from each other. In particular, globals (<tt>String</tt>, <tt>Math</tt>, <tt>Object</tt>, <tt>self</tt>) and the worker global scope itself (<tt>this</tt>) are shared between workers. In other words, the true isolation unit is the worker itself, not the module.</p>
Revert to this revision