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.
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.
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.
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
npm create plasmo plasmo-intro
cd plasmo-intro
npm run dev
You will then have the following file structure :
π¦ plasmo-intro
β£ π assets
β£ π build
β£ π package.json
β£ π popup.tsx
β£ π README.md
β π tsconfig.json
Now you can load the extension in your favorite browser
π 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.
π 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.
npm install @plasmohq/storage
more docs about Plasmo storage here
// 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.
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 and custom styles in popup.tsx
.
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.
Finally your popup should look like thisπ
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.
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
.
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.
npm run build
After the build, you will then have the following file structure :
π¦ 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.
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, 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!
Top comments (1)
The whole point of (most) browser extensions is that they are small, efficient, and do a single job well. Quite why you'd want to bloat them up with an entire framework like React/Vue/etc. is beyond me. In most cases this is simply prioritising 'ease' of use and familiarity for lazy developers, at the expensive of essentially packing your browser with bloatware.
Granted there are some bigger, complex things that you may want to build into a browser extension - and for those, including a framework and libraries might well be a good idea. For your average browser extension (and stuff like your sample) - this is definitely overkill... using a sledgehammer to crack a nut.