DEV Community

Cover image for Create Chrome Extension in React
Louis Bayard
Louis Bayard

Posted on

React Chrome Extension Create Chrome Extension in React

When I moved to Edge weeks ago, I found there's no built-in strong password generator in Edge. Then I decide write one for it.

Most of the extensions on marketplace are write many years ago, and they were written in raw HTML, CSS and JavaScript. But we have React and UI component libraries now, life should be easier.

The problem I soon found is there's almost no tutorial for a React extension anywhere. That's why I decide to share everything here.

Star the repo on Github or leave a review on Edge Addons Store are both welcome!

Features of the extension

Strong Password Generator Screenshot

It generates a 15 characters long password with lowercased letters, uppercased letters, numbers and symbols.

But it won't like Chrome built-in password manager, it doesn't:

  • copy to clipboard automatically
  • fill in the password/confirm field in web page
  • manage/backup your password somewhere, not in cloud, not even do it locally

It does:

  • keep everything running in client side, that means no server at all
  • manual copy to clipboard

I tried to make it as simple as a one-day-job. Anyone who follows this tutorial could submit your own extension to Chrome Web Store or Microsoft Edge Extension Addons(what a long name) in a single day(but from my experience, Microsoft need 2-3 days to approve your submission).

Extension Basic

Before dive into the details, I want to explain a little the basic structure of an extension of chromium based browser.

This extension structure works on Chrome, Edge and Brave, and maybe other Chromium based browsers I don't know.

There're several key parts of an extension:

Strong Password Generator Extension

manifest

manifest describes what's in the source package. It specified where browser could find background, content script, popup and option pages. As well as it describes permissions required by the extension.

background

A piece of code which is launched when the extension launched, and won't be terminated until extension removed or browser shutdown.

Background code has access to all chrome APIs, other parts are limited. But background doesn't have an UI and can not access DOM.

popup

The UI which is popped up while user click on 'browser action' which is your extension icon button right to the browser address bar.

Most extensions need a popup as entry.

options

It's an optional part of the extension. Not all extensions has an options page. It is used as a configuration UI for the extension. Your extension has to provide an entry for it.

If you have some something complicated to be configured, you need this.

content script

Content script is a piece of JavaScript which runs in a tab with specific URL. the URL pattern is defined in manifest.json. If the URL matched with which is specified in manifest.json, browser will launch the content script. It will be terminated while the URL changed, or tab closed.

If you want to manipulate DOM, you need content script.

So you should already have idea of what these parts are doing now.

Which parts involved in Strong Password Generator extension

Background, not in this tutorial, but there's an empty background.js in repo, just for future use.

Popup, yes. That's the focus of this article. I will show you how to write a Popup in React + Material.

Options, no.

Content script, no.

Start from scratch

Here're 5 steps to create an extension in React from scratch.

Step 1: create a react app

$npx create-react-app extension
Enter fullscreen mode Exit fullscreen mode

This will create a regular react app. Everything else are growing from this seed app.

Step 2: Modify public/manifest.json

You've already had a public/manifest.json after CRA(create-react-app). Change the file as below:

{
    "name": "Strong Password Generator",
    "version": "1.0.0",
    "manifest_version": 2,
    "description": "Strong password generator",
    "icons": {
        "512": "logo512.png"
    },
    "browser_action": {
        "default_icon": "logo512.png",
        "default_popup": "popup.html"
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a build script(script/build.sh)

#!/bin/bash

build() {
    echo 'building react'

    rm -rf dist/*

    export INLINE_RUNTIME_CHUNK=false
    export GENERATE_SOURCEMAP=false

    react-scripts build

    mkdir -p dist
    cp -r build/* dist

    mv dist/index.html dist/popup.html
}

build
Enter fullscreen mode Exit fullscreen mode

There're 2 things did in this script:

  • build react app with some specific environment variables set
  • renamed index.html into popup.html

INLINE_RUNTIME_CHUNK=false disabled webpack generating inline JavaScript in HTML. Normally webpack will put its own runtime into HTML inline script. But inline script is not allowed by browser extension.

Rename index.html into popup.html because it is required to be popup.html in manifest.json.

After create script/build.sh, don't forget add x permission:

chmod +x script/build.sh
Enter fullscreen mode Exit fullscreen mode

Step 4: Modify package.json

modify scripts like below:

"scripts": {
    "start": "react-scripts start",
    "build": "./script/build.sh",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
},
Enter fullscreen mode Exit fullscreen mode

Step 5: Build and load into Chrome(or Edge)

$npm run build
Enter fullscreen mode Exit fullscreen mode

Then you will get a 'dist' directory. Load it as unpacked extension in Chrome or Edge. You would see:

Alt Text

The React extension is running.

To be continue

There're still pending issues for a serious extension, like:

  • How to handle Options page? It's another page rather than Popup, but CRA created a SPA.
  • Is there any performance issue to write extension in React?
  • My content script is going to inject some UI component into host pages, can React be applied in this scenario?

And maybe some other topics not related to React too much but still important for a serious extension:

  • How to obfuscate source code, especially background.js
  • I'm going to introduce Firebase in my extension, any tips?

All the above will be discussed in the next post if someone interests into these questions. Leave a comment below if you have any other questions, suggestions, any feedback are welcome.

Discussion (28)

Collapse
vasilyshelkov profile image
Vasily Shelkov

Hi, I've created a repo in order to skip having to do these steps which I aim to maintain in case anyone is interested. You can check out the github repo

or just try it out:

npx create-react-app my-browser-extension --scripts-version react-browser-extension-scripts --template browser-extension
Enter fullscreen mode Exit fullscreen mode

or for typescript support

npx create-react-app my-browser-extension --scripts-version react-browser-extension-scripts --template browser-extension-typescript
Enter fullscreen mode Exit fullscreen mode
Collapse
dim0147 profile image
Bon

Thanks u

Collapse
rajvirsingh1313 profile image
Rajvir Singh

Can you add some examples in your readme like I am trying to make my own BlockSite extension, just for fun.

Collapse
619 profile image
Bobby

Reactjs in a chrome extension completely ruins the built in message passing capabilities. I found that using reactJS for my popup, background, and content scripts meant none of the 3 parts could talk to each other anymore.

Collapse
nemrosim profile image
Artem Diashkin

I'm describing this issue here:
medium.com/litslink-frontend-devel...

Collapse
mihailthebuilder profile image
Mihail Marian

What alternative do you use? vanilla JS + webpack?

Collapse
nyashanziramasanga profile image
Nyasha (Nash) Nziramasanga

Thanks for sharing was extremely helpful, for anyone using React + TypeScript you can use: $npx create-react-app my-app --template typescript in Stage 1 instead of $npx create-react-app extension

Collapse
spothedog1 profile image
Ron Basumallik

Hello, how could I include an Image in the Popup? I'm trying to include a button in the Popup with an image as the button but I can't figure out how to import the image. The source image file isn't reachable by the Popup. Thanks

Collapse
pradeepradyumna profile image
Pradeep Pradyumna

Good one! Thanks for posting.

Collapse
decoder314 profile image
Ali H. Dulaimi

For windows users, use "build": "sh ./script/build.sh" as the build command

Collapse
deepakshrma profile image
Deepak Vishwakarma

you don need all these script.
To pass u u can create .env file

REACT_APP_INLINE_RUNTIME_CHUNK=false
REACT_APP_GENERATE_SOURCEMAP=false
REACT_APP_BUILD_PATH=dist
Enter fullscreen mode Exit fullscreen mode

and for move file

MACHINE="$(uname -s)"
if [[ $MACHINE =~ "Darwin" ]]; then
    mv dist/index.html dist/popup.html
else
    move dist\index.html dist\popup.html
fi
Enter fullscreen mode Exit fullscreen mode
Collapse
fishsticks89 profile image
fishsticks89

Why did you change generate sourcemap to false?

Collapse
gabrielqmatos88 profile image
Gabriel Q. Matos

Nice :D, It's very interesting

Collapse
itslooklike profile image
Alexey Masalov

What is the point of creating a dist folder? why is build not suitable by default?

Collapse
semivori profile image
Vlad Osadchy

How run script/build.sh on Windows?

Collapse
ngoc199 profile image
Migo

You can type in your command prompt bash ./script/build.sh

Collapse
fishsticks89 profile image
fishsticks89

if you have git bash you can run

bash build.sh

Collapse
madrus profile image
Andre Roussakoff

Good article. Thanks. The extension should also work for Yandex browser.

Collapse
brettfinlay profile image
BrettFinlay

Like it

Collapse
sebazc profile image
Sebastián Azcárate

Awesome!

Collapse
oh_jeez_rick profile image
Gavin Chan

thank you

Collapse
yacinehechmi profile image
yacine717

thank you

Collapse
vasilyshelkov profile image
Vasily Shelkov

Great article though :) and I definitely haven't tackled some questions like:

Is there any performance issue to write extension in React?

Collapse
ajyjk7 profile image
ajyjk7

I'm going to introduce Firebase in my extension, any tips?

Collapse
carolbrodie profile image
CarolBrodie

Hi Louis,

Thanks for the sharing, may I know what's the size of your extension package?

Collapse
bayardlouis470 profile image
Louis Bayard Author

Everything in /dist directory: ~290KB
The package in chrome web store is compressed, it's ~100KB

Basically it's the size of a minimum React app.

Collapse
carolbrodie profile image
CarolBrodie

Thanks