How to configure Vite/React to build a Google Chrome (Web) Extension
Tags: vite, react, tutorial
Published: 2023-04-13 14:17:51

This is how I set up Vite to meet my requirements for building a Web Extension for Google Chrome, since other Browsers also support Web Extensions with Manifest v3 it should also apply to Firefox, Edge and Safari.

## Create a new project

I am going to use React for this extension, so the first step  is to create a new React/Typescript project:

```
npm create vite@latest
? Project name: › my-web-extension
? Select a framework: › React
? Select a variant: › TypeScript
cd my-web-extension
npm i
git init
git add --all
git commit -m "blank vite react/typescript project"
```

## Setup ESLint

For linting I am used to the create-react-app config, fortunately this is maintained in a dedicated package: https://www.npmjs.com/package/eslint-config-react-app 

1. Install the required packages:

```npm install --save-dev eslint-config-react-app eslint@^8.0.0```

2. To configure ESLint create a `.eslintrc.json` file in the root of the project and add this configuration:
```json
{
  "extends": "react-app"
}
```
> Alternatively you can add your config to the `eslintConfig` field of `package.json`

If ESLint is integrated into your editor, you should already see that it complains about the `target="_blank"` links in `src/App.tsx` not having `rel="noreferrer"`.

Commit your changes.

## Add a Manifest and multiple entry points

To make your output get recognized as a Web Extension there has to be a Manifest file in the output folder. 

Per default Vite will copy all content of the folder `public` to the output directory when building, so we just have to add the manifest file in there: `public/manifest.json`

As a starter we are just going to add an options page and a browser action to the extension:

```json
{
    "manifest_version": 3,
    "name": "My Web Extension",
    "version": "0.0.1",
    "description": "A Web Extension created with Vite",
    "options_page": "options.html",
    "action": {
        "default_title": "View all available tests",
        "default_popup": "popup.html"
    }
}
```

As you might have noticed the two pages `options.html` and `popup.html` do not exist yet. 

Vite supports [multi-page apps](https://vitejs.dev/guide/build.html#multi-page-app) with multiple .html entry points. To use this feature we have to create both files and specify them as entry points in `vite.config.js`:

```javascript
import { resolve } from 'path'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  build: {
    rollupOptions: {
      input: {
        main: resolve(__dirname, 'index.html'),
        popup: resolve(__dirname, 'popup.html'),
        options: resolve(__dirname, 'options.html'),
      },
    },
  },
})
```

For testing I just duplicated the original `index.html` twice and renamed it to `popup.html` and `options.html` respectively.

If your editor complains about missing types for `path` and `__dirname` this is because we did not yet install the types for node.

```
npm install --save @types/node
```

## Build and run

That's it, time to run `npm run build` to build the extension. If you are using Google Chrome you can now load the extension in Settings/Extensions by clicking on "Load unpacked" and selecting the `dist` folder of this project.

Repository: https://github.com/receter/vite-minimal-web-extension

Happy coding!