Since 1999, browser extensions have given developers the ability to customize and enhance their web browsing experience. However, through the years, extension development has become more challenging as different browsers entered the market and introduced their own unique extension APIs. Luckily, in 2015 the W3C created a single standard API for browser extensions with the goal of creating a uniform landscape for browser extension development. Even though there now exists a standard, there are still many differences between Chrome, Firefox, Opera and Edge. In this article, we will cover the difficulties of building a cross-browser extension and provide a solution to overcome those challenges.
The four common challenges faced when building a cross-platform browser extension are:
- Manifest management
- API inconsistencies
- Browser Action differences
The first challenge is the difference between
manifest.json files used by browsers. Browsers rely on the manifest to describe the functionality of the extension and to provide the order of operations required to run the extension. Although there are many similarities between manifests used by different browsers, there are also breaking differences that cause interoperability issues. To avoid this, use a different manifest file per browser and choose which manifest to use during build time.
Start by creating a NodeJS function called
build where a
browser argument can be used to indicate which manifest to use during build time. Then when running
node build --browser=chrome, the
build function will use the Chrome version of the manifest.
Future Challenges with Browser Manifests
Chrome released manifest V3 Preview/Alpha edition on October 31st, 2019 and with a stable release scheduled for 2020. The new manifest version proposes the greatest change to the manifest schema to date as it alters how extensions will work with browsers. With that said, by following the recommended structure, we were able to create compatibility between the different manifest versions.
Differences with API namespace and function coverage is usually the primary reason that developers resort to creating separate code bases per browser environment. However, by creating an abstraction between the browser and the extension, it is possible to manage the API differences.
In the illustration above, the
BrowserService contains all the browser API functions used throughout the extension. This abstraction layer enables the developer to implement more complex logic on top of the provided abstraction without needing to handle all the complexities and differences between browsers. Although the above illustration provides a better development experience, it does come at a performance cost since the extension will need to decide which function to use in real-time. The good news is that this performance loss will be eliminated by modifying the build (
node build --browser=chrome) to handle which browser variant of the
BrowserService to use during compilation time.
There will be scenarios where APIs that exist on one browser may not exist in other browsers. For some of these scenarios, there are polyfills and workarounds but these come at the cost of reliability or are lacking full API support.
Browser Action Differences
There are minimal differences regarding how browser actions are implemented within browsers. The key difference is the allowed maximum width and height of the browser action popover. There are two ways to overcome this. The easy way is to find the greatest common width and height between all browsers and set that as the width and height. The slightly more challenging way is to set the maximum width and height allowed for that browser dynamically during build time.
targets used by Babel during the build time and not create a generic target. With this, modern browsers can still take advantage of the modern APIs and benefit from their performance gains.
If building powerful browser extensions on a modern tech stack sounds like a dream job to you, check us out at DISQO. We are hiring!