Mozilla's getting a new look. What do you think? https://mzl.la/brandsurvey

JavaScript コードモジュールの利用

この翻訳は不完全です。英語から この記事を翻訳 してください。

JavaScript コードモジュールは、Gecko 1.9 で導入されたコンセプトであり、特権を持った異なるスコープ間でコードを共有するために用いられます。また、モジュールは、グローバルな JavaScript のシングルトンオブジェクトを生成するために用いることもできます (以前は JavaScript XPCOM オブジェクトを使う必要がありました)。 JavaScript コードモジュールは、登録されたパスに配置された純粋な JavaScript のコードです。Components.utils.import()Components.utils["import"]() を使って、 XUL スクリプトや JavaScript XPCOM スクリプトのような特定の JavaScript のスコープへモジュールを読み込むことができます。

JavaScript コードモジュールの作成

とても単純な JavaScript モジュールの例を以下に示します。

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

function foo() {
  return "foo";
}

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

var dummy = "dummy";

モジュールが普通の JavaScript を使って、関数、オブジェクト、定数、その他あらゆる JavaScript の型のオブジェクトを生成していることに注目してください。また、モジュールは EXPORTED_SYMBOLS という名前の特別な Array を定義します。 EXPORTED_SYMBOLS 内で命名されたすべての JavaScript オブジェクトは、モジュールからエクスポートされてインポート先のスコープ内で使用可能となります。以下に例を示します。

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

alert(foo());         // "foo" と表示される
alert(bar.size + 3);  // "6" と表示される
alert(dummy);         // 'dummy' はモジュールからエクスポートされないため、"dummy is not defined" と表示される

Note: あなたがコードモジュールにテスト変更を加えたとき、実行する前にアプリケーションビルドID(例、バージョンなど) が変わっているかどうか確認してください。 otherwise, you may find yourself running the previous version of your module's code.

code moduleのURL

上記のサンプルからわかる通り、コードモジュールをインポートするためにはURLが必要となります。(上の例ではURLは"resource://app/my_module.jsm"となっています)

Code modulesはchrome: (), resource:, or file: URLのどれかを使用してのみロードすることができます。

  • If you're writing an extension for Firefox 4 and already have a chrome.manifest with a content instruction in it, you can put the code module in your content folder and reference it like your other content files via chrome://<yourextension>/content/<yourmodule>.jsm.
  • If your extension or application needs to support Mozilla 1.9.x (Firefox 3.x), you should register a new resource URL. Details on doing this are in the "Extending resource: URLs" section below.

Sharing objects using code modules

Components.utils.import() の動作の非常に重要な点は、モジュールが読み込まれた時点でキャッシュされ、次のインポート時には、新しいバージョンのモジュールを再び読み込むことなく、以前にキャッシュされたバージョンを使用するということです。これは、モジュールが複数回インポートされた時に共有されることを意味します。モジュールをインポートしたあらゆるスコープ内で、データ、オブジェクト、関数の変更が可能となります。例えば、単一のモジュールが異なる 2 つの JavaScript のスコープ内へインポートされた場合、一方のスコープでの変更は他方のスコープにも影響します。

スコープ 1:

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

alert(bar.size + 3);  // "6" と表示される

bar.size = 10;

スコープ 2:

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

alert(foo());         // "foo" と表示される
alert(bar.size + 3);  // "13" と表示される

このような共有の動作によって、ウィンドウや XUL スクリプト、XPCOM コンポーネントをまたいでデータを共有できるシングルトンのオブジェクトを生成することが可能となります。

註: モジュールをインポートしたスコープごとに、そのモジュールでエクスポートされたシンボルの by-value コピーを受け取ります。シンボルの値の変更は他のスコープに伝搬することはありません。

スコープ 1:

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

bar = "foo";
alert(bar);         // "foo" と表示される

スコープ 2:

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

alert(bar);         // "[object Object]" と表示される

by-value コピーの主な効果は単純型のグローバル変数がスコープを横断して共有されないことです。常にラッパークラスの中に変数を置いてラッパーをエクスポートします (上の例にある bar のように)。

Unloading code modules

Gecko 7.0 が必要(Firefox 7.0 / Thunderbird 7.0 / SeaMonkey 2.4)

