зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1803678 - enable lazy loading of ESModule based moz- custom elements r=reusable-components-reviewers,pip-reviewers,credential-management-reviewers,translations-reviewers,kpatenio,issammani,mstriemer
Differential Revision: https://phabricator.services.mozilla.com/D207445
This commit is contained in:
Родитель
ccc7e6a6a1
Коммит
36a699b418
|
@ -618,7 +618,6 @@ var gXPInstallObserver = {
|
|||
break;
|
||||
}
|
||||
case "addon-install-blocked": {
|
||||
await window.ensureCustomElements("moz-support-link");
|
||||
// Dismiss the progress notification. Note that this is bad if
|
||||
// there are multiple simultaneous installs happening, see
|
||||
// bug 1329884 for a longer explanation.
|
||||
|
@ -1955,8 +1954,6 @@ var gUnifiedExtensions = {
|
|||
supportPage = null,
|
||||
type = "warning",
|
||||
}) {
|
||||
window.ensureCustomElements("moz-message-bar");
|
||||
|
||||
const messageBar = document.createElement("moz-message-bar");
|
||||
messageBar.setAttribute("type", type);
|
||||
messageBar.classList.add("unified-extensions-message-bar");
|
||||
|
@ -1964,8 +1961,6 @@ var gUnifiedExtensions = {
|
|||
messageBar.setAttribute("data-l10n-attrs", "heading, message");
|
||||
|
||||
if (supportPage) {
|
||||
window.ensureCustomElements("moz-support-link");
|
||||
|
||||
const supportUrl = document.createElement("a", {
|
||||
is: "moz-support-link",
|
||||
});
|
||||
|
|
|
@ -55,7 +55,6 @@ var StarUI = {
|
|||
delete this.panel;
|
||||
this._createPanelIfNeeded();
|
||||
var element = this._element("editBookmarkPanel");
|
||||
window.ensureCustomElements("moz-button-group");
|
||||
// initially the panel is hidden
|
||||
// to avoid impacting startup / new window performance
|
||||
element.hidden = false;
|
||||
|
|
|
@ -177,7 +177,6 @@ var gIdentityHandler = {
|
|||
|
||||
_popupInitialized: false,
|
||||
_initializePopup() {
|
||||
window.ensureCustomElements("moz-support-link");
|
||||
if (!this._popupInitialized) {
|
||||
let wrapper = document.getElementById("template-identity-popup");
|
||||
wrapper.replaceWith(wrapper.content);
|
||||
|
|
|
@ -14,9 +14,6 @@ var gPermissionPanel = {
|
|||
if (!this._popupInitialized) {
|
||||
let wrapper = document.getElementById("template-permission-popup");
|
||||
wrapper.replaceWith(wrapper.content);
|
||||
|
||||
window.ensureCustomElements("moz-support-link");
|
||||
|
||||
this._popupInitialized = true;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1377,7 +1377,6 @@ var gProtectionsHandler = {
|
|||
let wrapper = document.getElementById("template-protections-popup");
|
||||
this._protectionsPopup = wrapper.content.firstElementChild;
|
||||
wrapper.replaceWith(wrapper.content);
|
||||
window.ensureCustomElements("moz-support-link");
|
||||
|
||||
this.maybeSetMilestoneCounterText();
|
||||
|
||||
|
@ -1591,8 +1590,6 @@ var gProtectionsHandler = {
|
|||
|
||||
// Add an observer to observe that the history has been cleared.
|
||||
Services.obs.addObserver(this, "browser:purge-session-history");
|
||||
|
||||
window.ensureCustomElements("moz-button-group", "moz-toggle");
|
||||
},
|
||||
|
||||
uninit() {
|
||||
|
|
|
@ -24,6 +24,7 @@ Test the confirmation-dialog component
|
|||
</pre>
|
||||
<script>
|
||||
/** Test the confirmation-dialog component **/
|
||||
let isWin = navigator.platform.includes("Win");
|
||||
|
||||
let options = {
|
||||
title: "confirm-delete-dialog-title",
|
||||
|
@ -65,7 +66,7 @@ add_task(async function test_initial_focus() {
|
|||
add_task(async function test_tab_focus() {
|
||||
gConfirmationDialog.show(options);
|
||||
ok(!gConfirmationDialog.hidden, "The dialog should be visible");
|
||||
sendKey("TAB");
|
||||
synthesizeKey("VK_TAB", { shiftKey: !isWin });
|
||||
is(gConfirmationDialog.shadowRoot.activeElement, cancelButton,
|
||||
"After opening the dialog and tabbing once, the cancel button should be focused");
|
||||
gConfirmationDialog.hide();
|
||||
|
@ -86,7 +87,7 @@ add_task(async function test_enter_key_to_cancel() {
|
|||
add_task(async function test_enter_key_to_confirm() {
|
||||
let showPromise = gConfirmationDialog.show(options);
|
||||
ok(!gConfirmationDialog.hidden, "The dialog should be visible");
|
||||
sendKey("TAB");
|
||||
synthesizeKey("VK_TAB", { shiftKey: !isWin });
|
||||
sendKey("RETURN");
|
||||
try {
|
||||
await showPromise;
|
||||
|
|
|
@ -403,7 +403,6 @@ export const ContentAnalysis = {
|
|||
},
|
||||
|
||||
async showPanel(element, panelUI) {
|
||||
element.ownerGlobal.ensureCustomElements("moz-support-link");
|
||||
await element.ownerDocument.l10n.setAttributes(
|
||||
lazy.PanelMultiView.getViewNode(
|
||||
element.ownerDocument,
|
||||
|
|
|
@ -150,7 +150,6 @@ add_setup(async function () {
|
|||
gLink.innerText = "gLink";
|
||||
gLink.id = "gLink";
|
||||
gMainView.appendChild(gLink);
|
||||
await window.ensureCustomElements("moz-toggle");
|
||||
gToggle = document.createElement("moz-toggle");
|
||||
gToggle.label = "Test label";
|
||||
gMainView.appendChild(gToggle);
|
||||
|
|
|
@ -97,8 +97,6 @@ var DownloadsPanel = {
|
|||
|
||||
window.addEventListener("unload", this.onWindowUnload);
|
||||
|
||||
window.ensureCustomElements("moz-button-group");
|
||||
|
||||
// Load and resume active downloads if required. If there are downloads to
|
||||
// be shown in the panel, they will be loaded asynchronously.
|
||||
DownloadsCommon.initializeAllDataLinks();
|
||||
|
|
|
@ -235,8 +235,6 @@ export class ExtensionControlledPopup {
|
|||
return;
|
||||
}
|
||||
|
||||
win.ownerGlobal.ensureCustomElements("moz-support-link");
|
||||
|
||||
// Find the elements we need.
|
||||
let doc = win.document;
|
||||
let panel = ExtensionControlledPopup._getAndMaybeCreatePanel(doc);
|
||||
|
|
|
@ -23,8 +23,6 @@ class ScreenshotsPreview extends HTMLElement {
|
|||
// we get passed the <browser> as a param via TabDialogBox.open()
|
||||
this.openerBrowser = window.arguments[0];
|
||||
|
||||
window.ensureCustomElements("moz-button");
|
||||
|
||||
let [downloadKey, copyKey] =
|
||||
lazy.screenshotsLocalization.formatMessagesSync([
|
||||
{ id: "screenshots-component-download-key" },
|
||||
|
|
|
@ -30,8 +30,8 @@ Please refer to the existing [UA widgets documentation](https://firefox-source-d
|
|||
|
||||
### How to use existing Mozilla Custom Elements
|
||||
|
||||
The existing Mozilla Custom Elements are automatically imported into all chrome privileged documents.
|
||||
These existing elements do not need to be imported individually via `<script>` tag or by using `window.ensureCustomElements()` when in a privileged main process document.
|
||||
The existing Mozilla Custom Elements are either [automatically imported](https://searchfox.org/mozilla-central/rev/d23849dd6d83edbe681d3b4828700256ea34a654/toolkit/content/customElements.js#853-878) into all chrome privileged documents, or are [lazy loaded](https://searchfox.org/mozilla-central/rev/d23849dd6d83edbe681d3b4828700256ea34a654/toolkit/content/customElements.js#789-809) and get automatically imported when first used.
|
||||
In either case, these existing elements do not need to be imported individually via `<script>` tag.
|
||||
As long as you are working in a chrome privileged document, you will have access to the existing Mozilla Custom Elements.
|
||||
You can dynamically create one of the existing custom elements by using `document.createDocument("customElement)` or `document.createXULElement("customElement")` in the relevant JS file, or by using the custom element tag in the relevant XHTML document.
|
||||
For example, `document.createXULElement("checkbox")` creates an instance of [widgets/checkbox.js](https://searchfox.org/mozilla-central/source/toolkit/content/widgets/checkbox.js) while using `<checkbox>` declares an instance in the XUL document.
|
||||
|
@ -74,11 +74,10 @@ Just like with the UI widgets, [the `browser_all_files_referenced.js` will fail
|
|||
|
||||
### Using new domain-specific widgets
|
||||
|
||||
This is effectively the same as [using new design system components](#using-new-design-system-components).
|
||||
You will need to import your widget into the relevant `html`/`xhtml` files via a `script` tag with `type="module"`:
|
||||
This is effectively the same as [using new design system components](#using-new-design-system-components). In general you should be able to rely on these elements getting lazily loaded at the time of first use, similar to how existing custom elements are imported.
|
||||
|
||||
Outside of chrome privileged documents you may need to import your widget into the relevant `html`/`xhtml` files via a `script` tag with `type="module"`:
|
||||
|
||||
```html
|
||||
<script type="module" src="chrome://browser/content/<domain-directory>/<your-widget>.mjs"></script>
|
||||
```
|
||||
|
||||
Or use `window.ensureCustomElements("<your-widget>")` as previously stated in [the using new design system components section.](#using-new-design-system-components)
|
||||
|
|
|
@ -111,17 +111,16 @@ by updating [this array](https://searchfox.org/mozilla-central/rev/5c922d8b93b43
|
|||
|
||||
Once you've added a new component to `toolkit/content/widgets` and created
|
||||
`chrome://` URLs via `toolkit/content/jar.mn` you should be able to start using it
|
||||
throughout Firefox. You can import the component into `html`/`xhtml` files via a
|
||||
throughout Firefox. In most cases, you should be able to rely on your custom element getting lazy loaded at the time of first use, provided you are working in a privileged context where `customElements.js` is available.
|
||||
|
||||
You can import the component directly into `html`/`xhtml` files via a
|
||||
`script` tag with `type="module"`:
|
||||
|
||||
```html
|
||||
<script type="module" src="chrome://global/content/elements/your-component-name.mjs"></script>
|
||||
```
|
||||
|
||||
If you are unable to import the new component in html, you can use [`ensureCustomElements()` in customElements.js](https://searchfox.org/mozilla-central/rev/31f5847a4494b3646edabbdd7ea39cb88509afe2/toolkit/content/customElements.js#865) in the relevant JS file.
|
||||
For example, [we use `window.ensureCustomElements("moz-button-group")` in `browser-siteProtections.js`](https://searchfox.org/mozilla-central/rev/31f5847a4494b3646edabbdd7ea39cb88509afe2/browser/base/content/browser-siteProtections.js#1749).
|
||||
**Note** you will need to add your new widget to [the switch in importCustomElementFromESModule](https://searchfox.org/mozilla-central/rev/85b4f7363292b272eb9b606e00de2c37a6be73f0/toolkit/content/customElements.js#845-859) for `ensureCustomElements()` to work as expected.
|
||||
Once [Bug 1803810](https://bugzilla.mozilla.org/show_bug.cgi?id=1803810) lands, this process will be simplified: you won't need to use `ensureCustomElements()` and you will [add your widget to the appropriate array in customElements.js instead of the switch statement](https://searchfox.org/mozilla-central/rev/85b4f7363292b272eb9b606e00de2c37a6be73f0/toolkit/content/customElements.js#818-841).
|
||||
**Note** you will need to add your new widget to [this array in customElements.js](https://searchfox.org/mozilla-central/rev/cde3d4a8d228491e8b7f1bd94c63bbe039850696/toolkit/content/customElements.js#791-810) to ensure it gets lazy loaded on creation.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
|
|
|
@ -1043,8 +1043,6 @@ var FullPageTranslationsPanel = new (class {
|
|||
isFirstUserInteraction = null,
|
||||
}
|
||||
) {
|
||||
await window.ensureCustomElements("moz-button-group");
|
||||
|
||||
const { panel, appMenuButton } = this.elements;
|
||||
const openedFromAppMenu = target.id === appMenuButton.id;
|
||||
const { docLangTag } = await this.#getCachedDetectedLanguages();
|
||||
|
@ -1109,10 +1107,6 @@ var FullPageTranslationsPanel = new (class {
|
|||
return;
|
||||
}
|
||||
|
||||
const window =
|
||||
gBrowser.selectedBrowser.browsingContext.top.embedderElement.ownerGlobal;
|
||||
window.ensureCustomElements("moz-support-link");
|
||||
|
||||
const { button } = this.buttonElements;
|
||||
|
||||
const { requestedTranslationPair } =
|
||||
|
|
|
@ -393,7 +393,7 @@ var SelectTranslationsPanel = new (class {
|
|||
);
|
||||
}
|
||||
|
||||
await this.#openPopup(event, screenX, screenY);
|
||||
this.#openPopup(event, screenX, screenY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -403,10 +403,7 @@ var SelectTranslationsPanel = new (class {
|
|||
* @param {number} screenX - The x-axis location of the screen at which to open the popup.
|
||||
* @param {number} screenY - The y-axis location of the screen at which to open the popup.
|
||||
*/
|
||||
async #openPopup(event, screenX, screenY) {
|
||||
await window.ensureCustomElements("moz-button-group");
|
||||
await window.ensureCustomElements("moz-message-bar");
|
||||
|
||||
#openPopup(event, screenX, screenY) {
|
||||
this.console?.log("Showing SelectTranslationsPanel");
|
||||
const { panel } = this.elements;
|
||||
panel.openPopupAtScreen(screenX, screenY, /* isContextMenu */ false, event);
|
||||
|
|
|
@ -339,8 +339,6 @@ export var ExtensionsUI = {
|
|||
async showPermissionsPrompt(target, strings, icon) {
|
||||
let { browser, window } = getTabBrowser(target);
|
||||
|
||||
await window.ensureCustomElements("moz-support-link");
|
||||
|
||||
// Wait for any pending prompts to complete before showing the next one.
|
||||
let pending;
|
||||
while ((pending = this.pendingNotifications.get(browser))) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[DEFAULT]
|
||||
support-files = ["dummy_page.html"]
|
||||
|
||||
["test_custom_element_ensure_custom_element.html"]
|
||||
["test_custom_element_auto_import.html"]
|
||||
|
||||
["test_custom_element_htmlconstructor_chrome.html"]
|
||||
support-files = [
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1813077
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for customElements.ensureCustomElement</title>
|
||||
<title>Test for custom element auto import behavior</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script>
|
||||
|
@ -14,36 +11,33 @@
|
|||
outside of the task that imported them. This can create issues if writing
|
||||
another test in this file.
|
||||
*/
|
||||
add_task(async function test_ensure_custom_elements() {
|
||||
add_task(async function test_custom_elements_auto_import() {
|
||||
let registry = SpecialPowers.wrap(customElements);
|
||||
ok(window.ensureCustomElements, "should be defined");
|
||||
|
||||
// Ensure the custom elements from ESModules are not defined.
|
||||
is(registry.get("moz-button-group"), undefined, "moz-button-group should be undefined since we have not yet imported it");
|
||||
is(registry.get("moz-support-link"), undefined, "moz-support-link should be undefined since we have not yet imported it");
|
||||
is(registry.get("moz-toggle"), undefined, "moz-toggle should be undefined since we have not yet imported it");
|
||||
|
||||
// Import a single custom element and assert it exists in the custom
|
||||
// element registry
|
||||
let modules = await window.ensureCustomElements("moz-support-link");
|
||||
ok(registry.get("moz-support-link"), "moz-support-link should be defined after importing it");
|
||||
is(modules, null, "There should not be a return value when using ensureCustomElements");
|
||||
// Create a custom element and assert that it gets imported/defined.
|
||||
document.createElement("moz-support-link");
|
||||
ok(registry.get("moz-support-link"), "moz-support-link should be defined after creation");
|
||||
|
||||
// Import multiple custom elements and assert they exist in the registry
|
||||
modules = undefined;
|
||||
// Create multiple custom elements and assert they exist in the registry.
|
||||
is(registry.get("moz-button-group"), undefined, "moz-button-group should be undefined since we have not yet imported it");
|
||||
is(registry.get("moz-toggle"), undefined, "moz-toggle should be undefined since we have not yet imported it")
|
||||
modules = await window.ensureCustomElements("moz-toggle", "moz-button-group");
|
||||
is(modules, null, "There should not be a return value when using ensureCustomElements");
|
||||
|
||||
document.createElement("moz-button-group");
|
||||
document.createElement("moz-toggle");
|
||||
|
||||
ok(registry.get("moz-toggle"), "moz-toggle should be defined after importing it");
|
||||
ok(registry.get("moz-button-group"), "moz-button-group should be defined after importing it");
|
||||
|
||||
// Ensure there are no errors if the imported elements are imported
|
||||
// again
|
||||
modules = undefined;
|
||||
modules = await window.ensureCustomElements("moz-support-link", "moz-toggle", "moz-button-group");
|
||||
// Ensure there are no errors if the imported elements are created again.
|
||||
document.createElement("moz-support-link");
|
||||
document.createElement("moz-button-group");
|
||||
document.createElement("moz-toggle");
|
||||
ok(true, "The custom elements should not throw an error if imported again");
|
||||
is(modules, null, "There should not be a return value when using ensureCustomElements");
|
||||
})
|
||||
</script>
|
||||
</head>
|
|
@ -1358,7 +1358,6 @@ export let FormAutofillPrompter = {
|
|||
);
|
||||
|
||||
const { ownerGlobal: win } = browser;
|
||||
await win.ensureCustomElements("moz-support-link");
|
||||
win.MozXULElement.insertFTLIfNeeded(
|
||||
"toolkit/formautofill/formAutofill.ftl"
|
||||
);
|
||||
|
|
|
@ -246,8 +246,6 @@ export var PictureInPicture = {
|
|||
let panel = browser.ownerDocument.querySelector("#PictureInPicturePanel");
|
||||
|
||||
if (!panel) {
|
||||
browser.ownerGlobal.ensureCustomElements("moz-toggle");
|
||||
browser.ownerGlobal.ensureCustomElements("moz-support-link");
|
||||
let template = browser.ownerDocument.querySelector(
|
||||
"#PictureInPicturePanelTemplate"
|
||||
);
|
||||
|
|
|
@ -806,49 +806,32 @@
|
|||
"chrome://global/content/elements/autocomplete-input.js",
|
||||
],
|
||||
["editor", "chrome://global/content/elements/editor.js"],
|
||||
["moz-button", "chrome://global/content/elements/moz-button.mjs"],
|
||||
[
|
||||
"moz-button-group",
|
||||
"chrome://global/content/elements/moz-button-group.mjs",
|
||||
],
|
||||
["moz-card", "chrome://global/content/elements/moz-card.mjs"],
|
||||
["moz-five-star", "chrome://global/content/elements/moz-five-star.mjs"],
|
||||
[
|
||||
"moz-message-bar",
|
||||
"chrome://global/content/elements/moz-message-bar.mjs",
|
||||
],
|
||||
["moz-page-nav", "chrome://global/content/elements/moz-page-nav.mjs"],
|
||||
[
|
||||
"moz-support-link",
|
||||
"chrome://global/content/elements/moz-support-link.mjs",
|
||||
],
|
||||
["moz-toggle", "chrome://global/content/elements/moz-toggle.mjs"],
|
||||
]) {
|
||||
customElements.setElementCreationCallback(tag, () => {
|
||||
Services.scriptloader.loadSubScript(script, window);
|
||||
if (script.endsWith(".mjs")) {
|
||||
ChromeUtils.importESModule(script, { global: "current" });
|
||||
} else {
|
||||
Services.scriptloader.loadSubScript(script, window);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Bug 1813077: This is a workaround until Bug 1803810 lands
|
||||
// which will give us the ability to load ESMs synchronously
|
||||
// like the previous Services.scriptloader.loadSubscript() function
|
||||
function importCustomElementFromESModule(name) {
|
||||
switch (name) {
|
||||
case "moz-button":
|
||||
return import("chrome://global/content/elements/moz-button.mjs");
|
||||
case "moz-button-group":
|
||||
return import(
|
||||
"chrome://global/content/elements/moz-button-group.mjs"
|
||||
);
|
||||
case "moz-message-bar":
|
||||
return import("chrome://global/content/elements/moz-message-bar.mjs");
|
||||
case "moz-support-link":
|
||||
return import(
|
||||
"chrome://global/content/elements/moz-support-link.mjs"
|
||||
);
|
||||
case "moz-toggle":
|
||||
return import("chrome://global/content/elements/moz-toggle.mjs");
|
||||
case "moz-card":
|
||||
return import("chrome://global/content/elements/moz-card.mjs");
|
||||
}
|
||||
throw new Error(`Unknown custom element name (${name})`);
|
||||
}
|
||||
|
||||
/*
|
||||
This function explicitly returns null so that there is no confusion
|
||||
about which custom elements from ES Modules have been loaded.
|
||||
*/
|
||||
window.ensureCustomElements = function (...elementNames) {
|
||||
return Promise.all(
|
||||
elementNames
|
||||
.filter(name => !customElements.get(name))
|
||||
.map(name => importCustomElementFromESModule(name))
|
||||
)
|
||||
.then(() => null)
|
||||
.catch(console.error);
|
||||
};
|
||||
|
||||
// Immediately load the following elements
|
||||
for (let script of [
|
||||
|
|
|
@ -621,7 +621,7 @@
|
|||
customElements.define("notification", MozElements.Notification);
|
||||
|
||||
async function createNotificationMessageElement() {
|
||||
await window.ensureCustomElements("moz-message-bar");
|
||||
document.createElement("moz-message-bar");
|
||||
let MozMessageBar = await customElements.whenDefined("moz-message-bar");
|
||||
class NotificationMessage extends MozMessageBar {
|
||||
static queries = {
|
||||
|
@ -772,7 +772,6 @@
|
|||
|
||||
let buttonElem;
|
||||
if (button.hasOwnProperty("supportPage")) {
|
||||
window.ensureCustomElements("moz-support-link");
|
||||
buttonElem = document.createElement("a", {
|
||||
is: "moz-support-link",
|
||||
});
|
||||
|
|
|
@ -116,8 +116,6 @@
|
|||
MozXULElement.insertFTLIfNeeded("toolkit/global/popupnotification.ftl");
|
||||
this.appendChild(this.constructor.fragment);
|
||||
|
||||
window.ensureCustomElements("moz-button-group");
|
||||
|
||||
this.button = this.querySelector(".popup-notification-primary-button");
|
||||
if (
|
||||
this.hasAttribute("buttonlabel") ||
|
||||
|
|
Загрузка…
Ссылка в новой задаче