A starter repo for building browser extensions with React and Typescript.
Here's what you get:
- ⚛️ content scripts, popup and options page as three separate React (v18.2+) apps
- 𝙏𝙎 Typescript (v5.0+) on all apps and other scripts
- 💬 a common communication channel and storage for all these apps and scripts
- 🧩 works with Manifest V3 (i.e. works with all Chromium-based browsers and soon Firefox)
Short version:
# install dependencies in all apps thanks to Yarn workspaces
yarn
# run
cd content_scripts/app && yarn start
cd options && yarn start
cd popup && yarn start
# to build
yarn build
# to package into an archive
yarn zip
More details:
- learn more about WebExtensions and Manifest files (see resources section)
- update information inside
manifest.json
(name, description, homepage,...) and update icons - code and test your React apps within
/content_scripts/app
,/options
and/popup
- all three folders are regular React apps bundled via Vite, so just refer to their
package.json
andvite.config.js
for config, and write code like you would for any other React app - if you don't need some of these apps or scripts, simply remove them from the project and remove their build steps in the build pipeline (inside
./build.sh
)
- all three folders are regular React apps bundled via Vite, so just refer to their
- build/compile your extension by running
yarn build
from the root folder (this executes./build.sh
), load it in the browser and try it there- you can use generated
./build
folder to load the "unpacked" version of the extension in the browser and test it locally (see how for Chrome or for Firefox)
- you can use generated
- pack the extension into a single archive
- run
yarn zip
from the root folder
- run
- publish it on the web stores
- instructions for publishing to Chrome Web Store
- instructions for publishing to Firefox Add-ons
Docs and guides:
- Chrome API reference
- MV3 architecture overview (Chrome)
- Manifest V3 file format
- Anatomy of a Web Extension (Firefox)
- Building a cross-browser extension
- Porting a Google Chrome extension
Useful code repos:
Web extensions, and thus this repo, consist of four large parts, plus the manifest file specifying each of those and some additional meta-information. The parts are: content scripts, action/popup, options page and background scripts. A single web extension can have any combination of these, neither of all of them (i.e. all are optional); only the manifest is mandatory.
- The root folder (
./
) holds basic meta-information about the extension, i.e. its manifest and icons. /content_scripts
is a place for the extra JS and CSS that gets injected into the pages that you view while your extension is installed and enabled./app
folder within it holds the React app where you basically write the entirety of logic, and the remaining files are there to create a container for your React root (similar to howdiv#root
exists inpublic/index.html
when using a regular CRA)./popup
is a place for another React app that gets displayed as a popup/dropdown when clicking on the extension's icon displayed near the address bar in the browser./options
hosts a React app that serves an Options page for the extension where you can configure and persists whatever some common options./worker
is a place for a service worker (MV3) or a background script (MV2). These scripts can never have any UI as a part of it, so it consists only of TS/JS files, and they run in the background.
By having a very predictable build output (a single JS bundle) for each part of our extension, we can hardcode their script files inside manifest.json
and that's it - always the same output, always the same entry points and script files, i.e. no need for programmatic injection, dynamic loading or anything complex.
This is a build output:
You can see how that exactly matches the files specified inside of manifest.json
: