Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite

Chrome Extension Boilerplate with React + Vite + Typescript
https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite

Last synced: 2 months ago
JSON representation

Chrome Extension Boilerplate with React + Vite + Typescript

Lists

README

        


logo

Chrome Extension Boilerplate with
React + Vite + TypeScript

![](https://img.shields.io/badge/React-61DAFB?style=flat-square&logo=react&logoColor=black)
![](https://img.shields.io/badge/Typescript-3178C6?style=flat-square&logo=typescript&logoColor=white)
![](https://badges.aleen42.com/src/vitejs.svg)
![GitHub action badge](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/actions/workflows/build-zip.yml/badge.svg)
hits

> This project is listed in the [Awesome Vite](https://github.com/vitejs/awesome-vite)

## Table of Contents

- [Intro](#intro)
- [Features](#features)
- [Installation](#installation)
- [Procedures](#procedures)
- [Chrome](#chrome)
- [Firefox](#firefox)
- [Add Style Library](#add-style-library)
- [Twind](#twind)
- [Chakra UI](#chakra-ui)
- [Pages](#pages)
- [Screenshots](#screenshots)
- [NewTab](#newtab)
- [Popup](#popup)
- [Devtools](#devtools)
- [Examples](#examples)
- [Documents](#documents)

## Intro

This boilerplate is made for creating chrome extensions using React and Typescript.
> The focus was on improving the build speed and development experience with Vite.

## Features

- [React 18](https://reactjs.org/)
- [TypeScript](https://www.typescriptlang.org/)
- [Vitest](https://vitest.dev/)
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
- [Vite](https://vitejs.dev/)
- [SASS](https://sass-lang.com/)
- [Prettier](https://prettier.io/)
- [ESLint](https://eslint.org/)
- [Husky](https://typicode.github.io/husky/get-started.html#automatic-recommended)
- [Commitlint](https://commitlint.js.org/#/guides-local-setup?id=install-commitlint)
- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary)
- [Chrome Extension Manifest Version 3](https://developer.chrome.com/docs/extensions/mv3/intro/)
- HRR(Hot Rebuild & Refresh/Reload)

## Installation

## Procedures:

1. Clone this repository.
2. Change `extensionDescription` and `extensionName` in messages.json
3. Install pnpm globally: `npm install -g pnpm` (check your node version >= 16.6, recommended >= 18)
4. Run `pnpm install`

## And next, depending on the needs:

### For Chrome:

1. Run:
- Dev: `pnpm dev` or `npm run dev`
- Prod: `pnpm build` or `npm run build`
2. Open in browser - `chrome://extensions`
3. Check - `Developer mode`
4. Find and Click - `Load unpacked extension`
5. Select - `dist` folder

### For Firefox:

1. Run:
- Dev: `pnpm dev:firefox` or `npm run dev:firefox`
- Prod: `pnpm build:firefox` or `npm run build:firefox`
2. Open in browser - `about:debugging#/runtime/this-firefox`
3. Find and Click - `Load Temporary Add-on...`
4. Select - `manifest.json` from `dist` folder

### Remember in firefox you add plugin in temporary mode, that's mean it's disappear after close browser, you must do it again, on next launch.

## Add Style Library

> IMPORTANT: If you DO NOT want to use css file in the content script, you need to delete the css file in your
> manifest.js

```js
content_scripts: [
{
// YOU NEED TO DELETE THIS
css: ["assets/css/contentStyle.chunk.css"]
}
];
```

### Twind

> The smallest, fastest, most feature complete Tailwind-in-JS solution in existence

**1. Install the library:**

```bash
$ pnpm install -D @twind/core @twind/preset-autoprefix @twind/preset-tailwind
```

**2. Create twind.config.ts in the root folder**

twind.config.ts

```ts
import { defineConfig } from '@twind/core';
import presetTailwind from '@twind/preset-tailwind';
import presetAutoprefix from '@twind/preset-autoprefix';

export default defineConfig({
presets: [presetAutoprefix(), presetTailwind()],
});
```

**3. Create src/shared/style/twind.ts for importing**

src/shared/style/twind.ts

```ts
import { twind, cssom, observe } from '@twind/core';
import 'construct-style-sheets-polyfill';
import config from '@root/twind.config';

export function attachTwindStyle(
observedElement: Element,
documentOrShadowRoot: T,
) {
const sheet = cssom(new CSSStyleSheet());
const tw = twind(config, sheet);
observe(tw, observedElement);
documentOrShadowRoot.adoptedStyleSheets = [sheet.target];
}
```

**4. You can use Tailwind in your project:**

src/pages/popup/index.tsx

```tsx
import { attachTwindStyle } from '@src/shared/style/twind';

...
attachTwindStyle(appContainer, document);
const root = createRoot(appContainer);
root.render();
```

**5. If you want to use Twind in the content script, you need to add the following code:**

src/pages/content/ui/root.tsx

```tsx
import { attachTwindStyle } from '@src/shared/style/twind';

...
attachTwindStyle(rootIntoShadow, shadowRoot);
createRoot(rootIntoShadow).render();
```

[See more examples](https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite/pull/244/)

### Chakra UI

**1. Install the library:**

```bash
$ pnpm install @chakra-ui/react @emotion/cache @emotion/react
```

**2. You should add the code to `vite.config.ts`
for [Ignore unnecessary warnings](https://github.com/TanStack/query/pull/5161#issuecomment-1506683450)**

vite.config.ts

```ts
export default defineConfig({
build: {
rollupOptions: {
// Add below code ~~~~~
onwarn(warning, warn) {
if (
warning.code === "MODULE_LEVEL_DIRECTIVE" &&
warning.message.includes(`"use client"`)
) {
return;
}
warn(warning);
},
// Add above code ~~~~
},
},
});
```

**3. You can use Chakra UI in your project:**

src/pages/popup/Popup.tsx

```tsx
import { Button } from "@chakra-ui/react";

export default function Popup() {
return (

Button;

);
}
```

---

> if you don't want to use Chakra UI in the content script, you can skip 4,5 step.

**4. If you want to use Chakra UI in the content script, you need to add the following code:**

src/pages/content/ui/CustomChakraProvider.tsx

```tsx
import { ReactNode, useCallback, useEffect, useState } from "react";
import {
ColorMode,
ColorModeContext,
ColorModeScript,
CSSReset,
extendTheme,
GlobalStyle,
ThemeProvider
} from "@chakra-ui/react";

const theme = extendTheme();

const getCurrentTheme = () => {
const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
return isDark ? "dark" : "light";
};

type CustomChakraProviderProps = {
shadowRootId: string;
children: ReactNode;
};
export default function CustomChakraProvider({ children, shadowRootId }: CustomChakraProviderProps) {
const [colorMode, setColorMode] = useState(getCurrentTheme());

useEffect(() => {
const darkThemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const onChangeColorSchema = (event: MediaQueryListEvent) => {
const isDark = event.matches;
setColorMode(isDark ? "dark" : "light");
};

darkThemeMediaQuery.addEventListener("change", onChangeColorSchema);

return () => {
darkThemeMediaQuery.removeEventListener("change", onChangeColorSchema);
};
}, []);

const toggleColorMode = useCallback(() => {
setColorMode(prev => (prev === "dark" ? "light" : "dark"));
}, []);

return (





{children}


);
}
```

src/pages/content/ui/EmotionCacheProvider.tsx

```tsx
import createCache from '@emotion/cache';
import { CacheProvider, type EmotionCache } from '@emotion/react';
import { ReactNode, useEffect, useState } from 'react';

export default function EmotionCacheProvider({ children, rootId }: { rootId: string; children: ReactNode }) {
const [emotionCache, setEmotionCache] = useState(null);

useEffect(() => {
function setEmotionStyles(shadowRoot: ShadowRoot) {
setEmotionCache(
createCache({
key: rootId,
container: shadowRoot,
}),
);
}

const root = document.getElementById(rootId);
if (root && root.shadowRoot) {
setEmotionStyles(root.shadowRoot);
}
}, []);

return emotionCache ? {children} : null;
}
```

**5. Fix the `src/pages/content/ui/root.tsx` file:**

src/pages/content/ui/root.tsx

```tsx
import CustomChakraProvider from '@pages/content/ui/CustomChakraProvider';
import EmotionCacheProvider from '@pages/content/ui/EmotionCacheProvider';

// ...

createRoot(rootIntoShadow).render(
// Add Providers




,
);

```

## Pages

### New Tab

[Override Chrome pages](https://developer.chrome.com/docs/extensions/mv3/override/)
`chrome_url_overrides.newtab` in
manifest.json

### Popup

[Browser actions](https://developer.chrome.com/docs/extensions/reference/browserAction/)
`action.default_popup` in
manifest.json

### Devtools

[Devtools](https://developer.chrome.com/docs/extensions/mv3/devtools/#creating)
`devtools_page` in manifest.json

### Background

[Background](https://developer.chrome.com/docs/extensions/mv3/background_pages/)
`background.service_worker` in
manifest.json

### ContentScript

[Content Script (contentInjected/contentUI)](https://developer.chrome.com/docs/extensions/mv3/content_scripts/)
`content_scripts`
in
manifest.json

### Options

[Options](https://developer.chrome.com/docs/extensions/mv3/options/)
`options_page` in manifest.json

### SidePanel (Chrome 114+)

[SidePanel](https://developer.chrome.com/docs/extensions/reference/sidePanel/)
`side_panel.default_path` in
manifest.json

## Screenshots

### New Tab

newtab

### Popup

| Black | White |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| black | white |

### Devtools

devtools

## Examples

- https://github.com/Jonghakseo/react-code-finder-extension
- https://github.com/Jonghakseo/drag-gpt-extension
- https://github.com/Jonghakseo/pr-commit-noti
- https://github.com/ariburaco/chatgpt-file-uploader-extended

## Documents

- [Vite Plugin](https://vitejs.dev/guide/api-plugin.html)
- [ChromeExtension](https://developer.chrome.com/docs/extensions/mv3/)
- [Rollup](https://rollupjs.org/guide/en/)
- [Rollup-plugin-chrome-extension](https://www.extend-chrome.dev/rollup-plugin)

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=Jonghakseo/chrome-extension-boilerplate-react-vite&type=Date)](https://star-history.com/#Jonghakseo/chrome-extension-boilerplate-react-vite&Date)

## Contributors



JunyWuuuu91
JunyWuuuu91

πŸ’»
dim0147
dim0147

πŸ›
jon lepage
jon lepage

πŸ›
LironH
LironH

πŸ€”
Spencer Chang
Spencer Chang

πŸ›
deld123
deld123

πŸ›
Michal Hantl
Michal Hantl

πŸ€” πŸ›


Jordan Burgess
Jordan Burgess

πŸ€”
NAMEUN CHO
NAMEUN CHO

πŸ›
Andrew Mudrov
Andrew Mudrov

πŸ’¬
Shubham Lad
Shubham Lad

πŸ›
hanrong
hanrong

πŸ›
Florian KΓΆnig
Florian KΓΆnig

πŸ’¬
Tran Phong
Tran Phong

πŸ›


tonychandesign
tonychandesign

πŸ›
Ihor Makarchuk
Ihor Makarchuk

πŸ›
hugoobauer
hugoobauer

πŸ›
Karan Singh
Karan Singh

πŸ€”
remusris
remusris

πŸ€”
hegel_dark
hegel_dark

πŸ€”
Jingsi
Jingsi

πŸ› πŸ’»


Chris Ozgo
Chris Ozgo

πŸ›
Cong
Cong

πŸ›
PatrykKuniczak
PatrykKuniczak

πŸ€” πŸ’» πŸ“–
Hector Parra
Hector Parra

πŸ›
JeongHyeon Kim
JeongHyeon Kim

πŸš‡
Terminels
Terminels

πŸ’»
WonkyDD
WonkyDD

πŸ’» πŸ›


wangxy
wangxy

πŸ›
Rasul
Rasul

πŸ“–
gavinhow
gavinhow

πŸ›
Anand D.
Anand D.

πŸ“–
Romain Dequidt
Romain Dequidt

πŸ“–
Jakob Guddas
Jakob Guddas

πŸ“– πŸ›
Dino Scheidt
Dino Scheidt

πŸ’»


秋ηŸ₯
秋ηŸ₯

πŸ’»
Hiverse
Hiverse

πŸ›
rosendolu
rosendolu

πŸ’»
Egor Stronhin
Egor Stronhin

πŸ“–
webLiang
webLiang

πŸ’»
Adam Spiers
Adam Spiers

πŸ›
Ofir Zeitoun
Ofir Zeitoun

πŸ’»


Dmitri Yourchev
Dmitri Yourchev

πŸ’» πŸ›
Gaishi Hirota
Gaishi Hirota

πŸ’»
pipizhu
pipizhu

πŸ’»

---

## Thanks To

| [Jetbrains](https://jb.gg/OpenSourceSupport) | [Jackson Hong](https://www.linkedin.com/in/j-acks0n/) |
|--------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| JetBrains Logo (Main) logo. | Jackson Hong |

---

[Jonghakseo](https://nookpi.tistory.com/)