use create-react-app to develop Chrome extensions
Tags: react, chrome, tutorial, javascript
Published: 2020-07-18 15:24:46

---
canonical_url: https://www.jamalx31.com/tech-posts/use-create-react-app-to-develop-chrome-extensions
---
create-react-app (CRA) is probably the most common way to build, develop, and deploy React apps. A couple of weeks ago, I was working on a [chrome extension](https://chrome.google.com/webstore/detail/reflex-blocker/liadgdammolmojfoikhflaecchkalgmn). I wanted to use CRA to do it, but CRA only supports SPA out of the box.

I found the article [Create Chrome Extension in React](https://dev.to/bayardlouis470/create-chrome-extension-in-react-3pna) by @bayardlouis470, which I used to develop my extension, but there are 3 main issues with his approach:
1. It doesn't support multiple pages (if you want to have options page and popup for your extension)
2. You only use the production build version which makes it harder to debug.
3. After every change in your code, you need to re-run the build cmd

So I decided to take it a step further. Here will be sharing how to customize CRA to fit our needs to develop a chrome extension (a link to the full code at the end).

# Step 1: ⚛ create a react app

``` bash
npx create-react-app extension
```

# Step 2: Modify public/manifest.json
You already have a manifest file created by CRA but we need to change it to match the extension requirements

``` json
{
  "name": "Awesome Extension",
  "version": "0.0.1",
  "manifest_version": 2,
  "description": "create-react-app for extensions",
  "icons": {
    "128": "logo128.png"
  },
  "permissions": [],
  "background": {
    "scripts": [
      "background.js"
    ],
    "persistent": true
  },
  "browser_action": {
    "default_icon": "logo128.png",
    "default_popup": "popup.html"
  },
  "options_page": "index.html"
}
```
Notice that we have `index.html` for the options page, and `popup.html` for our extension popup.

# Step 3: 🏗 Structure
### inside ./src
Go ahead and create (inside src) a folder for the `options` and one for your `popup`. Also, create your `background.js` file.

### inside ./public
duplicate the `index.html` file and rename it to `popup.html`

### inside ./
create `.env` file and add the following
```
INLINE_RUNTIME_CHUNK=false
```
This is important since chrome doesn't allow inline script js code

# Step 4: 🎩 The magic 
Now we need to customize CRA. For this we will be using 4 great packages:
1. customize-cra
2. react-app-rewired
3. copy-webpack-plugin
4. react-app-rewire-multiple-entry

1 & 2 to override CRA webpack default configurations. 3 to copy our static assets and 4 to support multiple pages. so go ahead and install them.
``` bash
npm -i customize-cra react-app-rewired copy-webpack-plugin react-app-rewire-multiple-entry --save-dev
```

Now where all the magic happens. Create `config-overrides.js` in your root folder with the following code

``` javascript
const {
   override,
   overrideDevServer,
   addWebpackPlugin
} = require("customize-cra");
const CopyPlugin = require('copy-webpack-plugin');

const multipleEntry = require('react-app-rewire-multiple-entry')([
   {
      // points to the popup entry point
      entry: 'src/popup/index.js',
      template: 'public/popup.html',
      outPath: '/popup.html'
   },
   {
      // points to the options page entry point
      entry: 'src/options/index.js',
      template: 'public/index.html',
      outPath: '/index.html'
   }
]);

const devServerConfig = () => config => {
   return {
      ...config,
      // webpackDevService doesn't write the files to desk
      // so we need to tell it to do so so we can load the
      // extension with chrome
      writeToDisk: true
   }
}

const copyPlugin = new CopyPlugin({
   patterns: [
      // copy assets
      { from: 'public', to: '' },
      { from: 'src/background.js', to: '' }
   ]
})

module.exports = {
   webpack: override(
      addWebpackPlugin(
         copyPlugin
      ),
      multipleEntry.addMultiEntry,
   ),
   devServer: overrideDevServer(
      devServerConfig()
   ),

};

```

To make everything play together we just need to modify the scripts in `package.json` to use `react-app-rewired` and it will look like this:
```
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  }
```


# Step 5: 🎉 Run & enjoy
Like any other CRA project, run the development cmd with
```
npm run start
```
Wepback will create a `dist` folder Load it as an unpacked extension in Chrome. And when you are ready to publish your extension you can use the build command.

if everything went as planned your popup will look like this. And the best part is if you change your code you will see it instantly 🥳

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bn7l87xt14yb4x24bjjq.png)

# Source code
I published the full [boilerplate](https://github.com/jamalx31/cra-extensions-boilerplate) of on GitHub, so you can check the code if you'd like or just clone to develop your own extension.

# Final thoughts
Room for improvements:
* minimize the background.js file
* optimization
* use webpack-extension-reloader?

Let me know if you have any questions, thoughts or suggestions!