Les modules de code JavaScript sont un concept introduit dans Firefox 3 (Gecko 1.9) et peuvent être utilisés pour partager du code entre différentes visibilités privilégiées. On peut également utiliser des modules pour créer des singletons JavaScript globaux pour lesquels on avait auparavant besoin d'objets XPCOM JavaScript. Un module de code JavaScript est simplement constitué de code JavaScript placé à un endroit enregistré. Celui-ci est chargé dans une visibilité JavaScript particulière, comme un script XUL ou un script XPCOM JavaScript, à l'aide de Components.utils.import.
Un module JavaScript très simple ressemble à ceci :
var EXPORTED_SYMBOLS = ["foo", "bar"] function foo() { return "foo"; } var bar = { nom : "bar", taille : "3" }; var brol = "brol";
Remarquez que le module utilise du JavaScript tout à fait normal pour créer des fonctions, objets, constantes et tout autre type JavaScript. Le module définit également un tableau spécial appelé EXPORTED_SYMBOLS
. Tout élément JavaScript présent dans EXPORTED_SYMBOLS
sera exporté depuis le module et injecté dans la visibilité qui l'importe. Par exemple :
Components.utils.import("resource://app/modules/mon_module.jsm"); alert(foo()); // affiche "foo" alert(bar.taille + 3); // affiche "6" alert(brol); // affiche « brol n'est pas défini » car « brol » n'a pas été exporté par le module
Une caractéristique très importante du comportement de Components.utils.import est que les modules sont mis en cache lorsqu'il sont chargés et que les importations ultérieures ne rechargent pas une nouvelle version du module, mais utiliseront la version précédemment mise en cache. Cela signifie qu'un module donné sera partagé lorsqu'il est importé plusieurs fois. par exemple, si le module présenté plus haut était importé dans deux visibilités JavaScript différentes, les changements dans l'une pourraient être observés dans l'autre.
Visibilité 1 :
Components.utils.import("resource://app/modules/mon_module.jsm"); alert(bar.taille + 3); // affiche "6" bar.taille = 10;
Visibilité 2:
Components.utils.import("resource://app/modules/mon_module.jsm"); alert(foo()); // affiche "foo" alert(bar.taille + 3); // affiche "13"
Ce comportement partagé peut être utilisé pour créer des objets singletons pouvant partager des données entre fenêtres et entre scripts XUL et composants XPCOM.
Le protocole resource:
En utilisant Components.utils.import, vous remarquerez que les modules de code sont chargés à l'aide d'un protocole « resource:// ». La syntaxe de base d'une URL de ressource est la suivante :
resource://<alias>/<chemin-relatif>/<fichier.js|jsm>
La partie <alias>
est un alias vers un emplacement, généralement un emplacement physique relatif à l'application ou à l'environnement d'exécution XUL. Différents alias sont prédéfinis par l'environnement d'exécution XUL :
app
— Alias vers l'emplacement de l'application XUL.gre
— Alias vers l'emplacement de l'environnement d'exécution XUL.
La partie <chemin-relatif>
peut avoir plusieurs niveaux de profondeur et est toujours relative à l'emplacement défini par l'<alias>
. Le chemin relatif commun est « modules » et est utilisé par XULRunner et Firefox. Les fichiers de modules sont de simples fichiers JavaScript avec une extension .js ou .jsm.
La manière la plus simple pour des extensions et applications XUL d'ajouter des alias personnalisés est d'enregistrer un alias dans le manifeste chrome à l'aide d'une ligne comme celle-ci :
resource nomalias uri/vers/fichiers/
Des alias personnalisés peuvent également être ajoutés programmatiquement au protocole resource. Par exemple:
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); // en supposant que les modules de code sont dans le dossier alias lui-même, pas un sous-dossier Components.utils.import("resource://myalias/file.jsm"); // ...