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

Support Chrome manifest v3 APIs #329

Open
avalanche1 opened this issue Jul 16, 2021 · 21 comments
Open

Support Chrome manifest v3 APIs #329

avalanche1 opened this issue Jul 16, 2021 · 21 comments

Comments

@avalanche1
Copy link

Is this lib compatible with Chrome manifest v3?
I haven't found any mentions in the docs.

@avalanche1
Copy link
Author

If not - are you planning to implement the support?

@Rob--W
Copy link
Member

Rob--W commented Jul 22, 2021

Chrome will support promises at the chrome. namespace in browser, and still support the callback-based APIs.

The polyfill invokes methods in the chrome. namespace using callbacks and returns a Promise, for methods that are explicitly supported. When a method is not explicitly recognized, the parameters to the API call are passed as-is to the underlying chrome. namespace. In manifest v3, Chrome's APIs support promises too, so the return values would still be promises. In either case, the polyfill will provide support for the APIs as expected.

We'll keep this bug open, and close it once we've added integration tests.

@AhsanAyaz
Copy link

Chrome will support promises at the chrome. namespace in browser, and still support the callback-based APIs.

The polyfill invokes methods in the chrome. namespace using callbacks and returns a Promise, for methods that are explicitly supported. When a method is not explicitly recognized, the parameters to the API call are passed as-is to the underlying chrome. namespace. In manifest v3, Chrome's APIs support promises too, so the return values would still be promises. In either case, the polyfill will provide support for the APIs as expected.

We'll keep this bug open, and close it once we've added integration tests.

Is there any update on this? It seems like the extensions break with servicewoker+background script combo in manifest v3.

@avalanche1
Copy link
Author

avalanche1 commented Mar 7, 2022

@AhsanAyaz you mean servicewoker+**content script** combo in manifest v3?

@AhsanAyaz
Copy link

@avalanche1 . No I mean using the background.js or any file as a service worker with webextension-polyfill doesn't work because of the window being undefined.

@Rob--W
Copy link
Member

Rob--W commented Mar 8, 2022

@avalanche1 . No I mean using the background.js or any file as a service worker with webextension-polyfill doesn't work because of the window being undefined.

The polyfill does not use window, but globalThis. Are you using the latest version of the polyfill?

@getify
Copy link

getify commented Apr 9, 2022

I'm attempting to convert my working v2 extension to v3... but experiencing some issues. I am using importScripts(..) in my formerly-background-now-service-worker script to bring in this polyfill.

In particular, since v3 consolidates pageAction and browserAction into just action, I changed my calls from browser.pageAction.show(..) to browser.action.show(..), but that's throwing the exception: "browser.action.show is not a function". I then tried just directly chrome.action.show(..), but that's the same exception. And I then I tried the old browser.pageAction.show(..), but that gives an exception indicating that browser.pageAction is undefined (so thus the show property access fails).

Is this a problem with chrome's v3 manifest having changed or deprecated that function name? Or is this a problem with this polyfill? I can't seem to get properly updated info on the interplay between the v3 changes and this polyfill.

@getify
Copy link

getify commented Apr 9, 2022

Yes I'm sure I'm in manifest v3, because my other changes (including changes in the manifest, like "service_worker") are working as expected. Moreover, chrome.action is present and valid.

