For the agenda, I will start by giving an overview of the extension that I built to demo here, then explain the steps to set up an extension in React, highlight some interesting capabilities that I gave the Email Postponer extension, talk about running the extension locally, as well as publishing it to the store.
Then I will briefly touch upon cross-browser compatibility and how to convert a Chrome extension into a Firefox add-on. And I will end by showing a demo video of the Email Postponer extension in action.
So, for an overview, the Email Postponer extension looks like a web page, as you can see on the right, only opens on Gmail, opens as a side panel instead of a pop-up, because we want to be able to select information in the website without the pop-up closing, leverages Material UI for easy out-of-the-box component styling that is consistent with Google's Material design, allows users to interact with the contents of the web page both manually and automatically, and communicates with the back-end service using the Fetch API.
To set up the extension, I first created a new project using the Create React app in TypeScript. Then I had to change the build command to get React to generate separate JavaScript and HTML files in order to prevent content security policy errors. I also set it so that it doesn't generate source maps to get rid of some extra warnings. Because we are using TypeScript, I had to install some extra types to use the Chrome API. The project uses the Chrome API to interact with Chrome by using an injected object which is also called Chrome.
Create React app creates a manifest.json file for us, but extensions require a specific structure to that. Every extension needs to have a manifest.json file and it needs to be named manifest.json in its root directory. Google is in the process of phasing out manifest version 2 though they just announced some delays on this at Google I/O. Nevertheless, we're using manifest version 3 in our email postponer extension.
Because we want to open the extension as a side panel, we want to make sure action is empty here. Our extension will take its context from an index.html file that is compiled from React. The service worker which is also colloquially referred to as a background script, though there are some differences between the two. It runs on all tabs in the browser and gets executed on browser launch. It listens to specific events in the background, such as changing tabs or updating URLs. It takes browser-level actions accordingly, and it communicates with extension code and content scripts through message passing. This script is one of two scripts written in vanilla JavaScript, and we use it to open and close the site panel, as well as to call the res service using the fetch API, since calling it from React would give us cross-origin resource sharing errors.
Content scripts are scripts that run in the context of web pages, and they have access to DOM elements, objects, and methods. Separate instances run in separate tabs, one instance per tab, and they execute on pages that match the match's regular expression, and they communicate with the service worker and React code through message passing. Content scripts, which we only have one in this extension, are also written in vanilla JavaScript, and we use ours to create a side panel, iframe, pass messages between the React code and the background script, as well as copy and paste selected text in the extension. Also, the extension opens only in Gmail, since Gmail is the only expression that matches the regular expression in the matches property.
These are a few of the ways that messages are passed in extensions. Content scripts sit in the middle between the React code and the background script. React code communicates with content scripts through message passing. Content scripts either take action on the webpage the extension is running on or pass messages to the background script, which then can take browser lever actions accordingly. The background script can communicate with React code directly as well as with content scripts, also through message passing. Since we are running the extension in a side panel instead of a pop-up, we need to add web accessible resources to the extension.
Comments