Using JavaScript code modules

  • Revision slug: JavaScript_code_modules/Using
  • Revision title: Using JavaScript code modules
  • Revision id: 31928
  • Created:
  • Creator: Mgjbot
  • Is current revision? No
  • Comment robot Adding: [[es:Usando módulos de código JavaScript]] <<langbot>>

Revision Content

{{template.Fx_minversion_header(3)}}

JavaScript code modules are a concept introduced in Firefox 3 (Gecko 1.9) and can be used for sharing code between different privileged scopes. Modules can also be used to create global JavaScript singletons that previously required using JavaScript XPCOM objects. A JavaScript code module is simply some JavaScript code located in registered location. The module is loaded into a specific JavaScript scope, such as XUL script or JavaScript XPCOM script, using Components.utils.import.

A very simple JavaScript module looks like this:

var EXPORTED_SYMBOLS = ["foo", "bar"]

function foo() {
  return "foo";
}

var bar = {
  name : "bar",
  size : "3"
};

var dummy = "dummy";

Notice that the module uses normal JavaScript to create functions, objects, constants and any other JavaScript type. The module also defines a special Array named EXPORTED_SYMBOLS. Any JavaScript item named in EXPORTED_SYMBOLS will be exported from the module and injected into the importing scope. For example:

Components.utils.import("resource://app/modules/my_module.jsm");

alert(foo());         // displays "foo"
alert(bar.size + 3);  // displays "6"
alert(dummy);         // displays "dummy is not defined" because 'dummy' was not exported from the module

An extremely important behavior of Components.utils.import is that modules are cached when loaded and subsequent imports do not reload a new version of the module, but instead use the previously cached version. This means that a given module will be shared when imported multiple times. Any modifications to data, objects or functions will be available in any scope that has imported the module. For example, if the simple module were imported into two different JavaScript scopes, changes in one scope can be observed in the other scope.

Scope 1:

Components.utils.import("resource://app/modules/my_module.jsm");

alert(bar.size + 3);  // displays "6"

bar.size = 10;

Scope 2:

Components.utils.import("resource://app/modules/my_module.jsm");

alert(foo());         // displays "foo"
alert(bar.size + 3);  // displays "13"

This sharing behavior can be used to create singleton objects that can share data across windows and between XUL script and XPCOM components.

resource: Protocol

When using Components.utils.import, you will notice that code modules are loaded using a "resource://" protocol. The basic syntax of a resource URL is as follows:

resource://<alias>/<relative-path>/<file.js|jsm>

The <alias> is an alias to a location, usually a physical location relative to the application or XUL runtime. There are several pre-defined aliases setup by the XUL runtime:

  • app - Alias to the location of the XUL application.
  • gre - Alias to the location of the XUL runtime.

The <relative-path> can be multiple levels deep and is always relative to the location defined by the <alias>. The common relative path is "modules" and is used by XUL Runner and Firefox. Code modules are simple JavaScript files with a .js or .jsm extension.

The easiest way for extensions and XUL applications to add custom aliases is by registering an alias in the chrome manifest using a line like this:

resource aliasname uri/to/files/

For example, if the XPI for your foo extension includes a top-level modules directory containing the bar.js module, you could create an alias to that directory via the instruction:

resource foo modules/

You could then import the module into your JavaScript code via the statement:

Components.utils.import("resource://foo/bar.js");

Custom aliases can be programmatically added to the resource protocol as well. For example:

var ioService = Components.classes["@mozilla.org/network/io-service;1"]
                          .getService(Components.interfaces.nsIIOService);
var resProt = ioService.getProtocolHandler("resource")
                       .QueryInterface(Components.interfaces.nsIResProtocolHandler);

var aliasFile = Components.classes["@mozilla.org/file/local;1"]
                          .createInstance(Components.interfaces.nsILocalFile);
aliasFile.initWithPath("/some/absolute/path");

var aliasURI = ioService.newFileURI(aliasFile);
resProt.setSubstitution("myalias", aliasURI);

// assuming the code modules are in the alias folder itself, not a subfolder
Components.utils.import("resource://myalias/file.jsm");

// ...


{{ wiki.languages( { "es": "es/Usando_m\u00f3dulos_de_c\u00f3digo_JavaScript", "fr": "fr/Utilisation_de_modules_de_code_JavaScript", "ja": "ja/Using_JavaScript_code_modules", "pl": "pl/Zastosowanie_modu\u0142\u00f3w_JavaScript" } ) }}

Revision Source

<p>
{{template.Fx_minversion_header(3)}}
</p><p>JavaScript code modules are a concept introduced in Firefox 3 (Gecko 1.9) and can be used for sharing code between different privileged scopes. Modules can also be used to create global JavaScript singletons that previously required using JavaScript XPCOM objects. A JavaScript code module is simply some JavaScript code located in registered location. The module is loaded into a specific JavaScript scope, such as XUL script or JavaScript XPCOM script, using <a href="en/Components.utils.import">Components.utils.import</a>.
</p><p>A very simple JavaScript module looks like this:
</p>
<pre>var EXPORTED_SYMBOLS = ["foo", "bar"]

