Bug 1314861: Lazily load UI modules, as much as possible. r?rpl draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 30 Oct 2016 16:54:43 -0700
changeset 433093 2a3f7b7d6b3182a3272cfebf3f94e886d83da82f
parent 433092 531f125b08319f3b53c34b7f40c156f7640e0695
child 433094 a2648d98bbcc2299ed582188293fba8ea2697d43
push id34481
push usermaglione.k@gmail.com
push dateThu, 03 Nov 2016 03:45:04 +0000
reviewersrpl
bugs1314861
milestone52.0a1
Bug 1314861: Lazily load UI modules, as much as possible. r?rpl MozReview-Commit-ID: JdHHw639Lwv
addon-sdk/source/lib/sdk/ui.js
addon-sdk/source/lib/sdk/ui/button/action.js
addon-sdk/source/lib/sdk/ui/button/contract.js
addon-sdk/source/lib/sdk/ui/button/toggle.js
addon-sdk/source/lib/sdk/ui/button/view.js
addon-sdk/source/lib/sdk/ui/frame.js
addon-sdk/source/lib/sdk/ui/frame/model.js
addon-sdk/source/lib/sdk/ui/frame/view.js
addon-sdk/source/lib/sdk/ui/id.js
addon-sdk/source/lib/sdk/ui/sidebar.js
addon-sdk/source/lib/sdk/ui/sidebar/view.js
addon-sdk/source/lib/sdk/ui/state.js
addon-sdk/source/lib/sdk/ui/toolbar/view.js
--- a/addon-sdk/source/lib/sdk/ui.js
+++ b/addon-sdk/source/lib/sdk/ui.js
@@ -5,13 +5,21 @@
 
 module.metadata = {
   'stability': 'experimental',
   'engines': {
     'Firefox': '> 28'
   }
 };
 
-exports.ActionButton = require('./ui/button/action').ActionButton;
-exports.ToggleButton = require('./ui/button/toggle').ToggleButton;
-exports.Sidebar = require('./ui/sidebar').Sidebar;
-exports.Frame = require('./ui/frame').Frame;
-exports.Toolbar = require('./ui/toolbar').Toolbar;
+lazyRequire('./ui/button/action', 'ActionButton');
+lazyRequire('./ui/button/toggle', 'ToggleButton');
+lazyRequire('./ui/sidebar', 'Sidebar');
+lazyRequire('./ui/frame', 'Frame');
+lazyRequire('./ui/toolbar', 'Toolbar');
+
+module.exports = Object.freeze({
+  get ActionButton() { return ActionButton; },
+  get ToggleButton() { return ToggleButton; },
+  get Sidebar() { return Sidebar; },
+  get Frame() { return Frame; },
+  get Toolbar() { return Toolbar; },
+});
--- a/addon-sdk/source/lib/sdk/ui/button/action.js
+++ b/addon-sdk/source/lib/sdk/ui/button/action.js
@@ -8,32 +8,32 @@ module.metadata = {
   'engines': {
     'Firefox': '> 28'
   }
 };
 
 const { Class } = require('../../core/heritage');
 const { merge } = require('../../util/object');
 const { Disposable } = require('../../core/disposable');
-const { on, off, emit, setListeners } = require('../../event/core');
+lazyRequire('../../event/core', "on", "off", "emit", "setListeners");
 const { EventTarget } = require('../../event/target');
-const { getNodeView } = require('../../view/core');
+lazyRequire('../../view/core', "getNodeView");
 
-const view = require('./view');
+lazyRequire({ './view': "view" });
 const { buttonContract, stateContract } = require('./contract');
-const { properties, render, state, register, unregister,
-        getDerivedStateFor } = require('../state');
-const { events: stateEvents } = require('../state/events');
-const { events: viewEvents } = require('./view/events');
-const events = require('../../event/utils');
+lazyRequire('../state', "properties", "render", "state", "register",
+            "unregister", "getDerivedStateFor");
+lazyRequire('../state/events', { "events": "stateEvents" });
+lazyRequire('./view/events', { "events": "viewEvents" });
+lazyRequire({ '../../event/utils': "events" });
 
-const { getActiveTab } = require('../../tabs/utils');
+lazyRequire('../../tabs/utils', "getActiveTab");
 
