Plasmo - a new way to create modern browser extensions
Tags: javascript, webdev, chrome, plasmo
Published: 2023-09-07 20:21:43

![article banner](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zlicplku1illg6eha3ch.png)

## Context

I have had the opportunity to develop a new AI-based solution recently to enhance sellers' performance when using online conferencing platforms such as Zoom. After technical analysis, we concluded that the most effective approach is to create a browser extension for Chrome. 

Okay, but how do I create a Chrome extension? Can I use React or other tools I'm accustomed to? It is entirely possible, but setting one up can be time consuming and diverge from the standard configuration. While researching how to integrate React easily into my project, I encountered Plasmo. This framework promises to **supercharge** your extension with a set of features that I'll detail in this article.

## Introduction

Plasmo is an open-source tool with great documentation. It has a strong opinion on project architecture and configuration (no, you don't need to touch the usual manifest file). I don't think it is for everyone, but I found it pleasant to work with, especially if your codebase is growing rapidly. The team also offers SaaS for easier extension testing and deployment but is not included in today's topic.

Currently in version 0.82, Plasmo supports React, Svelte, and Vue **out of the box** providing live reloading and Hot Module Replacement for the ease of use. The tool makes it easy to compile the code, therefore enabling the compatibility with Chrome, Firefox and Safari, ensuring interoperability and consistency across platforms. 

![Plasmo production build](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrvbid2uehvutod94ctc.png)

In this article, I'll show you how to quickly create your first Plasmo project with React and Typescript. *The code will be provided on this [repo](https://github.com/corentinleberre/hiver)*.

## Create your first extension

Today, we're going to work together on creating a straightforward and enjoyable Plasmo extension – something fun like replacing the 𝕏 logo with the old blue and black Twitter logo, or even using a logo of your choice. The goal is to familiarize ourselves with the sharing mechanics of storage and understand how Plasmo allows us to interact with content scripts and popups easily.

![Gif illustrating the final plasmo project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g54pwvpdf493n2uqqqib.gif)

Our focus will be on the **Popup** and **Content Script** aspects. We will explore these specific components in detail (you can also interact with the Background service worker, Tabs and Options easily). Our primary attention will be paid to understanding how modifications of the popup interface should be made in **popup.tsx**, and how content script enhancements belong in **content.tsx**.

👉 Create the project

```bash
npm create plasmo plasmo-intro
cd plasmo-intro
npm run dev
```

You will then have the following file structure :

```text
📦 plasmo-intro  
┣ 📂 assets  
┣ 📂 build
┣ 📜 package.json  
┣ 📜 popup.tsx
┣ 📜 README.md  
┗ 📜 tsconfig.json
```

Now you can [load the extension in your favorite browser](https://docs.plasmo.com/framework#loading-the-extension-in-chrome)

👉 Customise the Popup

The popup is what shows up when you click on the extension in your browser. All the code needed can be found in **popup.tsx**.

This code defines an UI component that displays a set of radio buttons, each representing a different Twitter logo.

![popup without styling and useStorage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/puq9xxm4ci52cu3k7l63.png)

👉 Add the logic and styling

Plasmo provides utilities to ease communication between your popup, content script and the rest of your extension. We're going to add Plasmo Storage to our project to preserve a state in the browser. It will be used to pass the icon we want to display on *x.com* between the popup and the content script.

```bash
npm install @plasmohq/storage
```

*more docs about Plasmo storage [here](https://docs.plasmo.com/framework/storage)*

```json
// package.json

{
  "name": "plasmo-intro",
  ...
  "manifest": {
    "host_permissions": [
      "https://twitter.com/*",
	  "https://x.com/*"
    ],
    "permissions": [
      "storage"
    ]
  }
}
```

Browsers and Mobile apps need to explicitly declare features that you want to use for security reasons. That's why you will need to specify it in the permissions section of the manifest in the **package.json**.

Now we can use the **useStorage** hook to manipulate a preserved state in our react components.

```typescript
import { useStorage } from "@plasmohq/storage/hook"

const [logo, setLogo] = useStorage("logo", "original")
```

To make our application more user-friendly, we can add our different [SVG](https://github.com/corentinleberre/hiver/tree/main/assets/svg) and custom [styles](https://github.com/corentinleberre/hiver/blob/main/popup.css) in `popup.tsx`.

![Popup.tsx file with styles and useStorage hook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/utf66n5v9h0663oa288g.png)

Users can now select a logo, and the chosen option will be stored and managed using the `useStorage` hook from the `@plasmohq/storage` library. 

To make this code type safe you should define a type LogoType in `types.ts` containing all of your different logo.

![Logo types file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6kgd8808b4a1y5pgcki.png)

Finally your popup should look like this👇

![Final popup result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1bx7cnazy6s8owsrga0.png)

Now that we've managed the popup, we'll move on to the more important task which is to modify the `x.com` page.

👉 Customise the Content Script to modify `x.com` behaviors

To modify the integrity of a web page you will need to add the **"scripting"** permission to the manifest.

Plasmo manages different lifecycles to help you mount and unmount components in the content script. The global process is well described in their [docs](https://docs.plasmo.com/framework/content-scripts-ui/life-cycle). 

![Content.tsx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vhkm1z1eh7ck7qxj73x.png)

To make it concise, you need to create or locate an anchor on the website. In our case, it will be the `x.com` logo with the selector *[aria-label="X"]*. You can then access the local element to modify or replace it by mounting your own component.

In summary, the code below defines a custom `getRootContainer` function that asynchronously looks for a specific HTML, with the attribute `aria-label` set to "X". Once the element appears on the page, the interval is cleared and our new logo is replaced. 

The SVG logos are being dynamically rendered by the components mounted on the page, based on the value that we stored in local storage using `popup.tsx`.

![DisplaySvg.tsx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tjglpewf4yfb1buddo4d.png)

Now that everything's configured, the extension should be fully functional and will allow you to replace the `x.com` logo dynamically according to your preferences. The final step is to build your project and make it available to the world. 🥳

👉 Build the project

Plasmo provides the ability to build your project for different browsers, through the `plasmo package` command. By default, only the Chrome artifact is built.

```bash
npm run build
```

After the build, you will then have the following file structure :

```text
📦 plasmo-intro  
┣ 📂 build
 ┣ 📂 chrome-mv3-dev 
 ┗ 📂 chrome-mv3-prod
```

Finally, you can zip the prod folders and share it as is or [publish it on the Chrome web store](https://developer.chrome.com/docs/webstore/publish/).

## To go further

In this article, I chose a relatively simple example to illustrate Plasmo's key features. If you're interested in the subject, I implore you to take a closer look at their well structured documentation. They also provide a [Github repository with over 50 powerful templates](https://github.com/PlasmoHQ/examples), including Supabase, Tailwind, NextJS, Svelte, React-Router etc.
## Conclusion

Plasmo shows great potential for developing modern extensions without compromising the browsing experience. It allows you to create extensions for different platforms, but you need to be aware of cross-browser API limitations. Despite some unexpected behavior in dev mode, the tool offers several benefits, including rich documentation, an active community, and simplified manifest management. Additionally, it provides SaaS for testing and deployment of extensions across different online stores. This can be very valuable for development teams. 

Despite some challenges, Plasmo framework presents itself as a promising solution for the development of modern extensions!