--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -36,17 +36,19 @@ const { join: pathJoin, normalize, dirna
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsIResProtocolHandler");
XPCOMUtils.defineLazyServiceGetter(this, "zipCache",
"@mozilla.org/libjar/zip-reader-cache;1",
"nsIZipReaderCache");
-XPCOMUtils.defineLazyGetter(this, "XulApp", () => {
+const { defineLazyGetter } = XPCOMUtils;
+
+defineLazyGetter(this, "XulApp", () => {
let xulappURI = module.uri.replace("toolkit/loader.js",
"sdk/system/xul-app.jsm");
return Cu.import(xulappURI, {});
});
// Define some shortcuts.
const bind = Function.call.bind(Function.bind);
const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
@@ -471,16 +473,20 @@ const load = iced(function load(loader,
// Create a new object in this sandbox, that will be used as
// the scope object for this particular module
sandbox = new loader.sharedGlobalSandbox.Object();
// Inject all expected globals in the scope object
getOwnIdentifiers(globals).forEach(function(name) {
descriptors[name] = getOwnPropertyDescriptor(globals, name)
descriptors[name].configurable = true;
});
+ descriptors.lazyRequire = {
+ configurable: true,
+ value: lazyRequire.bind(sandbox),
+ };
Object.defineProperties(sandbox, descriptors);
}
else {
sandbox = Sandbox({
name: module.uri,
prototype: Object.create(globals, descriptors),
wantXrays: false,
wantGlobalProperties: module.id == "sdk/indexed-db" ? ["indexedDB"] : [],
@@ -722,16 +728,41 @@ const resolveURI = iced(function resolve
if(stripped === "" || id === stripped || id.startsWith(stripped + "/")) {
return normalizeExt(id.replace(path, uri));
}
}
return null;
});
Loader.resolveURI = resolveURI;
+let moduleMap = new WeakMap();
+
+function lazyRequire(module, ...args) {
+ if (typeof module === "object") {
+ for (let [moduleId, prop] of Object.entries(module))
+ defineLazyGetter(this, prop, () => this.require(moduleId));
+
+ return;
+ }
+
+ if (!moduleMap.has(this))
+ moduleMap.set(this, {});
+ let modules = moduleMap.get(this);
+
+ defineLazyGetter(modules, module, () => this.require(module));
+
+ for (let props of args) {
+ if (typeof props !== "object")
+ props = {[props]: props};
+
+ for (let [fromName, toName] of Object.entries(props))
+ defineLazyGetter(this, toName, () => modules[module][fromName]);
+ }
+}
+
// Creates version of `require` that will be exposed to the given `module`
// in the context of the given `loader`. Each module gets own limited copy
// of `require` that is allowed to load only a modules that are associated
// with it during link time.
const Require = iced(function Require(loader, requirer) {
let {
modules, mapping, resolve: loaderResolve, load,
manifest, rootURI, isNative, requireMap,