How to build a browser extension if you are a frontend developer from 2021?

Introduction
In this article, I will talk about my pet project Wordzzz, but I created an open-source extension starter kit Hello, Word, where I used the same technologies that I will talk about in this article. I want to share it with the community. Feel free to use it or contribute https://github.com/elcodabra/hello-word-sample
Russian version here — https://habr.com/ru/company/yandex_praktikum/blog/545664/
What will be considered?
- Extension Development Overview
- Developing a cross-browser extension (chrome/chromium, ff, safari)
- Code modularity, component reusing, and a modern frontend to help you develop extensions (react, typescript, lernajs)
- Development tools and bundlers (webpack, web-ext)
The structure of the extension similar to https://github.com/ajayyy/SponsorBlock, because I was inspired by this interesting project. But the extension is only one part of my project and I will share how to manage the whole project.
Note: You are free to choose another technology stack, in the article I will write about opportunities how to do that.
What the extension will do? / Requirements

- available on any site (add functionality to sites — content script) — when a word is highlighted, an icon appears, when clicked, a request is made for the translation service and the word translation window opens (1a)
- the word can also be translated using the context menu by right-clicking on the selected word (1b)
- from the translation window, you can add a word to the internal dictionary for history and further repetition (postMessage — for transferring between different parts of the extension, storage — for storing words)
- a word (notification) counter in the background script (2)
- the list of the internal dictionary can be seen in the extension menu (the same postMessage + storage) (3)
- training words in a separate window (a separate page inside the extension — learn script) (4)
Anatomy of web-extensions

I will quote information from one of the sites:
An extension consists of a set of files packaged for distribution and installation. In this article, we’ll take a quick look at the files that can be present in the extension.
manifest.json
This is a required file of an extension. Consists of metadata and permissions.
Also, it contains pointers to several other types of files:
- Background pages: Implement long-running logic.
- Icons for the extension and any buttons it might define.
- Sidebars, popups, and options pages: HTML documents that provide content for various user interface components.
- Content scripts: JavaScript included with your extension, that you will inject into web pages.
- Web-accessible resources: Make packaged content accessible to web pages and content scripts.
Let’s apply this structure to our project:

Project architecture:
You can develop simple extensions as in the instructions from Chrome Developers Site, but I’m interested in expanding this instruction for more complex projects where you need to add common components, bundlers, cross-browser compatibility, react, typescript, etc., without which it is difficult to imagine a modern frontend project.

In Figure 4 you can see that the project consists of several parts (packages):
- Common — common components, styles, etc.
- Extension — extension package
- Web — a landing page for the project
- Your choice may be different (even another extension, why not?) — in the current project, this is also a react-native project, an additional server, and various interesting ideas and experiments.
Project structure
LernaJS helps to manage connections between packages (read more about configuration and use here). As I wrote above, in common — common styles and components, common static files (font and icons) in the public folder at the root. Web and extension share common components.

In my case, all packages are built using webpack. For Extension, 5 bundles are collected in the distribution kit (according to Fig. 3), manifest.json, in which these bundles are specified, and the statics are copied.
Common components are used in accordance with the lerna instructions, there is nothing complicated there.
To run the extension, the web-ext tool is used — it installs the extension and allows you to pick up code changes to this installed extension and much more.
But there are also limitations (known bug) of the tool, so a combination with a simple method helps — update manually through the extensions panel (mainly for changing the content of scripts).
Description of tools and find others can be here — https://extensionworkshop.com/documentation/develop
Cross-browser
1) Separate manifests for different environments and browsers
It is assembled by a webpack using a small written module for different environments and browsers. In FF, for example, we need to extend our original manifest.json by adding browser_specific_settings.gecko.id
2) Safari: converting code to xcode project
I use Apple’s converter (link):
xcrun safari-web-extension-converter ./packages/extension/dist --project-location ./packages/extension/safari --app-name HelloWord --swift --bundle-identifier app.wordzzz.HelloWord
Specify yours bundle-identifier (in my case app.wordzzz.HelloWord)
If everything went well, then:

After the end, the project will open and recommendations not to use some functions (more on that below)
Click the Run button in Xcode and see how it works.
Note: You may need to enable Allow unsigned extensions (under the Develop menu).
3) Checking in CSS and a little bit about the path:
Different relative path to files in chromium browsers and FF, so I used css selectors:
/* firefox */
@-moz-document url-prefix() {
.hw-icon__logo-content {
background: url("../images/logo.svg") no-repeat;
}
}/* not firefox */
@supports not (-moz-appearance:none) {
.hw-icon__logo-content {
background: url("chrome-extension://__MSG_@@extension_id__/images/logo.svg") no-repeat;
}
}
4) Checking in JS
Nothing new here: checking navigator.userAgent.
For example, when publishing in the Apple Store, I was asked to remove the donate button.
5) Recommendations for the (non-) use of certain functions
There are recommendations not to use some functions in some browsers
There is a good article about cross-browser extension — https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Build_a_cross_browser_extension
In short, you can use a polyfill— https://github.com/mozilla/webextension-polyfill/
Links
Разработка под Chrome — https://developer.chrome.com/docs/extensions/mv3/overview/
Разработка под Firefox — https://developer.mozilla.org/ru/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension
Конвертация расширения под FF –
https://extensionworkshop.com/documentation/develop/porting-a-google-chrome-extension/
Firefox extension supported functions https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_support_for_JavaScript_APIs
How to develop an extension for Safari –https://developer.apple.com/documentation/safariservices/safari_web_extensions
How to convert chrome extension for safari –https://developer.apple.com/documentation/safariservices/safari_web_extensions/converting_a_web_extension_for_safari
How to build a cross-browser extension — https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Build_a_cross_browser_extension
Chrome extensions samples — https://github.com/GoogleChrome/chrome-extensions-samples
About Wordzzz
Wordzzz extension analyzes subtitles in your YouTube & Netflix player (subtitles must be enabled) and when you hover over a word, the video stops and you can click on a word to see the translation card. Also, you can translate text while browsing.

All translated words can be added to your vocabulary. We use internal storage of the browser so no sign-in is required. When you click on the Wordzzz icon, the main extension window with vocabulary and language settings will appear.

Learn new words with the most effective card system. When you start practicing, hover over the card and see the translation of the new word — this effective method allows you to remember the new words and check the translation on-the-go.

We have a lot of languages for translating:

Summary:
★ TRANSLATE TEXT WHILE BROWSING
Double click or select any word to translate it
★ SAVE NEW WORDS
Save words while watching your favorite videos on YouTube
★ PRACTICE YOUR VOCABULARY
Learn new words with the most effective card system
★ EASILY SWITCH LANGUAGES
Switch between the most popular language pairs
★ DARK MODE FOR READABILITY
Reduce your eye strain with the automatic dark mode
★ HOW TO USE WORDZZZ
- Download Wordzzz extension from Chrome store
- Whenever you see a new word or phrase, click on it to get its meaning
- Add it to your vocabulary to practice later
- Go to the main extension window and start practicing
Link to our extension — wordzzz.app
Final
As you can see, the development of extensions can also be with a modern stack, there is still a lot that can be done in the current project, for example, cover with types and tests, use preprocessors, and much more. Suggest in the comments useful ideas for improving the project and your solutions and useful tools for developing extensions and implement your ideas. Peace for everyone.
Support us on Patreon.
Link to my extension starter kit — https://github.com/elcodabra/hello-word-sample
Russian version — https://habr.com/ru/company/yandex_praktikum/blog/545664/