-const { id: addonID } = require('../../self');
-const { identify } = require('../id');
+lazyRequire('../../self', { "id": "addonID" });
+lazyRequire('../id', "identify");
 
 const buttons = new Map();
 
 const toWidgetId = id =>
   ('action-button--' + addonID.toLowerCase()+ '-' + id).
     replace(/[^a-z0-9_-]/g, '');
 
 const ActionButton = Class({
--- a/addon-sdk/source/lib/sdk/ui/button/contract.js
+++ b/addon-sdk/source/lib/sdk/ui/button/contract.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 const { contract } = require('../../util/contract');
-const { isLocalURL } = require('../../url');
-const { isNil, isObject, isString } = require('../../lang/type');
+lazyRequire('../../url', "isLocalURL");
+lazyRequire('../../lang/type', "isNil", "isObject", "isString");
 const { required, either, string, boolean, object, number } = require('../../deprecated/api-utils');
 const { merge } = require('../../util/object');
 const { freeze } = Object;
 
 const isIconSet = (icons) =>
   Object.keys(icons).
     every(size => String(size >>> 0) === size && isLocalURL(icons[size]));
 
--- a/addon-sdk/source/lib/sdk/ui/button/toggle.js
+++ b/addon-sdk/source/lib/sdk/ui/button/toggle.js
@@ -6,34 +6,34 @@
 module.metadata = {
   'stability': 'experimental',
   'engines': {
     'Firefox': '> 28'
   }
 };
 
 const { Class } = require('../../core/heritage');
-const { merge } = require('../../util/object');
+lazyRequire('../../util/object', "merge");
 const { Disposable } = require('../../core/disposable');
-const { on, off, emit, setListeners } = require('../../event/core');
+lazyRequire('../../event/core', "on", "off", "emit", "setListeners");
 const { EventTarget } = require('../../event/target');
-const { getNodeView } = require('../../view/core');
+lazyRequire('../../view/core', "getNodeView");
 
-const view = require('./view');
+lazyRequire({ "./view": "view" });
 const { toggleButtonContract, toggleStateContract } = require('./contract');
-const { properties, render, state, register, unregister,
-  setStateFor, getStateFor, getDerivedStateFor } = require('../state');
-const { events: stateEvents } = require('../state/events');
-const { events: viewEvents } = require('./view/events');
-const events = require('../../event/utils');
+lazyRequire('../state', "properties", "render", "state", "register", "unregister",
+            "setStateFor", "getStateFor", "getDerivedStateFor");
+lazyRequire('../state/events', { "events": "stateEvents" });
+lazyRequire('./view/events', { "events": "viewEvents" });
+lazyRequire({ '../../event/utils': "events" });
 
-const { getActiveTab } = require('../../tabs/utils');
+lazyRequire('../../tabs/utils', "getActiveTab");
 
-const { id: addonID } = require('../../self');
-const { identify } = require('../id');
+lazyRequire('../../self', { "id": "addonID" });
+lazyRequire('../id', "identify");
 
 const buttons = new Map();
 
 const toWidgetId = id =>
   ('toggle-button--' + addonID.toLowerCase()+ '-' + id).
     replace(/[^a-z0-9_-]/g, '');
 
 const ToggleButton = Class({
--- a/addon-sdk/source/lib/sdk/ui/button/view.js
+++ b/addon-sdk/source/lib/sdk/ui/button/view.js
@@ -6,28 +6,28 @@
 module.metadata = {
   'stability': 'experimental',
   'engines': {
     'Firefox': '> 28'
   }
 };
 
 const { Cu } = require('chrome');
-const { on, off, emit } = require('../../event/core');
+lazyRequire('../../event/core', "on", "off", "emit");
 
-const { data } = require('sdk/self');
+lazyRequire('sdk/self', "data");
 
-const { isObject, isNil } = require('../../lang/type');
+lazyRequire('../../lang/type', "isObject", "isNil");
 
-const { getMostRecentBrowserWindow } = require('../../window/utils');
-const { ignoreWindow } = require('../../private-browsing/utils');
+lazyRequire('../../window/utils', "getMostRecentBrowserWindow");
+lazyRequire('../../private-browsing/utils', "ignoreWindow");
 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
 const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI;
 
-const { events: viewEvents } = require('./view/events');
+lazyRequire('./view/events', { "events": "viewEvents" });
 
 const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
 
 const views = new Map();
 const customizedWindows = new WeakMap();
 
 const buttonListener = {
   onCustomizeStart: window => {
--- a/addon-sdk/source/lib/sdk/ui/frame.js
+++ b/addon-sdk/source/lib/sdk/ui/frame.js
@@ -5,12 +5,11 @@
 
 module.metadata = {
   "stability": "experimental",
   "engines": {
     "Firefox": "> 28"
   }
 };
 
-require("./frame/view");
 const { Frame } = require("./frame/model");
 
 exports.Frame = Frame;
--- a/addon-sdk/source/lib/sdk/ui/frame/model.js
+++ b/addon-sdk/source/lib/sdk/ui/frame/model.js
@@ -7,29 +7,29 @@ module.metadata = {
   "stability": "experimental",
   "engines": {
     "Firefox": "> 28"
   }
 };
 
 const { Class } = require("../../core/heritage");
 const { EventTarget } = require("../../event/target");
-const { emit, off, setListeners } = require("../../event/core");
+lazyRequire("../../event/core", "emit", "off", "setListeners");
 const { Reactor, foldp, send, merges } = require("../../event/utils");
 const { Disposable } = require("../../core/disposable");
 const { OutputPort } = require("../../output/system");
-const { InputPort } = require("../../input/system");
-const { identify } = require("../id");
-const { pairs, object, map, each } = require("../../util/sequence");
-const { patch, diff } = require("diffpatcher/index");
-const { isLocalURL } = require("../../url");
+lazyRequire("../id", "identify");
+const { pairs, object, each } = require("../../util/sequence");
+lazyRequire("diffpatcher/index", "patch", "diff");
+lazyRequire("../../url", "isLocalURL");
 const { compose } = require("../../lang/functional");
 const { contract } = require("../../util/contract");
 const { id: addonID, data: { url: resolve }} = require("../../self");
 const { Frames } = require("../../input/frame");
+require("./view");
 
 
 const output = new OutputPort({ id: "frame-change" });
 const mailbox = new OutputPort({ id: "frame-mailbox" });
 const input = Frames;
 
 
 const makeID = url =>
--- a/addon-sdk/source/lib/sdk/ui/frame/view.js
+++ b/addon-sdk/source/lib/sdk/ui/frame/view.js
@@ -7,26 +7,23 @@ module.metadata = {
   "stability": "experimental",
   "engines": {
     "Firefox": "> 28"
   }
 };
 
 const { Cu, Ci } = require("chrome");
 const { CustomizableUI } = Cu.import('resource:///modules/CustomizableUI.jsm', {});
-const { subscribe, send, Reactor, foldp, lift, merges, keepIf } = require("../../event/utils");
-const { InputPort } = require("../../input/system");
+const { send, Reactor } = require("../../event/utils");
 const { OutputPort } = require("../../output/system");
-const { LastClosed } = require("../../input/browser");
-const { pairs, keys, object, each } = require("../../util/sequence");
+lazyRequire("../../util/sequence", "pairs", "keys", "object", "each");
 const { curry, compose } = require("../../lang/functional");
-const { getFrameElement, getOuterId,
-        getByOuterId, getOwnerBrowserWindow } = require("../../window/utils");
-const { patch, diff } = require("diffpatcher/index");
-const { encode } = require("../../base64");
+lazyRequire("../../window/utils", "getFrameElement", "getOuterId", "getByOuterId", "getOwnerBrowserWindow");
+lazyRequire("diffpatcher/index", "patch", "diff");
+lazyRequire("../../base64", "encode");
 const { Frames } = require("../../input/frame");
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const OUTER_FRAME_URI = module.uri.replace(/\.js$/, ".html");
 
 const mailbox = new OutputPort({ id: "frame-mailbox" });
 
--- a/addon-sdk/source/lib/sdk/ui/id.js
+++ b/addon-sdk/source/lib/sdk/ui/id.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   'stability': 'experimental'
 };
 
 const method = require('../../method/core');
-const { uuid } = require('../util/uuid');
+lazyRequire('../util/uuid', "uuid");
 
 // NOTE: use lang/functional memoize when it is updated to use WeakMap
 function memoize(f) {
   const memo = new WeakMap();
 
   return function memoizer(o) {
     let key = o;
     if (!memo.has(key))
--- a/addon-sdk/source/lib/sdk/ui/sidebar.js
+++ b/addon-sdk/source/lib/sdk/ui/sidebar.js
@@ -8,46 +8,43 @@ module.metadata = {
   'engines': {
     'Firefox': '*'
   }
 };
 
 const { Class } = require('../core/heritage');
 const { merge } = require('../util/object');
 const { Disposable } = require('../core/disposable');
-const { off, emit, setListeners } = require('../event/core');
+lazyRequire('../event/core', "off", "emit", "setListeners");
 const { EventTarget } = require('../event/target');
-const { URL } = require('../url');
-const { add, remove, has, clear, iterator } = require('../lang/weak-set');
-const { id: addonID, data } = require('../self');
-const { WindowTracker } = require('../deprecated/window-utils');
-const { isShowing } = require('./sidebar/utils');
-const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../window/utils');
+lazyRequire('../url', "URL");
+lazyRequire('../self', { "id": "addonID" }, "data");
+lazyRequire('../deprecated/window-utils', 'WindowTracker');
+lazyRequire('./sidebar/utils', "isShowing");
+lazyRequire('../window/utils', "isBrowser", "getMostRecentBrowserWindow", "windows", "isWindowPrivate");
 const { ns } = require('../core/namespace');
-const { remove: removeFromArray } = require('../util/array');
-const { show, hide, toggle } = require('./sidebar/actions');
-const { Worker } = require('../deprecated/sync-worker');
+lazyRequire('../util/array', { "remove": "removeFromArray" });
+lazyRequire('./sidebar/actions', "show", "hide", "toggle");
+lazyRequire('../deprecated/sync-worker', "Worker");
 const { contract: sidebarContract } = require('./sidebar/contract');
-const { create, dispose, updateTitle, updateURL, isSidebarShowing, showSidebar, hideSidebar } = require('./sidebar/view');
-const { defer } = require('../core/promise');
-const { models, views, viewsFor, modelFor } = require('./sidebar/namespace');
-const { isLocalURL } = require('../url');
+lazyRequire('./sidebar/view', "create", "dispose", "updateTitle", "updateURL", "isSidebarShowing", "showSidebar", "hideSidebar");
+lazyRequire('../core/promise', "defer");
+lazyRequire('./sidebar/namespace', "models", "views", "viewsFor", "modelFor");
+lazyRequire('../url', "isLocalURL");
 const { ensure } = require('../system/unload');
-const { identify } = require('./id');
-const { uuid } = require('../util/uuid');
-const { viewFor } = require('../view/core');
+lazyRequire('./id', "identify");
+lazyRequire('../util/uuid', "uuid");
+lazyRequire('../view/core', "viewFor");
 
 const resolveURL = (url) => url ? data.url(url) : url;
 
 const sidebarNS = ns();
 
 const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
 
-var sidebars = {};
-
 const Sidebar = Class({
   implements: [ Disposable ],
   extends: EventTarget,
   setup: function(options) {
     // inital validation for the model information
     let model = sidebarContract(options);
 
     // save the model information
@@ -204,18 +201,16 @@ const Sidebar = Class({
         if (windowNS(window).onWebPanelSidebarUnload) {
           panelBrowser && panelBrowser.contentWindow.removeEventListener('unload', windowNS(window).onWebPanelSidebarUnload, true);
           windowNS(window).onWebPanelSidebarUnload();
         }
       }
     });
 
     views.set(this, bars);
-
-    add(sidebars, this);
   },
   get id() {
     return (modelFor(this) || {}).id;
   },
   get title() {
     return (modelFor(this) || {}).title;
   },
   set title(v) {
@@ -254,18 +249,16 @@ const Sidebar = Class({
   hide: function(window) {
     return hideSidebar(viewFor(window), this);
   },
   dispose: function() {
     const internals = sidebarNS(this);
 
     off(this);
 
-    remove(sidebars, this);
-
     // stop tracking windows
     if (internals.tracker) {
       internals.tracker.unload();
     }
 
     internals.tracker = null;
     internals.windowNS = null;
 
--- a/addon-sdk/source/lib/sdk/ui/sidebar/view.js
+++ b/addon-sdk/source/lib/sdk/ui/sidebar/view.js
@@ -5,21 +5,21 @@
 
 module.metadata = {
   'stability': 'unstable',
   'engines': {
     'Firefox': '*'
   }
 };
 
-const { models, buttons, views, viewsFor, modelFor } = require('./namespace');
-const { isBrowser, getMostRecentBrowserWindow, windows, isWindowPrivate } = require('../../window/utils');
-const { setStateFor } = require('../state');
-const { defer } = require('../../core/promise');
-const { isPrivateBrowsingSupported, data } = require('../../self');
+lazyRequire('./namespace', "models", "buttons", "views", "viewsFor", "modelFor");
+lazyRequire('../../window/utils', "isBrowser", "getMostRecentBrowserWindow", "windows", "isWindowPrivate");
+lazyRequire('../state', "setStateFor");
+lazyRequire('../../core/promise', "defer");
+lazyRequire('../../self', "isPrivateBrowsingSupported", "data");
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const WEB_PANEL_BROWSER_ID = 'web-panels-browser';
 
 const resolveURL = (url) => url ? data.url(url) : url;
 
 function create(window, details) {
   let id = makeID(details.id);
--- a/addon-sdk/source/lib/sdk/ui/state.js
+++ b/addon-sdk/source/lib/sdk/ui/state.js
@@ -16,29 +16,29 @@ module.metadata = {
 
 const { Ci } = require('chrome');
 
 const events = require('../event/utils');
 const { events: browserEvents } = require('../browser/events');
 const { events: tabEvents } = require('../tab/events');
 const { events: stateEvents } = require('./state/events');
 
-const { windows, isInteractive, getFocusedBrowser } = require('../window/utils');
-const { getActiveTab, getOwnerWindow } = require('../tabs/utils');
+lazyRequire('../window/utils', "windows", "isInteractive", "getFocusedBrowser");
+lazyRequire('../tabs/utils', "getActiveTab", "getOwnerWindow");
 
-const { ignoreWindow } = require('../private-browsing/utils');
+lazyRequire('../private-browsing/utils', "ignoreWindow");
 
 const { freeze } = Object;
 const { merge } = require('../util/object');
-const { on, off, emit } = require('../event/core');
+lazyRequire('../event/core', "on", "off", "emit");
 
-const { add, remove, has, clear, iterator } = require('../lang/weak-set');
-const { isNil } = require('../lang/type');
+lazyRequire('../lang/weak-set', "add", "remove", "has", "clear", "iterator");
+lazyRequire('../lang/type', "isNil");
 
-const { viewFor } = require('../view/core');
+lazyRequire('../view/core', "viewFor");
 
 const components = new WeakMap();
 
 const ERR_UNREGISTERED = 'The state cannot be set or get. ' +
   'The object may be not be registered, or may already have been unloaded.';
 
 const ERR_INVALID_TARGET = 'The state cannot be set or get for this target.' +
   'Only window, tab and registered component are valid targets.';
--- a/addon-sdk/source/lib/sdk/ui/toolbar/view.js
+++ b/addon-sdk/source/lib/sdk/ui/toolbar/view.js
@@ -15,20 +15,20 @@ const { CustomizableUI } = Cu.import('re
 const { subscribe, send, Reactor, foldp, lift, merges } = require("../../event/utils");
 const { InputPort } = require("../../input/system");
 const { OutputPort } = require("../../output/system");
 const { Interactive } = require("../../input/browser");
 const { CustomizationInput } = require("../../input/customizable-ui");
 const { pairs, map, isEmpty, object,
         each, keys, values } = require("../../util/sequence");
 const { curry, flip } = require("../../lang/functional");
-const { patch, diff } = require("diffpatcher/index");
+lazyRequire("diffpatcher/index", "patch", "diff");
 const prefs = require("../../preferences/service");
-const { getByOuterId } = require("../../window/utils");
-const { ignoreWindow } = require('../../private-browsing/utils');
+lazyRequire("../../window/utils", "getByOuterId");
+lazyRequire('../../private-browsing/utils', "ignoreWindow");
 
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const PREF_ROOT = "extensions.sdk-toolbar-collapsed.";
 
 
 // There are two output ports one for publishing changes that occured
 // and the other for change requests. Later is synchronous and is only
 // consumed here. Note: it needs to be synchronous to avoid race conditions