function foo() {
  return "foo";
}

var bar = {
  name : "bar",
  size : "3"
};

var dummy = "dummy";
</pre>
<p>Notice that the module uses normal JavaScript to create functions, objects, constants and any other JavaScript type. The module also defines a special Array named <code>EXPORTED_SYMBOLS</code>. Any JavaScript item named in <code>EXPORTED_SYMBOLS</code> will be exported from the module and injected into the importing scope. For example:
</p>
<pre>Components.utils.import("resource://app/modules/my_module.jsm");

alert(foo());         // displays "foo"
alert(bar.size + 3);  // displays "6"
alert(dummy);         // displays "dummy is not defined" because 'dummy' was not exported from the module
</pre>
<p>An extremely important behavior of <a href="en/Components.utils.import">Components.utils.import</a> is that modules are cached when loaded and subsequent imports do not reload a new version of the module, but instead use the previously cached version. This means that a given module will be shared when imported multiple times. Any modifications to data, objects or functions will be available in any scope that has imported the module. For example, if the simple module were imported into two different JavaScript scopes, changes in one scope can be observed in the other scope.
</p><p>Scope 1:
</p>
<pre>Components.utils.import("resource://app/modules/my_module.jsm");

alert(bar.size + 3);  // displays "6"

bar.size = 10;
</pre>
<p>Scope 2:
</p>
<pre>Components.utils.import("resource://app/modules/my_module.jsm");

alert(foo());         // displays "foo"
alert(bar.size + 3);  // displays "13"
</pre>
<p>This sharing behavior can be used to create singleton objects that can share data across windows and between XUL script and XPCOM components.
</p>
<h4 name="resource:_Protocol"> resource: Protocol </h4>
<p>When using <a href="en/Components.utils.import">Components.utils.import</a>, you will notice that code modules are loaded using a "resource://" protocol. The basic syntax of a resource URL is as follows:
</p>
<pre class="eval">resource://&lt;alias&gt;/&lt;relative-path&gt;/&lt;file.js|jsm&gt;
</pre>
<p>The <code>&lt;alias&gt;</code> is an alias to a location, usually a physical location relative to the application or XUL runtime. There are several pre-defined aliases setup by the XUL runtime:
</p>
<ul><li> <code>app</code> - Alias to the location of the XUL application.
</li><li> <code>gre</code> - Alias to the location of the XUL runtime.
</li></ul>
<p>The <code>&lt;relative-path&gt;</code> can be multiple levels deep and is always relative to the location defined by the <code>&lt;alias&gt;</code>. The common relative path is "modules" and is used by XUL Runner and Firefox. Code modules are simple JavaScript files with a .js or .jsm extension.
</p><p>The easiest way for extensions and XUL applications to add custom aliases is by registering an alias in the <a href="en/Chrome_Registration">chrome manifest</a> using a line like this:
</p>
<pre class="eval">resource <i>aliasname</i> <i>uri/to/files/</i>
</pre>
<p>For example, if the XPI for your <i>foo</i> extension includes a top-level modules directory containing the <i>bar.js</i> module, you could create an alias to that directory via the instruction:
</p>
<pre class="eval">resource foo modules/
</pre>
<p>You could then import the module into your JavaScript code via the statement:
</p>
<pre class="eval">Components.utils.import("resource://foo/bar.js");
</pre>
<p>Custom aliases can be programmatically added to the resource protocol as well. For example:
</p>
<pre>var ioService = Components.classes["@mozilla.org/network/io-service;1"]
                          .getService(Components.interfaces.nsIIOService);
var resProt = ioService.getProtocolHandler("resource")
                       .QueryInterface(Components.interfaces.nsIResProtocolHandler);

var aliasFile = Components.classes["@mozilla.org/file/local;1"]
                          .createInstance(Components.interfaces.nsILocalFile);
aliasFile.initWithPath("/some/absolute/path");

var aliasURI = ioService.newFileURI(aliasFile);
resProt.setSubstitution("myalias", aliasURI);

// assuming the code modules are in the alias folder itself, not a subfolder
Components.utils.import("resource://myalias/file.jsm");

// ...
</pre>
<p><br>
</p>
<div class="noinclude">
</div>
{{ wiki.languages( { "es": "es/Usando_m\u00f3dulos_de_c\u00f3digo_JavaScript", "fr": "fr/Utilisation_de_modules_de_code_JavaScript", "ja": "ja/Using_JavaScript_code_modules", "pl": "pl/Zastosowanie_modu\u0142\u00f3w_JavaScript" } ) }}
Revert to this revision