Create a Chrome Extension with React FW Plasmo
Tags: javascript, react, typescript, chrome
Published: 2023-10-20 16:55:18

## Context
Recently, I created a Chrome Extension called 'hosts-modifier' with Plasmo. It allows users to effortlessly redirect domain requests without the need to modify thier hosts file. Even though it was my first time publishing, the development process was smooth. So, in this article, I would like to share how to develop a Chrome Extension with Plasmo.

{% embed https://chrome.google.com/webstore/detail/hosts-modifier/cmjkafkhlfpegnlhphhbpfbdblmkmden?hl=ja&authuser=0 %}

{% embed https://github.com/yamashita-ki/hosts-modifier %}

## What is Plasmo?
[Plasmo](https://docs.plasmo.com/) is a React framework designed for creating browser extensions.

> With Plasmo, you can say goodbye to tedious boilerplate code and hello to a faster, more seamless development experience.

Let's get started to create an easy Chrome Extension.

### Features
- First-class React + Typescript Support
- Live-reloading + React HMR
- Optional support for Svelte and Vue
- Remote code bundling (e.g., for Google Analytics)

https://docs.plasmo.com/framework

## Getting Started

###  Create the project
Developers can choose their favorite package manager.
In this article, I would like to choose pnpm due to its strong recommendation in the official documentation. 

>**System Requirements**
Node.js 16.14.x or later
macOS, Windows, or Linux
(Strongly Recommended) pnpm


```
pnpm create plasmo
# OR
yarn create plasmo
# OR
npm create plasmo
```

After answering few questions, you will see the following file structure.

![plasmo file structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jnd501vq0g4schj3u8z.png)

`popup.tsx` :  A default React component that gets rendered into your popup page.
`assets` : A directory for applying icons. Plasmo provides a default icon, but to publish your extension, you'll need various icon sizes (16×16, 48×48, 128×128 in PNG format).
`.github` : Contains GitHub Actions workflows for automated deployment.

###  Development Server
By executing this command, Plasmo generates a `chrome-mv3-dev` directory. 

```
pnpm plasmo dev
```

Next, toggle on the developer mode:

chrome://extensions/

![developer mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/taec1m5me9fhyzsoe7ai.png)

From the [Load unpacked] option, developers can upload and view their extensions.

![upload a chrome extension](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zaa8tx4yv0vtcpbbdda.png)


## background and content_script 
Chrome extensions primarily consist of two main components: content scripts and background scripts. The differences between them are as follows:

Content Scripts: These scripts directly interact with the web page the user is viewing. Handling the web page DOM.

Background Scripts: These run in the background while Chrome is active, essentially like an invisible tab. They provide functionalities that are independent of the web pages and are browser-specific. Can not handling the web page DOM.

In Plasmo to use background scripts, create a background.ts and add below sentence on `package.json`.

```json
"background": {
      "service_worker": "background.js",
      "persistent": false
    },
```

## Convenient Chrome API

These are just brief overviews of what each API offers. For a comprehensive understanding and to explore more functionalities, it's recommended to refer to the official [Chrome API documentation](https://developer.chrome.com/docs/extensions/reference/).

### Storage API
The Chrome Storage API provides a way to store and retrieve key-value pairs in a persistent manner. Unlike cookies or local storage in web pages, the storage managed by extensions is separate and persists even when the browser is closed. This makes it a powerful tool for extensions that need to maintain state or save user preferences.

#### Using the Storage API
To use the Storage API, you first need to declare the "storage" permission in your extension's package.json:

```json
{
  "permissions": ["storage"]
}
```

Once you have the necessary permissions, you can use the `chrome.storage.local` or `chrome.storage.sync` methods to save and retrieve data.

#### Local Storage:
`chrome.storage.local` provides a large amount of storage space for data that does not need to be synced across devices.

```javascript
// Setting a value
chrome.storage.local.set({key: 'value'}, function() {
  console.log('Value is set to ' + value);
});

// Getting a value
chrome.storage.local.get(['key'], function(result) {
  console.log('Value currently is ' + result.key);
});
```

#### Synced Storage:

`chrome.storage.sync` allows you to store a limited amount of data that will be synced across all instances of the browser that the user is logged into.


```javascript
// Setting a value
chrome.storage.sync.set({key: 'value'}, function() {
  console.log('Value is set to ' + value);
});

// Getting a value
chrome.storage.sync.get(['key'], function(result) {
  console.log('Value currently is ' + result.key);
});
```

### Tabs API
The Tabs API allows extensions to interact with the browser's tab system. By requesting the "tabs" permission in the `package.json`, the extension can access information about open tabs, create new tabs, and perform various other tab-related operations. The sample code queries the currently active tab in the browser window and logs its URL.

```json
{
  "permissions": ["tabs"]
}
```

```javascript
// Query the active tab in the current window
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  var currentTab = tabs[0];
  console.log(currentTab.url);
});
```

## Conclusion
By using Plasmo to create extensions, you'll not only gain proficiency in React and TypeScript but also deepen your understanding of the various APIs provided by Chrome. Publishing an extension doesn't require much expense, allowing you to share your favorite features with the world without any regrets.