Setting up Chrome extension with ReactJs

In this article we are going to discuss how to setup reactJs to create a chrome extension. First we are going to look how to setup chrome extension without ReactJs and then with ReactJs using webpack.

lets just create a directory name my-extension we can name it whatever we want. Now navigate into the my-extension directory. Create a file called manifest.json which will look something like this.

{
    "manifest_version":2,
    "name":"Word Defination",
    "version":"1.0.0",
    "content_scripts":[
        {
            "matches" :[
                "<all_urls>"
            ],
            "js":["content.js"]
        }
    ],
    "background": {
        "scripts":["background.js"]
    },

    "browser_action": {
        "default_popup": "popup.html",
        "default_title":"Lookup a defination"
    }

}

Here I have choose to use manifest_version: 2 you are free to choose version 3 as well. There are few changes in manifest file structure from version 2 to version 3. Please refer the official docs for this. developer.chrome.com/docs/extensions/mv3

I am not going to explain every line here that we will discuss in separate article. Here the important part is the files we need to create we are going to create 3 files as below.

- background.js
- popup.html
- content.js

All the files should be in the root directory as we have mentioned in manifest.json file. So this is the basic intro to how to setup file for chrome extension. Now we will discuss how to achieve same with the webpack and reactjs.

Let's initialise a package.json by running this command in terminal.

npm init -y

After package.json is initialise we need to update it to something like this.

{
  "name": "extension-react",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "webpack --watch --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "@babel/core": "^7.16.0",
    "@babel/preset-env": "^7.16.4",
    "@babel/preset-react": "^7.16.0",
    "babel-loader": "^8.2.3",
    "copy-webpack-plugin": "^10.0.0",
    "css-loader": "^6.5.1",
    "html-webpack-plugin": "^5.5.0",
    "style-loader": "^3.3.1",
    "webpack": "^5.64.4",
    "webpack-cli": "^4.9.1",
    "webpack-merge": "^5.8.0"
  }
}

Now we will create a public directory and put our manifest.json file in it. we will also create a directory called src in which we will put all our files.

Inside src we will create the following files.

- background.js
- content.js
- popup.html
- popup.jsx
- popup.css

Our popup.html will look something like this.

<!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-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

It's just an html code with div with an id="root". Now we will target this div from the popup.jsx which will look something like this.

import React, { useState } from "react";
import { render } from "react-dom";
import "./popup.css";

function Popup() {
  return (
    <div>
      <p>Chrome Extension</p>
    </div>
  );
}

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

Now in the final setup we will setup our webpack.config.js. Our webpack.config.js will look something like this.

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
  entry: {
    popup: "./src/popup.jsx",
    background: "./src/background.js",
    content:"./src/content.js"
  },
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"],
          },
        },
      },
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/popup.html",
      filename: "popup.html",
    }),
    new CopyPlugin({
      patterns: [{ from: "public" }],
    }),

  ],
};

We can also setup our development and production environment by creating saparate file for webpack.dev.js and webpack.production.js.

 // - webpack.dev.js

const {merge}  = require('webpack-merge');
const config = require('./webpack.config.js');

module.exports = merge(config, {
    mode: 'development',
    devtool:'inline-source-map'
})

For Production

const {merge}  = require('webpack-merge');
const config = require('./webpack.config.js');

module.exports = merge(config, {
    mode: 'production',
})

After following the above structure you file structure will look something like this.

- my-extension
     - public/manifest.json
     - src/ 
           - background.js
           - content.js
           - popup.html
           - popup.css
           - popup.jsx
      - package.json
      - webpack.config.js
      - webpack.dev.js
      - webpack.prod.js

Now after all this step we will run then command to run our extension.

npm run dev

Once you enter this command and hit enter in your terminal. You will able to see a dist directory created by our webpack. Inside dist directory you will able to see the same file structure that we have discussed at the start of the article.

Hope this article will help you in creating your chrome extension with reactJS. For any question you can put comment below. This is my first article on hashnode if you find any mistake feel free to notify me.

Did you find this article valuable?

Support aditya kumar by becoming a sponsor. Any amount is appreciated!