How to set up a chrome extension using React and TypeScript with multiple pages and entry points?

All we need is an easy explanation of the problem, so here it is.

There are plenty of questions and tutorials on this topic, but none of them cover all use cases for a chrome extension, because most of them assume there’s only one entry point.

Here are the requisites:

Multiple “single page applications”:

1) popup.html for the extension pop up page

2) options.html for the options page

3) custom.html this is a custom .html file that the extension can refer to “locally”

Each of these files are entry points for React to manipulate the DOM, but they behave independently of each other.

Non React TypeScript files

They must not be bundled together with any other scripts, and gets compiled to its own JavaScript file, for example a background.ts that compiles to background.js (which is refered to in the manifest.json).

I assume this is doable with TypeScript, React and Webpack but I’m not sure how to approach that.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

There is a custom CRA template that exactly fits your needs: complex-browserext-typescript.


npx create-react-app my-app --template complex-browserext-typescript

By default it sets up 4 entry points associated with page-like extension components:

  • popup (src/index.tsx) – extension’s popup page, replaces the
    default index entry point.
  • options (src/options.tsx) – extension’s options page.
  • background (src/background.ts) – background script.
  • content (src/content.ts) – content script.

However there is an option to exclude any of the above components except the popup from compilation as well as add extra HTML page(s).

Also see this article for usage example.

Method 2

I found a solution but it was not using create-react-app and webpack. It looks like parcel supports multiple entry points out of the box without any configuration.

Assuming a directory structure like this:

├── chrome
│   └── background.ts
├── html
│   ├── custom.html
│   ├── options.html
│   └── popup.html
├── manifest.json
├── package.json
├── react
│   ├── custom.tsx
│   ├── options.tsx
│   └── popup.tsx

With Parcel.js you simply do:

parcel build html/*.html react/*.tsx chrome/*.ts

And it will handle the multiple entry points. I created a repository that contains a template for that approach, it contains a fully runnable example.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply