5

I have written a Chrome extension and I am migrating it to other browsers like Firefox and Edge. However, the WebExtensions API on Firefox has some differences compared to Chrome's API.

So I have to detect whether I should use callback-style APIs (in Chrome, as well as in Edge) or the promise-style APIs (in Firefox).

For example:

if(RUNNING_ON_CHROME)
    chrome.permissions.request({
        permissions: ...,
        origins: ...,
    }, function(result) { // callback-style
        ...
    });
else // running on firefox
    browser.permissions.request({
        permissions: ...,
        origins: ...,
    }).then(function(result) { // promise-style
        ...
    });

I'm wondering how can I perform the RUNNING_ON_CHROME test. Should I check the related string in UserAgent, or check browser!==undefined?

ps. Edge uses browser.* APIs but its API is callback-styled.

xmcp
  • 3,347
  • 2
  • 23
  • 36
  • 1
    Best practises *can* be opinionated depending on the individual. – Script47 Aug 31 '17 at 15:32
  • Could you do something like `browser = browser || chrome`? – freginold Aug 31 '17 at 15:38
  • 1
    @freginold No, since they have different signatures. There is a polyfill maintained by Mozilla though. – Xan Aug 31 '17 at 15:40
  • 1
    @freginold their API have some differences. Like the code in my problem, Chrome uses callback and Firefox uses Promise. Mozilla does have a [polyfill for it](https://github.com/mozilla/webextension-polyfill) but it's too heavyweight for my extension. – xmcp Aug 31 '17 at 15:40
  • 1
    @xmcp Define "too heavyweight". After all, you're not loading the script over network, so size has less impact.. – Xan Aug 31 '17 at 15:42
  • Why would you want to have different code to use `browser.*` and Promises on Firefox while *also* having code that uses `chrome.*` and callbacks on Chrome? Just use `chrome.*` and callbacks on both. Firefox fully supports using callbacks and the `chrome.*` namespace for direct code compatibility (with some differences), where Firefox implements the API at all. – Makyen Aug 31 '17 at 17:34

1 Answers1

6

As of right now, you can rely on browser and chrome:

(no longer works for detecting Edge since the switch to Chromium-based engine)

function getBrowser() {
  if (typeof chrome !== "undefined") {
    if (typeof browser !== "undefined") {
      return "Firefox";
    } else {
      return "Chrome";
    }
  } else {
    return "Edge";
  }
}

On one hand, using this every time you want to call the API is going to be full of boilerplate; you can polyfill one of them (e.g. using webextension-polyfill to get browser in Chrome) and use only one.

On the other hand, there are real differences in implementation (even if you get the same signatures), so you will need the above browser detection to separate some logic.

Xan
  • 74,770
  • 16
  • 179
  • 206
  • 3
    You might want to mention that Firefox natively supports using the `chrome.*` namespace and callbacks. Thus, the easiest code-compatibility between Chrome and Firefox is to just use `chrome.*` in both. You only need to use the `browser.*` polyfill if *really* want to use Promises. – Makyen Aug 31 '17 at 17:38
  • @Makyen Edge was explicitly mentioned in the question. – Xan Aug 31 '17 at 17:39
  • But, in Edge they use callbacks anyway. Thus, you can generally just alias `chrome = browser` in Edge. However, I've not extensively tested in Edge, as what testing I did do (early in the year) indicated that extension support was too unstable for reasonable development (i.e. it was a pain in the rear, and I didn't have a compelling business reason). – Makyen Aug 31 '17 at 17:44
  • 1
    This answer no longer works as Edge now shares Chrome APIs: https://blogs.windows.com/windowsexperience/2018/12/06/microsoft-edge-making-the-web-better-through-more-open-source-collaboration/ – Kos Feb 14 '21 at 16:59