The only really difference sometimes is in the manifest. If you target the webextension api and use the Mozilla poly fill library, your code base does not need to be duplicated at all.
It adds the benefit of being able to use all API calls in a promise based manner instead of needing to use callbacks.
Edit:
To give it a bit more context (although you can find that in other comments I left under this post).
Which if included allows you to swap out `chrome` callback based calls for promise based `browser` calls.
So instead of using `chrome.extension.api.call(() => { // callback})` you do something like `await browser.extension.api.call()` with the same results working in both browsers.
Then the only thing where you still need some separation is for the manifest as some keys are Firefox specific and vice versa.
It adds the benefit of being able to use all API calls in a promise based manner instead of needing to use callbacks.
Edit:
To give it a bit more context (although you can find that in other comments I left under this post).
The polyfill library itself: https://github.com/mozilla/webextension-polyfill
Which if included allows you to swap out `chrome` callback based calls for promise based `browser` calls.
So instead of using `chrome.extension.api.call(() => { // callback})` you do something like `await browser.extension.api.call()` with the same results working in both browsers.
Then the only thing where you still need some separation is for the manifest as some keys are Firefox specific and vice versa.
An example you can find here: https://github.com/toolbox-team/reddit-moderator-toolbox
Where all code lives in one directory and there is just two manifest files, one for chrome and firefox: https://github.com/toolbox-team/reddit-moderator-toolbox/tre...
Building is nothing more than rollup packaging the code and grabbing the right manifest to put in the build directory for each browser: https://github.com/toolbox-team/reddit-moderator-toolbox/blo...