Components.utils.unload() allows you to unload a previously imported code module. Once this method has been called, references to the module will continue to work but any subsequent import of the module will reload it and give a new reference.

Examples

コードモジュールの配置

Gecko 2.0 note
(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

Gecko 2.0 より前のバージョンでは、JavaScript コードモジュールは、file: または resource: URL のみを用いて読み込むことができました。 Gecko 2.0 では、chrome: URL からのモジュールの読み込みが追加されましたが、これらは JAR アーカイブ内に限られます。

Components.utils.import() を使用する場合、コードモジュールは、ディスク上のファイルを指し示すために file: または chrome:, resource: URL を使用して読み込まれなければなりません。

resource: URL の使用

Gecko 2.0 より前のバージョンでは、コードモジュールを読み込む最も一般的な方法は resource: URL を使用することでした。 resource URL の基本的な構文は以下のようになります:

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

<alias> は通常、アプリケーションや XUL ランタイムの相対的なファイルパスへのエイリアスです。 XUL ランタイムによって予め定義されたいくつかのエイリアスがあります:

  • app - XUL アプリケーションのパスへのエイリアス。
  • gre - XUL ランタイムのパスへのエイリアス。

<relative-path> は複数の階層とすることも可能で、常に <alias> で定義されたパスに対する相対パスとなります。一般的な相対パスは "modules" であり、 XUL Runner や Firefox にて使用されています。コードモジュールは拡張子 .js や .jsm の単一の JavaScript ファイルです。

<alias> must be unique to your add-on, as the application and other extensions share the same namespace for all aliases.

chrome.manifestを使う

拡張機能や XUL アプリケーションへ独自のエイリアスを追加する最も簡単な方法は、 chrome manifest 内の以下のような行によって登録することです:

resource aliasname uri/to/files/

例えば、拡張機能 foo の XPI ファイルがモジュール bar.js を含むトップレベルの modules/ ディレクトリを有する場合 (つまり、modules/ ディレクトリが chrome.manifestinstall.rdf の兄弟)、以下の命令によってそのディレクトリへのエイリアスを作ることができます:

resource foo modules/

(末尾のスラッシュを忘れないこと!) すると、以下の一文でモジュールを JavaScript コードへインポートできるようになります:

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

プログラムによるエイリアスの追加

nsILocalFile として表せるパスへの独自のエイリアスをプログラムによって追加することもできます。以下に例を示します。

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

// コードモジュールはサブフォルダではなくエイリアスフォルダ直下にあるとする

Notes

カスタムモジュールと XPCOM コンポーネント

Gecko 2.0 より前のバージョンでは、JavaScript XPCOM コンポーネントは、chrome が登録される前に読み込まれることに注意してください。これは、コンポーネントソース内のトップレベルにおいて独自の resource URL で Components.utils.import() が使用できないことを意味します。可能な解決策は、Components.utils.import() の呼び出しを XPCOM コンポーネントのコンストラクタ内に移動することです (このことについての議論を参照してください)。

Packaging notes

It's important to note that you should not typically put your JavaScript code modules in a JAR file in your add-on. Firefox 3.6 doesn't support them at all, and there's only one case in which it's remotely useful: a Firefox 4-only add-on which must be installed unpacked. Otherwise placing code modules in a JAR file breaks compatibility unnecessarily.

Importing CommonJS modules

The JavaScript code modules described here are not the same thing as CommonJS modules, but you can import CommonJS modules into any scope where you can use Components.utils.import. Just call the following:

const { require } = Cu.import("resource://gre/modules/commonjs/toolkit/require.js", {})

This will import require() into your scope.

You can then use that to import CommonJS modules. You can import Add-on SDK modules in just the same way you could from an SDK add-on:

// import the SDK's base64 module

var base64 = require("sdk/base64");
base64.encode("hello"); // "aGVsbG8="

You can import other CommonJS modules, too, as long as you know the path to them:

// import my module

var myModule = require("resource://path/to/my/module.js");

In this case, though, you might be better off creating your own loader, so you can specify the paths property yourself.

関連項目

ドキュメントのタグと貢献者

 このページの貢献者: lv7777, ethertank, hiiragi77, Marsf
 最終更新者: lv7777,