Skip to content
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

Add example using MV3 userScripts API #576

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Rob--W
Copy link
Member

@Rob--W Rob--W commented Dec 18, 2024

Description

Add example using MV3 userScripts API. And many other aspects of MV3 development, useful for #496.

Motivation

This example is part of the documentation of the userScripts API.

Additional details

Related issues and pull requests

@Rob--W Rob--W requested a review from dotproto December 18, 2024 14:53
"browser_specific_settings": {
"gecko": {
"id": "[email protected]",
"strict_min_version": "134.0a1"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I put strict_min_version 134 because this is the first version of Firefox where the API landed, behind the extensions.userScripts.mv3.enabled preference. I may update it to 135 or 136 once we ship it by default on release.

@erosman
Copy link

erosman commented Dec 18, 2024

Note: "host_permissions" should include "file:///*", as many users (myself included) run personal userScripts on local files.

@Rob--W
Copy link
Member Author

Rob--W commented Dec 18, 2024

Note: "host_permissions" should include "file:///*", as many users (myself included) run personal userScripts on local files.

This is a demo extension, not a full-fledged user script manager. For it to be a complete user script manager, it would have to define the full GM.* / GM_* APIs, and also have a better UI. That goes beyond demonstrating the extension APIs and is left as an exercise to the reader.

@erosman
Copy link

erosman commented Dec 18, 2024

I understand.. the intension was to demonstrate that the MV3 userScripts API supports "file:///*" as well.

Copy link
Contributor

@dotproto dotproto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this review I mostly identified small tweaks. The core functionality looks quite solid. Nice work, @Rob--W!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rob--W, if you want to publish this example before the 135, I think we should add some installation instructions to the README that mention that you need to enable extensions.userScripts.mv3.enabled in about:config.

Comment on lines +3 to +8
A user script manager, demonstrating the userScripts API, the permissions API,
`optional_permissions`, and Manifest Version 3 (MV3).
The extension is an example of a
[user script manager](https://en.wikipedia.org/wiki/Userscript_manager).

This covers the following aspects to extension development:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reword to fix a grammar issue and for clarity. Currently the intro sentence is incomplete.

Suggested change
A user script manager, demonstrating the userScripts API, the permissions API,
`optional_permissions`, and Manifest Version 3 (MV3).
The extension is an example of a
[user script manager](https://en.wikipedia.org/wiki/Userscript_manager).
This covers the following aspects to extension development:
The extension is an example of a
[user script manager](https://en.wikipedia.org/wiki/Userscript_manager). It
demonstrates the userScripts API, the permissions API, `optional_permissions`,
and Manifest Version 3 (MV3).
This demo covers the following aspects to extension development:

Comment on lines +15 to +16
- Minimizing the overhead of background script startup, which is especially
relevant because event pages .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reword to make this comment more applicable to other browsers. It also addresses the fact that other browsers may also support service workers in the future.

Suggested change
- Minimizing the overhead of background script startup, which is especially
relevant because event pages .
- Minimizing the overhead of background script startup. This is relevant because
Manifest Version 3 extensions uses an event-based background context.

NOTE: If you accept this suggestion, you should also update this line with a similar change.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correcting grammar in suggestion

Suggested change
- Minimizing the overhead of background script startup, which is especially
relevant because event pages .
- Minimizing the overhead of background script startup. This is relevant because
Manifest Version 3 extensions use an event-based background context.

Comment on lines +18 to +19
- Monitoring an optional (userScripts) permission, and dynamically registering
events and scripts based on its availability.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reword for clarity. The parenthetical should appear after the entire phrase that it applies to.

I tend to prefer to include the quotation marks when referring to a permission. That said, I don't know if we have an established pattern one way or the other.

Suggested change
- Monitoring an optional (userScripts) permission, and dynamically registering
events and scripts based on its availability.
- Monitoring grants for an optional permission (`"userScripts"`), and
dynamically registering events and scripts based on its availability.

- Monitoring an optional (userScripts) permission, and dynamically registering
events and scripts based on its availability.

- Using the `userScripts` API to register, update and unregister code.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: clarify that the extension is specifically operating on user scripts rather than arbitrary code.

Suggested change
- Using the `userScripts` API to register, update and unregister code.
- Using the `userScripts` API to register, update and unregister user script
code.


## What it does

This extension is an example of a [user script manager](https://en.wikipedia.org/wiki/Userscript_manager)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: end the sentence with a period.

Suggested change
This extension is an example of a [user script manager](https://en.wikipedia.org/wiki/Userscript_manager)
This extension is an example of a [user script manager](https://en.wikipedia.org/wiki/Userscript_manager).

userScriptsAvailableAtStartup = false;

// Clear cached state, so that ensureUserScriptsRegistered() will refresh
// the registered user scripts if the permissions is granted again.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// the registered user scripts if the permissions is granted again.
// the registered user scripts if the permission is granted again.

Comment on lines +144 to +145
let worldIds = scriptsToRemove.map(s => s.id);
await browser.userScripts.unregister({ worldIds });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 145 currently throws the following error:

Uncaught (in promise) Error: Type error for parameter filter (Unexpected property "worldIds") for userScripts.unregister.

Channel: Nightly
Version: 135.0a1 (2024-12-30) (aarch64)
OS: macOS 15.1 (24B83)

I looked through the current version of toolkit/components/extensions/schemas/user_scripts.json and the current version of UserScriptFilter only has a ids property.

It looks like this may be the result of some refactoring that occured during development. The script appears to work as expected if we change the body of the if clause as follows:

Suggested change
let worldIds = scriptsToRemove.map(s => s.id);
await browser.userScripts.unregister({ worldIds });
await browser.userScripts.unregister({ ids: scriptsToRemove });

}
}

button.onclick = async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to double check that re-assigning an onevent handler like this would remove the previous event handler, but it checks out! (mdn, whatwg spec)

"javascript_apis": [
"userScripts.register",
"runtime.onMessage",
"runtime.sendMessage"
],
"name": "user-script-register"
},
{
"description": "A user script manager, demonstrating the userScripts API, permissions API, optional_permissions and Manifest Version 3 (MV3).",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"description": "A user script manager, demonstrating the userScripts API, permissions API, optional_permissions and Manifest Version 3 (MV3).",
"description": "A user script manager demonstrating the userScripts API, permissions API, optional_permissions, and Manifest Version 3 (MV3).",

Comment on lines +3 to +6
A user script manager, demonstrating the userScripts API, the permissions API,
`optional_permissions`, and Manifest Version 3 (MV3).
The extension is an example of a
[user script manager](https://en.wikipedia.org/wiki/Userscript_manager).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A user script manager, demonstrating the userScripts API, the permissions API,
`optional_permissions`, and Manifest Version 3 (MV3).
The extension is an example of a
[user script manager](https://en.wikipedia.org/wiki/Userscript_manager).
This is an example [user script manager](https://en.wikipedia.org/wiki/Userscript_manager) that demonstrates the userScripts API, the permissions API,`optional_permissions`, and Manifest Version 3 (MV3).

The extension is an example of a
[user script manager](https://en.wikipedia.org/wiki/Userscript_manager).

This covers the following aspects to extension development:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This covers the following aspects to extension development:
This example illustrates these aspects of extension development:


This covers the following aspects to extension development:

- Showing onboarding UI after installation.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Showing onboarding UI after installation.
- Showing an onboarding UI after installation.


- Showing onboarding UI after installation.

- Designing background scripts that can restart repeatedly with minimal
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rob--W as we seem to make the assumption that this is going to be rendered as a markdown document (e.g. use of hyperlink in the introductory paragraph) is there any need to impose line breaks?


// Now we have computed the changed scripts, apply the changes in this order:
// 1. Unregister obsolete scripts.
// 2. Reset / configure worlds.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 2. Reset / configure worlds.
// 2. Reset or configure worlds.

// Now we have computed the changed scripts, apply the changes in this order:
// 1. Unregister obsolete scripts.
// 2. Reset / configure worlds.
// 3. Update / register new scripts.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 3. Update / register new scripts.
// 3. Update or register new scripts.

// 3. Update / register new scripts.
// This order is significant: scripts rely on world configurations, and while
// running this asynchronous script updating logic, the browser may try to
// execute any of the registered scripts when a website loaded in a tab or
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// execute any of the registered scripts when a website loaded in a tab or
// execute any of the registered scripts when a website loads in a tab or

await browser.userScripts.unregister({ worldIds });
}

// 2. Reset / configure worlds.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 2. Reset / configure worlds.
// 2. Reset or configure worlds.


// 2. Reset / configure worlds.
if (scripts.some(s => s.worldId)) {
// When a userscripts need privileged functionality, we run them in a
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// When a userscripts need privileged functionality, we run them in a
// When a userscripts need privileged functionality, run them in a

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn’t that be "When a userscript needs" or "When userscripts need"?

Comment on lines +15 to +16
- Minimizing the overhead of background script startup, which is especially
relevant because event pages .
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correcting grammar in suggestion

Suggested change
- Minimizing the overhead of background script startup, which is especially
relevant because event pages .
- Minimizing the overhead of background script startup. This is relevant because
Manifest Version 3 extensions use an event-based background context.

}

/**
* Shows the form where the user can edit or create a new user script.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Shows the form where the user can edit or create a new user script.
* Shows the form where the user can edit or create a user script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants