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

Proposal: declaring background scripts in a neutral way #282

Open
carlosjeurissen opened this issue Sep 27, 2022 · 95 comments
Open

Proposal: declaring background scripts in a neutral way #282

carlosjeurissen opened this issue Sep 27, 2022 · 95 comments
Labels
implemented: chrome Implemented in Chrome implemented: firefox Implemented in Firefox implemented: safari Implemented in Safari proposal Proposal for a change or new feature topic: service worker Related to service worker background scripts

Comments

@carlosjeurissen
Copy link
Contributor

carlosjeurissen commented Sep 27, 2022

Edit by @Rob--W on 2023-02-24: The spirit of this feature request is to enable cross-browser development with a single manifest file. Chrome opposed the initial proposal that is described below, but after proposing an alternative solution that consists of allowing service_worker and scripts to co-exist (with the latter being ignored in Chrome), the position changed to Chrome being supportive.

Since the group currently does not agree what the future of background scripting should look like Safari and Firefox with limited event pages, Chrome with serviceWorkers

To make sure developers can define their background scripts in both situations I am proposing the following syntax:

"background": {
  "scripts": ["script1.js", "script2.js"]
}

Browsers only supporting serviceWorkers would use the script directly as serviceWorker if only one script is defined. If multiple script files are listed, it will create a generated serviceWorker named _generated_service_worker.js just like browsers currently generate a _generated_background_page.html. This serviceWorker will import all scripts using importScripts():

importScripts(
  'script1.js',
  'script2.js'
);

Browsers only supporting limited event pages would generate a _generated_background_page.html which imports the scripts using script tags:

<head></head><body>
<script src="script1.js"></script>
<script src="script2.js"></script>
</body>

Browsers supporting both serviceWorkers and limited event pages would choose based on their own preference. We can let developers set preferred_environment to serviceWorker or page which browser vendors can ignore as such:

"background": {
  "scripts": ["script1.js", "script2.js"],
  "preferred_environment": "serviceWorker"
}

Why is this important? This will lead to a more optimal contract between the developer and the browser. In which the developer is able to communicate their preferred environment while allowing browsers to decide what environment extensions should be using. This also makes sure browsers can change their preferred environment over time and have their own approach towards background script handling.

This also has the added benefit of allowing browsers to support both mv2 and mv3 like Safari does right now.

"type": "module"

This syntax works perfectly fine with type module as well by using imports in the serviceWorker, or the type module attribute for the limited event page.

In the case of "type": "module", the _generated_service_worker.js would look like this:

import "./script1.js";
import "./script2.js";

In the case of limited event pages, we can actually also start supporting "type": "module" by adding it to the _generated_background_page.html as such:

<head></head><body>
<script type="module" src="script1.js"></script>
<script type="module" src="script2.js"></script>
</body>

See #289

@carlosjeurissen carlosjeurissen added topic: service worker Related to service worker background scripts inconsistency Inconsistent behavior across browsers agenda Discuss in future meetings labels Sep 27, 2022
@xeenon xeenon added supportive: safari Supportive from Safari proposal Proposal for a change or new feature and removed inconsistency Inconsistent behavior across browsers labels Sep 28, 2022
@xeenon xeenon changed the title Inconsistency: declaring background scripts in a neutral way Proposal: declaring background scripts in a neutral way Sep 29, 2022
@xeenon xeenon added next manifest version Consider for the next manifest version and removed next manifest version Consider for the next manifest version labels Sep 29, 2022
@dotproto dotproto added follow-up: chrome Needs a response from a Chrome representative neutral: chrome Not opposed or supportive from Chrome labels Sep 29, 2022
@oliverdunk
Copy link
Member

One thing that makes this potentially less impactful is that lots of developers use bundlers which handle this sort of thing automatically. That said - adding an extra script is currently the path recommended in https://github.com/mozilla/webextension-polyfill and I think that speaks to the benefits of keeping code snippets that work in MV2 working in MV3.

@Rob--W Rob--W added the supportive: firefox Supportive from Firefox label Sep 29, 2022
@carlosjeurissen
Copy link
Contributor Author

@oliverdunk bundlers can be very useful indeed and also using them in many of my extension projects. The point of this request was also to align declaring background scripts across browsers independent on whether or not the browsers use serviceWorkers or event pages.

Adding the webExtension polyfill is one of the use cases. Another one is reusing script files across your options pages, popup pages, content scripts and background pages. As you mentioned I also very much support the idea of reducing friction when switching manifest versions.

@apple502j
Copy link

I do believe there should be at least a way to declare both Event Pages and Service Workers in a single manifest (the script performs browser check in case a browser implements both).

This helps people downloading builds from GitHub zipball, those developing extensions on tablets or Chromebooks (yes, they do exist), or those who can't use bundlers for some reason.

@tophf
Copy link

tophf commented Oct 11, 2022

How would automatic import work for "type": "module" where importScripts is not available? You can't just do import './script2.js' because its scope will be isolated not shared as it's in importScripts or in standard DOM scripts.

@carlosjeurissen
Copy link
Contributor Author

carlosjeurissen commented Oct 13, 2022

@tophf That is a good catch. Since the "type": "module" is a case in which developers already expect isolation, having this behaviour in background scripting in extensions seems expected. If needed, developers can share scope by setting / getting properties on globalThis anyway. To make this extra clear, we can add it to the documentation.

ServiceWorker with type module

So in the case of "type": "module", the _generated_service_worker.js would look like this:

import "./script1.js";
import "./script2.js";

limited event pages with type module

In the case of limited event pages, we can actually also start supporting "type": "module" by adding it to the _generated_background_page.html, see #289

@apple502j
Copy link

Any update on this? I understand this is a lot more complicated, but being able to use one manifest.json file for every browser does help a lot.

@xeenon
Copy link
Collaborator

xeenon commented Nov 3, 2022

Safari and WebKit now support "type": "module" for _generated_background_page.html as well as for service_worker (just not a generated service worker.) WebKit/WebKit@ba3a201

@dotproto
Copy link
Member

dotproto commented Nov 9, 2022

@xeenon, just to make sure I understand, with this change is the following manifest.json valid in Safari?

{
  "name": "Demo",
  "version": "0.0.1",
  "manifest_version": 3,
  "background": {
    "scripts": ["lib.js", "background.js"],
    "type": "module"
  }
}

@dotproto dotproto added opposed: chrome Opposed by Chrome and removed follow-up: chrome Needs a response from a Chrome representative labels Nov 10, 2022
@dotproto
Copy link
Member

I recently had a chance to discuss the original proposal with other Chrome folks. At the moment we have significant reservations with using a minimal set of manifest fields that work across all browsers. We expect that this approach will lead to situations where background scripts authored for page contexts or service worker contexts will be executed in a different environment from what the author expected and, as a direct result, unexpected runtime behavior. As such, we are currently opposed to the proposed introduction of a "preferred_environment" key in the background object or the use of a minimal set of properties that apply to multiple different execution environments.

That said, we did not discuss (and I think it may be worth exploring) other approaches to defining a single manifest file that works across multiple environments. For example, rather than have a way for a developer to suggest an execution environment, perhaps we could have an explicit declaration of entry points per environment.

@WorldLanguages
Copy link

Any updates? Chrome should suggest an alternative proposal that they wouldn't oppose.

We at the Scratch Addons open-source extension (100,000+ users) are watching this closely. Is it reasonable that updating to MV3 will force us to use a bundler? We have been considering adding a bundler to our workflow for some time, but did not foresee that we would need to hurry because of Manifest V3.

@carlosjeurissen
Copy link
Contributor Author

@xeenon About the naming.

precedence works for me. The downside of preferred_environment is the fact it implies singular, yet takes an array. While both precedence and preference lack this kind of singular / plural implication.

webkit-commit-queue pushed a commit to xeenon/WebKit that referenced this issue Apr 9, 2024
https://webkit.org/b/272244
rdar://problem/125988233

Reviewed by Brian Weinstein.

Add support for extensions declaring a `preferred_environment` in the `background` entry.
The `preferred_environment` key can be a string or an array of strings. When an array is
used, the browser will prefer the first one it supports.

    "background": {
        "preferred_environment": [ "service_worker", "document" ],
        "scripts": [ "script1.js", "script2.js" ]
    }

If no environments are specified or supported, then we fallback to the previous handling of
the `scripts`, `page` or `service_worker` keys (in that order) for backwards compatibility.

This allows cross-browser extensions to have a single manifest that works in multiple
browsers. Chrome plans to only support service workers going forward, but Safari and
Firefox plan to support pages and service workers, and extension might prefer a document
environment over a service worker in Safari and Firefox.

This also adds support for a `_generated_service_worker.js` script that works with normal
scripts or modules based on the `scripts` and `type` keys if `preferred_environment`
is `service_worker`.

WECG discussion here: w3c/webextensions#282

* Source/WebCore/en.lproj/Localizable.strings: Updated.
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionCocoa.mm:
(WebKit::WebExtension::resourceStringForPath): Support _generated_service_worker.js.
(WebKit::WebExtension::resourceDataForPath): Ditto.
(WebKit::WebExtension::backgroundContentUsesModules): Use renamed m_backgroundContentUsesModules.
(WebKit::WebExtension::backgroundContentIsServiceWorker): Use new m_backgroundContentEnvironment.
(WebKit::WebExtension::backgroundContentPath): Support _generated_service_worker.js.
(WebKit::WebExtension::generatedBackgroundContent): Generate the service worker script.
(WebKit::WebExtension::populateBackgroundPropertiesIfNeeded): Handle preferred_environment.
* Source/WebKit/UIProcess/Extensions/WebExtension.h: Added m_backgroundContentEnvironment and renamed
m_backgroundPageUsesModules to m_backgroundContentUsesModules.
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtension.mm:
(TestWebKitAPI::TEST(WKWebExtension, BackgroundPreferredEnvironmentParsing)): Added.
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtensionController.mm:
(TestWebKitAPI::TEST(WKWebExtensionController, BackgroundWithServiceWorkerPreferredEnvironment)): Added.
(TestWebKitAPI::TEST(WKWebExtensionController, BackgroundWithPageDocumentPreferredEnvironment)): Added.
(TestWebKitAPI::TEST(WKWebExtensionController, BackgroundWithScriptsDocumentPreferredEnvironment)): Added.
(TestWebKitAPI::TEST(WKWebExtensionController, BackgroundWithMultipleDocumentModuleScripts)): Added.
(TestWebKitAPI::TEST(WKWebExtensionController, BackgroundWithMultipleServiceWorkerScripts)): Added.
(TestWebKitAPI::TEST(WKWebExtensionController, BackgroundWithMultipleServiceWorkerModuleScripts)): Added.

Canonical link: https://commits.webkit.org/277228@main
@carlosjeurissen
Copy link
Contributor Author

@xeenon Even if page is deprecated

Not under the impression page was ever deprecated. (except by chrome in mv3).

Glad to see the browser behaviour when including multiple values is now documented on mdn:
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background#browser_support

@xeenon Not sure the info here is correct. It states:

mdn: supports background.scripts (or background.page) if service_worker is not specified.

This should probably be

Supports specifying scripts, page and service_worker simultaneously (since Safari x?).

in Safari, the service_worker property is used, and a service worker starts that opens the tab because Safari gives priority to using service workers for background scripts.

This should probably be

Safari prefers `scripts`, then `page`, then `service_worker` since Safari x. Until Safari x, a `service_worker` is preferred over `page` and `scripts.

However these changes might not have shipped yet?

@xeenon
Copy link
Collaborator

xeenon commented Apr 13, 2024

@carlosjeurissen Correct, the recent changes have not shipped yet. The preference order change is in Safari Technology Preview 192, but that's all for now. We tend to update MDN once we ship things in a main Safari release.

@carlosjeurissen
Copy link
Contributor Author

@oliverdunk When using this syntax on CWS, extensions currently seem to be rejected with the following message:
The "background.page" key cannot be used with manifest_version 3. Use the "background.service_worker" key instead."

The background property in the manifest is set as follows:

"background": {
  "service_worker": "/background.js",
  "page": "/views/background.html",
  "preferred_environment": ["document", "service_worker"]
}

@oliverdunk
Copy link
Member

Thanks @carlosjeurissen - I've escalated this internally, I'll let you know directly once I hear back. For the benefit of others, the item was rejected during review. Chrome fully supports this and the Chrome Web Store allows the extensions to be uploaded, but it looks like this was a one-off where it was incorrectly flagged. It shouldn't be a widespread problem :)

@carlosjeurissen
Copy link
Contributor Author

@oliverdunk Thanks for escalating! If the CWS review team is afraid including both service_worker and page / scripts is not intentional, it could require the preferred_environment?

@oliverdunk
Copy link
Member

@oliverdunk Thanks for escalating! If the CWS review team is afraid including both service_worker and page / scripts is not intentional, it could require the preferred_environment?

I think it's more that your extension got tested using an older version of Chrome, so it actually failed to load in the browser. They are usually pretty good about using an updated version of Chrome, so I'm not sure what happened, but looking into it.

@dotproto
Copy link
Member

Updated labels to reflect that Firefox and Chrome now support declaring event pages and a service_worker in the same manifest.json file.

scripts example
"background": {
  "scripts": ["background.js"],
  "service_worker": "background.js"
}
page example
"background": {
  "page": "background.html",
  "service_worker": "background.js"
}

@erosman
Copy link

erosman commented Aug 30, 2024

Was a priority order established?

What would be loaded (now and/or in future when all are supported) by Firefox, Chrome & Safari with the following entry?

"background": {
  "scripts": ["background.js"],
  "service_worker": "background.js"
}

preferred_environment

The important aim of dealing with inconsistencies in the manifest.json is to enable using a unified manifest for all browsers.
As preferred_environment would be different on each browsers, having to specify it in the manifest.json appears to defeat the purpose.

For Chrome

"background": {
    "preferred_environment": [ "service_worker" ],
    "service_worker": "background.js",
    "scripts": [ "background.js" ]
}

For Firefox

"background": {
    "preferred_environment": [ "document" ],
    "page": "background.html",
    "scripts": [ "background.js" ]
}

If using a preferred_environment is preferred, an alternative format might be more practical and can be used for all browsers.

"background": {
    "preferred_environment": {
      "firefox": "scripts",
      "chrome": "service_worker",
      "safari": "scripts"
    },
    "service_worker": "background.js",
    "scripts": [ "background.js" ]
}

@carlosjeurissen
Copy link
Contributor Author

@erosman with:

"background": {
  "scripts": ["background.js"],
  "service_worker": "background.js"
}

As rob mentioned before: Per #282 (comment), Safari prefers scripts, page, then service_worker when they are all specified; Previously service_worker came first. When Firefox ships service_worker support, it will also prefer Event pages over service workers (#282 (comment)).

Chrome will simply ignore the scripts, page and preferred_environment. Effectively preferring service_worker

@erosman Why would preferred_environment be different for each browser?

Use document to prefer a document background page (which can then be defined using either scripts or page.
Use service_worker to prefer a service_worker (defined using service_worker or, if supported (currently only safari), defined using scripts).

If however you want to prefer document in Firefox and Safari, but not in Chrome. You can still specify document, as Chrome will simply skip the document value (currently Chrome just fully skipps the preferred_environment, thus having the same result).

@erosman
Copy link

erosman commented Aug 30, 2024

@carlosjeurissen I see... therefore, in future when both service service_worker & scripts are supported by Firefox & Safari:

In the following example:

"background": {
  "preferred_environment": [ "scripts" ],
  "service_worker": "worker.js",
  "scripts": [ "background.js" ]
}
  • Chrome loads service_worker
  • Firefox & Safari load scripts

What would be the outcome of the following?

"background": {
  "service_worker": "worker.js",
  "scripts": [ "background.js" ]
}
  • Chrome loads service_worker
  • Firefox & Safari ??

For the sake of being thorough, I would imagine preferred_environment would be ignored in the following:

"background": {
  "preferred_environment": [ "scripts" ],
  "service_worker": "worker.js"
}

@carlosjeurissen
Copy link
Contributor Author

@erosman The outcome of the following would be:

"background": {
  "service_worker": "worker.js",
  "scripts": [ "background.js" ]
}

Chrome loads: service_worker
Firefox & Safari: load scripts in a _generated_background.html "document" using background.js.

As for:

"background": {
  "preferred_environment": [ "scripts" ],
  "service_worker": "worker.js"
}

For the extension developer, having the browser give a warning or even an error when an extension is loaded with this manifest would be preferred as scripts is not a valid value for preferred_environment. Even if document would have been specified a warning would be very welcome as no information is there in the background property to create a background document.

This is actually why I suggested to use serviceWorker instead of service_worker for preferred_environment to remove the perceived connection between the background keys and the environment.

@xeenon
Copy link
Collaborator

xeenon commented Sep 1, 2024

Indeed, scripts is not an environment, it is an input in this case. Safari supports document and service_worker as valid preferred_environment values. We will also generate a _generated_service_worker.js script based on scripts and type keys when preferred_environment is service_worker.

@carlosjeurissen serviceWorker vs service_worker is too subtle of a distinction to be truly different. We might as well match the snake case at that point. I could buy worker being the environment name.

@dotproto
Copy link
Member

Closing this issue as it has been implemented in all browsers.

@dotproto
Copy link
Member

Reopening. I didn't realize that implementation of preferred_environment was keeping this issue open.

@dotproto dotproto reopened this Sep 24, 2024
@carlosjeurissen
Copy link
Contributor Author

In addition to the preferred_environment there is also the generated service worker based on both the scripts and module keys which Safari implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
implemented: chrome Implemented in Chrome implemented: firefox Implemented in Firefox implemented: safari Implemented in Safari proposal Proposal for a change or new feature topic: service worker Related to service worker background scripts
Projects
None yet
Development

No branches or pull requests