React Browser Extension

Published on

Introduction

Creating a browser extension for Chrome using React is a great way to get started with developing for the web. I liked browser extensions already before I knew how to create one myself. There were times when I had 20 extensions added to my Chrome at the same time. Of course I was not using all of them but it shows that there really are a lot of tools and features for sites already out there for you to explore or get inspired. The cool thing about them is that you can basically use them to create content on any site that helps you make decisions or shows certain metrics that nobody else can. For example I created a tool that helped me to rate the rarity of certain NFT collections. But that is just one example. You might want to compare prices on amazon or show data in graphs. With browser extensions you can do that.

How to get it done

In the following I will show you the exact steps how to create a browser extension for Chrome using React.

Getting started

Create a new folder and run

npm init

Create the initial folder structure and add the following files:

langs

Then inside these folders create the following files:

langs

Manifest file

For a browser extension to work it needs a manifest.json file. This file is a json file that describes the extension. The manifest file is the first file that gets loaded when the extension is initialized and it tells the browser what to do and where to find the files that it needs. You can find out more about that on the Chrome developer site.

// manifest.json
{
  "name": "Getting Started Example",
  "description": "Build an Extension!",
  "version": "1.0",
  "manifest_version": 3
  "browser_action": {
		"default_popup": "popup.html"
	},
}

This is the most basic version of the manifest file. It is basically the getting started version from the Chrome developer site with the addition of the browser action.

popup.html file

Next we create the content of the popup.html file that will be shown when the browser action is clicked.

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scal=1.0" />
		<title>Document</title>
	</head>
	<body>
		<div id="react-root"></div>
	</body>
</html>

install react

npm i --save react react-dom

popup.jsx file

In our popup.jsx file we will create the content that will be shown inside the popup.html file that we created. So we will define the components that will be rendered inside the react-root div in our popup.html file.

import React from "react";
import { render } from "react-dom";

function Popup(props) {
	return (
		<div className="popup">
			<div className="popup_inner">{props.children}</div>
		</div>
	);
}

render(<Popup />, document.getElementById("react-root"));

Webpack

Since the browser is not able to load the files directly we need to use webpack to bundle the files first. The reason for this is that the browser can not simply open the files directly as they are node and not javascript files. Instead we will need to create static hmtl and javascript files for the browser to be able to load our extension. The process for this is relatively simple but the setup of webpack can be a bit of a pain. So we will try to keep it simple.

First create a webpack.config.js file in the root of the project.

// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
	// pages to convert
	entry: {
		popup: "./src/popup.jsx",
		// further pages to be converted to js
	},
	// output files and output path
	output: {
		path: path.resolve(__dirname, "dist"),
		filename: "[name].js",
	},
	module: {
		rules: [
			{
				// loader will execute for js or jsx files
				test: /\.(js|jsx)$/,
				// exclude node_modules from conversion
				exclude: /node_modules/,
				// babel loader to convert jsx to js
				use: {
					loader: "babel-loader",
					options: {
						presets: ["@babel/preset-env", "@babel/preset-react"],
					},
				},
			},
		],
	},
};

For the code above to be working we will need to do two things.

  1. First we need to install the babel and babel/preset-react packages.
npm i --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react
  1. Second we need to add the a new script in the package.json file for the webpack command to build the extension.
// package.json
...
	"scripts": {
		"build": "webpack --config webpack.config.js"
	},
...

Now our conversion would already work and you can test that by writing npm run build in the terminal. You should see the extension beeing build in the dist folder.

The issue that we still have with the webpack setup is that the extension like this is not able to load the files directly, because it is missing its center piece of the extension which is the popup.html file and all our static files as well. We could add the popup.html file to the dist folder manually every time we build but as we are still using webpack we can use the CopyPlugin to copy the files from the public folder to the dist folder. And use the HtmlWebpackPlugin to add the popup.html file to the dist folder.

Lets first install our dependencies.

npm i --save-dev copy-webpack-plugin html-webpack-plugin

To make the rest happen we need to add the CopyPlugin and the HtmlWebpackPlugin to the plugins array in the webpack.config.js file.

// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
	// pages to convert
	entry: {
		popup: "./src/popup.jsx",
		// further pages to be converted to js like background.js
	},
	// output files and output path
	output: {
		path: path.resolve(__dirname, "dist"),
		filename: "[name].js",
	},
	module: {
		rules: [
			{
				// loader will execute for js or jsx files
				test: /\.(js|jsx)$/,
				// exclude node_modules from conversion
				exclude: /node_modules/,
				// babel loader to convert jsx to js
				use: {
					loader: "babel-loader",
					options: {
						presets: ["@babel/preset-env", "@babel/preset-react"],
					},
				},
			},
		],
	},
	// plugins
	plugins: [
		new HtmlWebpackPlugin({
			template: "./src/popup.html",
			filename: "popup.html",
		}),
		new CopyPlugin({
			patterns: [{ from: "public" }],
		}),
	],
};

Open Extension in Chrome

To load the extension in Chrome we need to open the chrome://extensions page in Chrome and click or the extension icon in your extensions section in the Browser.

langs
  1. Enable developer mode in Chrome
  2. Load unpacked extension in Chrome

Now you have your extension loaded in Chrome and you can click it in the top right corner of the browser to see the popup.

Enhance your Extension from here

How to enhance your extension from here?

  1. You cann add new pages to the extension like background.js. If you want to do so you need to remember to add those files to the entry object in the webpack.config.js file and your manifest.json file.
  2. You can add new components and import them in the popup.jsx file.

Bonus Dev Tip

Open the adress chrome-extension://<extensionid>/popup.html in your browser. Exchange the <extensionid> with the extension id of your extension. You can find the ID generated by Chrome on your extensions page. See the image above. With this setup you can now debug your extension in Chrome just like a regular webpage.

Affiliate Disclaimer
Disclaimer:
Links on the site might be affiliate links, so if you click them I might earn a small commission.