-
Notifications
You must be signed in to change notification settings - Fork 2.7k
MDN get started tutorial examples to manifest V3 #608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
MDN get started tutorial examples to manifest V3 #608
Conversation
Migrate to Scripting API
borderify/manifest.json
Outdated
|
|
||
| "browser_specific_settings": { | ||
| "gecko": { | ||
| "id": "[email protected]", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the prevailing pattern in for the examples in this repo is <example-name>@mozilla.org where example-name is a kebab case identifier that resembles the example's parent directory. This pattern has the benefit of being reserved on AMO, so developers cannot submit add-ons with these IDs while testing.
| "id": "borderify@example.com", | |
| "id": "borderify@mozilla.org", |
beastify/manifest.json
Outdated
| "browser_action": { | ||
| "browser_specific_settings": { | ||
| "gecko": { | ||
| "id": "[email protected]", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See this comment for details.
| "id": "beastify@example.com", | |
| "id": "beastify@mozilla.org", |
dotproto
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the feedback in this review focuses on revising the Beastify extension to use async/await as that's the preferred pattern on MDN.
When both [
async/awaitand Promises] are possible, we prefer using the simplerasync/awaitsyntax.
beastify/popup/choose_beast.js
Outdated
| function reset(tabs) { | ||
| browser.tabs.removeCSS({code: hidePage}).then(() => { | ||
| browser.tabs.sendMessage(tabs[0].id, { | ||
| command: "reset", | ||
| const tabId = tabs[0].id; | ||
| browser.scripting | ||
| .removeCSS({ | ||
| target: { tabId }, | ||
| css: hidePage, | ||
| }) | ||
| .then(() => { | ||
| browser.tabs.sendMessage(tabId, { | ||
| command: "reset", | ||
| }); | ||
| }); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revise the function to use async/await.
Warning
This function has also been revised to expect a single tab rather than an array of tabs. As such, call sites will also need to be updated.
| function reset(tabs) { | |
| browser.tabs.removeCSS({code: hidePage}).then(() => { | |
| browser.tabs.sendMessage(tabs[0].id, { | |
| command: "reset", | |
| const tabId = tabs[0].id; | |
| browser.scripting | |
| .removeCSS({ | |
| target: { tabId }, | |
| css: hidePage, | |
| }) | |
| .then(() => { | |
| browser.tabs.sendMessage(tabId, { | |
| command: "reset", | |
| }); | |
| }); | |
| }); | |
| } | |
| async function reset(tab) { | |
| await browser.scripting.removeCSS({ | |
| target: { tabId: tab.id }, | |
| css: hidePage, | |
| }); | |
| browser.tabs.sendMessage(tabId, { command: "reset" }); | |
| } |
beastify/popup/choose_beast.js
Outdated
| function beastify(tabs) { | ||
| browser.tabs.insertCSS({code: hidePage}).then(() => { | ||
| const url = beastNameToURL(e.target.textContent); | ||
| browser.tabs.sendMessage(tabs[0].id, { | ||
| command: "beastify", | ||
| beastURL: url | ||
| const tabId = tabs[0].id; | ||
| browser.scripting | ||
| .insertCSS({ | ||
| target: { tabId }, | ||
| css: hidePage, | ||
| }) | ||
| .then(() => { | ||
| const url = beastNameToURL(e.target.textContent); | ||
| browser.tabs.sendMessage(tabId, { | ||
| command: "beastify", | ||
| beastURL: url, | ||
| }); | ||
| }); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revise the function to use async/await.
Warning
This function now takes a single Tab rather than an array of Tabs. Call sites must be updated.
| function beastify(tabs) { | |
| browser.tabs.insertCSS({code: hidePage}).then(() => { | |
| const url = beastNameToURL(e.target.textContent); | |
| browser.tabs.sendMessage(tabs[0].id, { | |
| command: "beastify", | |
| beastURL: url | |
| const tabId = tabs[0].id; | |
| browser.scripting | |
| .insertCSS({ | |
| target: { tabId }, | |
| css: hidePage, | |
| }) | |
| .then(() => { | |
| const url = beastNameToURL(e.target.textContent); | |
| browser.tabs.sendMessage(tabId, { | |
| command: "beastify", | |
| beastURL: url, | |
| }); | |
| }); | |
| }); | |
| } | |
| async function beastify(tab) { | |
| await browser.scripting.insertCSS({ | |
| target: { tabId: tab.id }, | |
| css: hidePage, | |
| }); | |
| const url = beastNameToURL(e.target.textContent); | |
| browser.tabs.sendMessage(tabId, { | |
| command: "beastify", | |
| beastURL: url, | |
| }); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revise to use async/await instead of Promise chains.
beastify/popup/choose_beast.js
Outdated
| * get the beast URL, and | ||
| * send a "beastify" message to the content script in the active tab. | ||
| */ | ||
| function beastify(tabs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| function beastify(tabs) { | |
| async function beastify(tabs) { |
beastify/popup/choose_beast.js
Outdated
| if (e.target.type === "reset") { | ||
| browser.tabs.query({active: true, currentWindow: true}) | ||
| browser.tabs | ||
| .query({ active: true, currentWindow: true }) | ||
| .then(reset) | ||
| .catch(reportError); | ||
| } else { | ||
| browser.tabs.query({active: true, currentWindow: true}) | ||
| browser.tabs | ||
| .query({ active: true, currentWindow: true }) | ||
| .then(beastify) | ||
| .catch(reportError); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revise the if block to use async/await conventions.
Since the query for the current tab is common to both blocks, we can move it above the if statements. Similarly, since the reportError error handler is common across both branches of the if statement, we can move it into a catch that wraps the entire if/else block.
| if (e.target.type === "reset") { | |
| browser.tabs.query({active: true, currentWindow: true}) | |
| browser.tabs | |
| .query({ active: true, currentWindow: true }) | |
| .then(reset) | |
| .catch(reportError); | |
| } else { | |
| browser.tabs.query({active: true, currentWindow: true}) | |
| browser.tabs | |
| .query({ active: true, currentWindow: true }) | |
| .then(beastify) | |
| .catch(reportError); | |
| } | |
| const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); | |
| try { | |
| if (e.target.type === "reset") { | |
| await reset(tab); | |
| } else { | |
| await beastify(tab); | |
| } | |
| } catch (error) { | |
| reportError(error); | |
| } |
beastify/popup/choose_beast.js
Outdated
| browser.tabs | ||
| .query({ active: true, currentWindow: true }) | ||
| .then(([tab]) => | ||
| browser.scripting.executeScript({ | ||
| target: { tabId: tab.id }, | ||
| files: ["/content_scripts/beastify.js"], | ||
| }) | ||
| ) | ||
| .then(listenForClicks) | ||
| .catch(reportExecuteScriptError); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| browser.tabs | |
| .query({ active: true, currentWindow: true }) | |
| .then(([tab]) => | |
| browser.scripting.executeScript({ | |
| target: { tabId: tab.id }, | |
| files: ["/content_scripts/beastify.js"], | |
| }) | |
| ) | |
| .then(listenForClicks) | |
| .catch(reportExecuteScriptError); | |
| (function runOnPopupOpened() { | |
| try { | |
| const [tab] = browser.tabs.query({ active: true, currentWindow: true }); | |
| await browser.scripting.executeScript({ | |
| target: { tabId: tab.id }, | |
| files: ["/content_scripts/beastify.js"], | |
| }); | |
| listenForClicks(); | |
| } catch(e) { | |
| reportExecuteScriptError(e); | |
| } | |
| })(); |
Co-authored-by: Simeon Vincent <[email protected]>
dotproto
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks solid. I also checked this branch branch out locally and did some additional testing; everything appeared to work as expected.
Co-authored-by: Simeon Vincent <[email protected]>
Description
Updates the borderify and beastify examples to use Manifest V3.
Motivation
These examples are used in the MDN getting started "your first extension" and "your second extension" tutorials. This change enables the getting-started guides up to be updated and brought in line with best practices for extension development using Manifest V3.
Related issues and pull requests
Related changes to MDN content in PR TBC.