Specifically, the error I'm getting is that chrome.action (or browser.action) do not have a show(..) function. In manifest-v2 browser.pageAction.show(..) works great, but I can't seem to get the equivalent to work in manifest-v3 via chrome.action.show(..) or browser.action.show(..) -- they both throw an exception for show(..) not being a function (it's undefined).

@meandavejustice
Copy link

@getify chrome.action.show Is not in mv3. You may be looking for setPopup

https://developer.chrome.com/docs/extensions/reference/action/

@getify
Copy link

getify commented Apr 10, 2022

They didn't list throwing away show(..) in the breaking changes from manifest v2 to v3... but it does seem like setPopup(..) is roughly equivalent... though now I have to pass the URL for the HTML page whereas in v2 that URL is specified in the manifest itself.

In any case, I've now passed that error, and encountered a variety of others. For example, my extension (obviously) has a popup, and I used to be able to call browser.extension.getViews({ type: "popup" }) to get references to all instances of my extension's popup, so that I could get call postMessage(..) on each reference to send them all messages.

getViews(..) is another one which apparently was discarded from v2 to v3. :( A similar (but not equivalent or equivalent) seems to be action.getPopup(..). Sadly, that function doesn't get the popup window reference itself, it just gets the URL of the popup... which isn't at all helpful since I already manually provided that URL.

In any case, sorry to be rambling here... it seems that the conversion from v2 to v3 is NOT particularly straightforward the way the migration guide makes it seem. There's quite a bit of breaking change behavior where they apparently decided people didn't need (or shouldn't need) to do things that were perfectly valid/useful in v2.

I don't guess that my problems right now are particularly related to this polyfill, so I don't need to keep creating noise here. Sorry!

If anyone has any suggested resources on how to navigate all these breaking changes, I'd certainly love to read it. I feel like I'm flailing in the dark here, because just about everything I google search about reveals stuff about v2 and nobody seems to have much concrete answers on v3.

Side note: it's annoying that Chrome is already warning (with logged errors) about manifest v2 extensions going away, but the v3 stuff we're supposed to convert to is not even fully shipped, and the docs for it are painfully lacking. Maybe I'm just in the pain because I decided to be proactive when I saw the error, and perhaps I should just sleep on this for about 6 months while more of this bakes fully.

@XjSv
Copy link

XjSv commented May 26, 2022

I came across this: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Build_a_cross_browser_extension and it seems like things are still up in the air. The note specifically mentions that the webextension-polyfill is specifically for Manifest V2.

Building a cross-browser extension

@Rob--W
Copy link
Member

Rob--W commented May 27, 2022

They didn't list throwing away show(..) in the breaking changes from manifest v2 to v3... but it does seem like setPopup(..) is roughly equivalent... though now I have to pass the URL for the HTML page whereas in v2 that URL is specified in the manifest itself.

.show is NOT replaced with setPopup, the two are different.
action.show is the replacement for pageAction.show and browserAction.enable.

In any case, I've now passed that error, and encountered a variety of others. For example, my extension (obviously) has a popup, and I used to be able to call browser.extension.getViews({ type: "popup" }) to get references to all instances of my extension's popup, so that I could get call postMessage(..) on each reference to send them all messages.

getViews(..) is another one which apparently was discarded from v2 to v3. :(

This is not the case. Extension pages can still use extension.getViews(). What you may be observing is the absence of extension.getViews() in a background Service Worker. That's because service workers run off the main thread, where they cannot access DOM APIs, including entire documents/windows that would be exposed via getViews().

A similar (but not equivalent or equivalent) seems to be action.getPopup(..). Sadly, that function doesn't get the popup window reference itself, it just gets the URL of the popup... which isn't at all helpful since I already manually provided that URL.

getPopup() never returned the window reference itself.

@getify
Copy link

getify commented May 27, 2022

@Rob--W

action.show is the replacement for pageAction.show and browserAction.enable.

Well, I wish that was the case, but... did you read this from me earlier in the thread?

I changed my calls from browser.pageAction.show(..) to browser.action.show(..), but that's throwing the exception: "browser.action.show is not a function". I then tried just directly chrome.action.show(..), but that's the same exception. And I then I tried the old browser.pageAction.show(..), but that gives an exception indicating that browser.pageAction is undefined (so thus the show property access fails).

So it's not (or wasn't at time of writing) in Chrome. Moreover, it's not (or wasn't at time of writing) in the MV3 docs.

And when I came here with my problem, here was the first response:

getify chrome.action.show Is not in mv3. You may be looking for setPopup

So... shrugs. It's clearly in a state of confusion and flux.

How am I supposed to migrate when faced with such mixed signals?

@getify
Copy link

getify commented May 27, 2022

@Rob--W

What you may be observing is the absence of extension.getViews() in a background Service Worker.

Well, what's my reasonable workaround then?

My MV2 extension sends messages from browser page to the background page, which then finds the extension popup to relay the message to. The background page (MV2) had no trouble doing that. If SW (MV3) cannot do so, how can I get these messages routed?

@Rob--W
Copy link
Member

Rob--W commented May 27, 2022

@Rob--W

action.show is the replacement for pageAction.show and browserAction.enable.

Well, I wish that was the case, but... did you read this from me earlier in the thread?

I changed my calls from browser.pageAction.show(..) to browser.action.show(..), but that's throwing the exception: "browser.action.show is not a function". I then tried just directly chrome.action.show(..), but that's the same exception. And I then I tried the old browser.pageAction.show(..), but that gives an exception indicating that browser.pageAction is undefined (so thus the show property access fails).

The API is only available if action is declared in manifest.json.

getify chrome.action.show Is not in mv3. You may be looking for setPopup

So... shrugs. It's clearly in a state of confusion and flux.

How am I supposed to migrate when faced with such mixed signals?

Read official documentation instead of relying on a comment from a random third party.

@Rob--W

What you may be observing is the absence of extension.getViews() in a background Service Worker.

Well, what's my reasonable workaround then?

My MV2 extension sends messages from browser page to the background page, which then finds the extension popup to relay the message to. The background page (MV2) had no trouble doing that. If SW (MV3) cannot do so, how can I get these messages routed?

The extension page or even a content script can directly communicate with the popup, e.g. with runtime.sendMessage.

@getify
Copy link

getify commented May 27, 2022

@Rob--W

The API is only available if action is declared in manifest.json.

This tone is almost deliberately condescending and hostile. It's like stating "the sky is blue" as if someone doesn't know that obviously, the sky is blue.

Of course I have "action" declared in the manifest. I was using the equivalent of it (browser.pageAction) in MV2. I couldn't even get a running MV3 extension (the manifest validation would have failed) without having first converted the pageAction manifest entry to action. I did so following the best information in the migration notes and the "official documentation".

As I stated above, I have other action.* methods in my code that are working just fine, but as I've now asserted multiple times, action.show(..) is NOT working, it shows as undefined and not a function, even though other action.* methods are present and working. Moreover, this "official documentation" doesn't even list show under action anymore -- or at least didn't at the time of my writing these messages.

Please refrain from insulting me like I have no idea what I'm doing. I have a perfectly good and workable MV2 extension that has worked for years. Migrating to MV3 has been a horrible nightmare, and it's the fault of the developers building the changes as well as those responsible for the poor state of the "official documentation".

Read official documentation instead of relying on a comment from a random third party.

First off, how on earth am I supposed to know who's who? Maybe you're the "random third party" for all I know.

[ Edit: these comments are off-topic ] The "official documentation" for MV3 is confusing and incomplete, at best.

But as I stated multiple different ways above in the thread, I HAVE READ THE DOCUMENTATION.

[ Edit: these comments are off-topic ] The documentation is wrong and broken.

Moreover, your dismissive and condescending tone here furthers the off-putting nature of this whole situation.

[ Edit: these comments are off-topic ] Google should be ashamed for the current state of this rollout. Why would anyone care to write or maintain extensions when they are treated as being ignorant and at fault when such a huge change is absurdly difficult to migrate, accompanied by poor and incomplete documentation.

@Rob--W
Copy link
Member

Rob--W commented May 28, 2022

@Rob--W

The API is only available if action is declared in manifest.json.

This tone is almost deliberately condescending and hostile. It's like stating "the sky is blue" as if someone doesn't know that obviously, the sky is blue.

That was not intended. I misread the error message that you pasted, and thought that the error indicated the absence of the action API in your extension, hence the question of whether "action" was declared.

Secondly, I made a typo in an earlier comment. The method is action.enable (not action.show). If you wonder why, it's historical: In Chrome, pageAction has been visually indistinguishable from browserAction for many years now (it wasn't the case in the past), hence Chrome decided to merge it with the browserAction API, followed by renaming it to action.

Read official documentation instead of relying on a comment from a random third party.

First off, how on earth am I supposed to know who's who? Maybe you're the "random third party" for all I know.

It seems that you believe that this is the place for feedback to Google, judging by your expressed frustration directed towards Google and Chrome. This is not the place for that.

You are currently posting questions and complaints about Google's MV3 implementation, in the issue tracker of a library that offers a Promise-based API layer over whatever the execution environment offers. The only overlap is "MV3" as subject, but other than that your comments are off-topic. Your questions about the API would fit better on a Q&A site or a forum for extension developers.

The "official documentation" for MV3 is confusing and incomplete, at best. But as I stated multiple different ways above in the thread, I HAVE READ THE DOCUMENTATION. The documentation is wrong and broken.

The API references match the browsers' implementations. If something is missing or inaccurate, file a bug report in the right places: https://github.com/mdn/content for MDN (Firefox, Safari and other browsers), and https://github.com/GoogleChrome/developer.chrome.com/ for Chrome-specific docs.

@getify
Copy link

getify commented May 29, 2022

@Rob--W

The method is action.enable

I read the docs for enable(..), but it sure doesn't seem to me semantically to be a replacement for show(..). I don't think of "enable" as "make visible" (which is what I'm intending). But if that's indeed the consolidation that occurred, and we're supposed to know that, fine. I am not sure I ever would have come to the conclusion (from the docs) that "enable" means "make the popup visible", but having learned that now, I'm glad for the clarification.

It is still the case that the migration guide/breaking-changes of those "official docs" does not list this "change" from show(..) to enable(..). If it had, I probably would never have come here.

That's not the fault of this polyfill, of course. So that complaint indeed belongs elsewhere. But it is nonetheless fact that bears on how this thread has unfolded.

the issue tracker of a library that offers a Promise-based API layer over whatever the execution environment offers

I'm only on this thread because when I initially encountered the errors in migration, it wasn't at all clear if any/all of them might be coming from this polyfill not being MV3 compliant (the OP's topic). The fact that the issue was still open led me to believe that the question was still undecided.

After a few messages exchanged here, it seemed clear that my issues likely weren't caused by the polyfill. So 2 months ago my "last" message said that I didn't want to continue creating undue noise in this repo/thread, and intended to take my support questions (and complaints) to a different channel (at some future date).

It was your belated comment (with mistake/typo) contradicting earlier facts/claims that restarted the conversation and brought me back into the mix here.

I'll again assert that, my intent is for THIS to be my last message here on the subject, and that my support questions and complaints will go elsewhere.

Side note: the OP had asked "is this polyfill MV3 compliant?" If it is, now -- and I think so, but I'm not in a position to know for sure -- then it seems like this thread is ready to be closed with an affirmative answer to that question. That would probably help clear up any future readers of this thread being confused by the unfortunate detours.

I misread the error message that you pasted... Secondly, I made a typo in an earlier comment

We all make mistakes. For the record, my tone escalated to significant frustration not from the first message you posted (with the mistake/typo), but from the second reply, where you doubled down with comments I interpreted as suggesting that the fault was entirely mine for not RTFM.

Moreover, I interpreted your defense of the "official" documentation, and your dismissal of another thread commenter as "random third-party", as positioning yourself instead as "official". That made your mistake/typo claims all the more infuriating. I don't have any idea who you work for, but it seemed to me like you were defending Google there, perhaps even as a Google employee might, so that's what spurred my Google-specific complaints.

You are currently posting questions and complaints about Google's MV3 implementation... your comments are off-topi

Agreed. I edited my earlier comment to strikeout the parts that were off-topic complaints about Google. My apologies for the noise.

@fregante
Copy link
Contributor

I think that the polyfill isn't useful after MV3:

  • Chrome MV3 already offers promisified chrome.* APIs natively
  • Firefox always offered promisified chrome.* APIs
  • Browsers are now collaborating to ensure cross-browser compatibility

Firefox doesn't support MV3 at all at the moment so using this "Firefox polyfill" on a Chrome-only MV3 extension makes no sense.

Once Firefox supports MV3, you'll just be able to load your natively-promisified "Chrome-only" chrome-*-based MV3 extension in Firefox without a any polyfills.

Surely there will be some API discrepancies going forward, but the polyfill isn't really built with that in mind and has its own downsides/bugs.

@Juraj-Masiar
Copy link

So, if I want to keep using "browser" namespace in my MV3 Chromium extension, I could "simplify" this polyfill to just this:

if (!('browser' in self)) {
  self.browser = self.chrome;
}

Right?
Or is the polyfill doing something more?

nachtjasmin added a commit to ItsVipra/ProToots that referenced this issue Jul 5, 2023
It looks like that the polyfill is no longer required for Manifest v3.
[^1]
However, for a better developer experience, we keep the TypeScript
definitions and use a little workaround for the global "browser"
namespace.

[^1]: mozilla/webextension-polyfill#329
nachtjasmin added a commit to ItsVipra/ProToots that referenced this issue Jul 5, 2023
It looks like that the polyfill is no longer required for Manifest v3.
[^1]
However, for a better developer experience, we keep the TypeScript
definitions and use a little workaround for the global "browser"
namespace.

[^1]: mozilla/webextension-polyfill#329
nachtjasmin added a commit to ItsVipra/ProToots that referenced this issue Jul 5, 2023
It looks like that the polyfill is no longer required for Manifest v3.
[^1]
However, for a better developer experience, we keep the TypeScript
definitions and use a little workaround for the global "browser"
namespace.

[^1]: mozilla/webextension-polyfill#329
nachtjasmin added a commit to ItsVipra/ProToots that referenced this issue Jul 5, 2023
It looks like that the polyfill is no longer required for Manifest v3.
[^1]
However, for a better developer experience, we keep the TypeScript
definitions and use a little workaround for the global "browser"
namespace.

[^1]: mozilla/webextension-polyfill#329
@james-cnz
Copy link

james-cnz commented Dec 10, 2023

@Juraj-Masiar: Thanks, this helped me. I did run into an issue, though, that Chrome still doesn't support returning a promise from a message listener. Instead you have to start a promise that will call a callback, and immediately return true. See; https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage
(Also, Chrome seems to have deprecated a bunch of functionality, so I'll have to work around that.)
EDIT: One of the things Chrome's deprecated is the ability to specify multiple JavaScript files for a background script. You can specify a background script as a JavaScript module, that can import things from other JavaScript modules that export them, but you can't specify a content script as a JavaScript module, so if you want to have a JavaScript file that's shared between the background script and a content script, you need a workaround for that: https://stackoverflow.com/questions/48104433/how-to-import-es6-modules-in-content-script-for-chrome-extension
EDIT 2: FYI, other things Chrome's deprecated are getBackgroundPage in popup scripts, and using DOMParser in the background script. So now, instead of the popup script being able to call getBackgroundPage and interact with the background script directly, it has to send messages, same as between the background script and content scripts. And instead of background scripts being able to use DOMParser directly, DOMParser has to be used from an "offscreen document". So more messages, I guess. It'll be like Old MacDonald's Farm, but with messages: Here a message, there a message, everywhere a message message.

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

No branches or pull requests

9 participants