## File: README.md

CRXJS

[📚 Documentation](https://crxjs.dev) | [💬 Discord ](https://discord.com/invite/FnnE4XR7Wj)

## 📦 Create CRXJS Project ```shell npm create crxjs@latest ``` > [!IMPORTANT] > `@latest` MUST NOT be omitted, otherwise `npm` may resolve to a cached and outdated version of the package. ## ✨ Features - 🧩 **Full Vite Plugin Ecosystem** - Leverage any Vite-compatible plugins with zero extra setup - ⚙️ **Zero Configuration** - Start developing immediately with intelligent defaults - 3️⃣ **Manifest V3 Support** - Built for modern Chrome extensions with enhanced security - 🔥 **True Hot Module Replacement** - Instant UI updates while preserving extension state 🎈**works with content scripts** - 📁 **Static Asset Import** - Directly reference images/fonts in your code - 🤖 **Auto Web-Accessible Resources** - Automatic generation of `web_accessible_resources` manifest entries > [!NOTE] > Looking for MV2 support? See [`rollup-plugin`](packages/rollup-plugin/README.md) ## 💻 Development - Clone this repository - Install [pnpm](https://pnpm.io) - Install dependencies using `pnpm install` - Build the `vite-plugin` project using `pnpm build:vite-plugin` - Playgrounds project is located at `playgrounds/**`, using `pnpm play` can run the playgrounds - Cd into the `vite-plugin` directory using `cd packages/vite-plugin` - Test using `pnpm run test` - Use [DeepWiki](https://deepwiki.com/crxjs/chrome-extension-tools) to learn more about CRXJS ## 💝 Contributors This project exists thanks to all the people who contribute. And thank you to all our backers! 🙏 ## 🤝 Supporting If these plugins have helped you ship your product faster, please consider [sponsoring me](https://github.com/sponsors/jacksteamdev) on GitHub. --- ## File: .changeset/README.md # Changesets Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) --- ## File: design/README.md # Design Resources You can find design files for CRXJS in this folder. ## Logo Design Logo was made by [Free Logo Maker: Design Custom Logos | Adobe Express](https://www.adobe.com/express/create/logo) Fonts used: Lato-BlackItalic Colors used: 298CD6,F2BAE4 Icon url: https://thenounproject.com/term/puzzle/8651 Icon by: [Daniel Heitz (@dnlhtz) / Twitter](https://twitter.com/dnlhtz) ## Pallets By blue: [ColorSpace - Color Palettes Generator and Color Gradient Tool](https://mycolor.space/?hex=%23298CD6&sub=1) By pink: [ColorSpace - Color Palettes Generator and Color Gradient Tool](https://mycolor.space/?hex=%23F2BAE4&sub=1) --- ## File: packages/vite-plugin-docs/docs/common/_get-url-for-images.mdx import { ImageCodeBlock } from './ImageCodeBlock'; ## Get the right URL :::info Content scripts share the origin of the page where they run. ::: The browser treats the imported value `logo` as a URL from the host page. If the content script is running on `https://google.com`, the `img` tag will try to load from `https://google.com/logo.svg`. Images first must be specified in the `web_accessible_resources` field in your `manifest.json` file: ```json title="manifest.json" "web_accessible_resources": [ { "resources": [ "icons/*.png"], "matches": [] } ] ``` Then you reference the image in your content script using the [chrome.runtime.getURL](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getURL) method: --- ## File: packages/vite-plugin-docs/docs/concepts/00-manifest.md --- position: 0 title: Manifest JSON id: manifest --- # Extension Manifest CRXJS parses the manifest to discover what entry files your extension uses. Because we import the manifest into the Vite config, you can use JSON, JavaScript, or TypeScript. ## TypeScript CRXJS exports a helper function called `defineManifest`. It's similar to Vite's `defineConfig` and supports autocompletion and dynamic or async definitions. :::tip Did you know? Chrome Extensions don't use Semver. Read more about the Chrome Extension version format in the [Google Developer Docs](https://developer.chrome.com/docs/extensions/mv3/manifest/version/). ::: The following example uses the version from `package.json` and dynamically sets the name depending on Vite's mode. ```typescript title=manifest.config.ts import { defineManifest } from '@crxjs/vite-plugin' import packageJson from './package.json' const { version } = packageJson // Convert from Semver (example: 0.1.0-beta6) const [major, minor, patch, label = '0'] = version // can only contain digits, dots, or dash .replace(/[^\d.-]+/g, '') // split into version parts .split(/[.-]/) export default defineManifest(async (env) => ({ manifest_version: 3, name: env.mode === 'staging' ? '[INTERNAL] CRXJS Power Tools' : 'CRXJS Power Tools', // up to four numbers separated by dots version: `${major}.${minor}.${patch}.${label}`, // semver is OK in "version_name" version_name: version, })) ``` ## Manifest Paths Paths inside the manifest are relative to the [Vite project root](https://vitejs.dev/guide/#index-html-and-project-root), so the location of the manifest file doesn't matter. :::tip Use paths that start with a letter ```json title=manifest.json { "options_page": "options.html", "devtools_page": "pages/devtools.html" } ``` ::: :::danger Don't use relative or absolute paths ```json title=manifest.json { "options_page": "./options.html", "devtools_page": "/root/user/.../devtools.html" } ``` ::: ## JSON Schema If you're using a JSON file, consider using a schema like the one at [JSON Schema Store](https://json.schemastore.org/chrome-manifest.json) to take advantage of autocompletion and validation. You can configure VSCode to use a JSON schema by adding this to your settings file: ```json title=settings.json { "json.schemas": [ { "fileMatch": ["manifest.json"], "url": "https://json.schemastore.org/chrome-manifest.json" } ] } ``` --- ## File: packages/vite-plugin-docs/docs/concepts/01-pages.md --- position: 1 title: HTML Pages --- # Extension Pages CRXJS provides extension HTML pages with Vite HMR during development and optimizations in a production build. The manifest can declare the most common pages, such as the action popup and the options page, but not every extension page has a place in the manifest. ## Extra HTML pages If you need to declare extra HTML pages beyond those the manifest accommodates, place them in the Vite config under `build.rollupOptions.input`. This example includes a welcome page to open when the user installs the extension. ```javascript title=vite.config.ts export default defineConfig({ build: { rollupOptions: { input: { welcome: 'pages/welcome.html', }, }, }, }) ``` Vite will serve these input pages during development and include an optimized version of them in the production build. --- ## File: packages/vite-plugin-docs/docs/concepts/02-background.md --- position: 2 title: Background --- # Extension Background Chrome Extensions use a **service worker** to listen for Chrome API Events in the background. Add a service worker to your extension in the manifest under `background.service_worker`. CRXJS uses module-type service workers because Vite uses the ES module format. ```json title=manifest.json { "background": { "service_worker": "src/background.ts", "type": "module" } } ``` CRXJS loads the service worker from the Vite Dev Server during development, and HMR causes a full extension reload when Vite detects a change to the background code. Learn more about extension service workers in the [Chrome Developer Docs](https://developer.chrome.com/docs/extensions/mv3/service_workers/). --- ## File: packages/vite-plugin-docs/docs/concepts/03-content-scripts.md --- position: 3 title: 'Content Scripts' --- # Content Scripts CRXJS provides content scripts with Vite HMR, so updates don't always require a full host page reload. In addition, frameworks like React and Vue work in content scripts the same as HTML pages. :::tip Host Pages The host page of a content script is the website where the content script is running. ::: ## Static Assets Feel free to import static assets! CRXJS automatically declares imported content script dependencies as `web_accessible_resources` in the manifest. ## Use the extension URL Content scripts share the origin of the host page, so convert imported static assets to the extension origin using the Chrome API. ```javascript import logo from './logo.png' const url = chrome.runtime.getURL(logo) ``` ## HTML in content scripts It is possible to inject an extension page into a host page using an iframe. The host page CSP does not affect the injected iframe even if the host page specifies the `frame-src` policy. An injected extension page loads inside a cross-origin iframe, so it does not have access to the host page DOM like a content script. ```javascript title=content-script.js const src = chrome.runtime.getURL('pages/iframe.html') const iframe = new DOMParser().parseFromString( ``, ).body.firstElementChild document.body.append(iframe) ``` Injected extension pages do have access to the full Chrome API, however. :::info Configuration required If you load an HTML file from a content script, you need to declare the file as a web-accessible resource. ```json { "web_accessible_resources": [ { "resources": ["pages/iframe.html"], "matches": ["https://*.google.com/*"] } ] } ``` You will also need to add the HTML file to your Vite config under `build.rollupOptions.input`. ```javascript title=vite.config.ts export default defineConfig({ build: { rollupOptions: { input: { welcome: 'pages/iframe.html', }, }, }, }) ``` ::: ### Imported HTML If you need to render complex HTML in a content script without a framework, an HTML file can serve as a static fragment by importing it as text using the `?raw` query. This technique does not require the file to be web-accessible, and you don't need to declare it in the Vite config. ```javascript import html from './root.html?raw' const iframe = new DOMParser().parseFromString(html).body.firstElementChild iframe.src = chrome.runtime.getURL('pages/iframe.html') document.body.append(iframe) ``` Importing an HTML file as text lets you take advantage of IDE language services for HTML files. Depending on your HTML, this technique may be more concise than using `document.createElement()`. --- ## File: packages/vite-plugin-docs/docs/getting-started/react/00-create-project.md --- id: create-project title: Create a project tags: - Getting started - React - Vite config pagination_prev: null slug: create-project --- import {CreateProjectTabs} from '../\_create-project-tabs.mdx' # Get Started with React This quick guide will get you up and running with a Chrome Extension popup page. You'll see how to integrate CRXJS with Vite, then explore Vite HMR in an extension React HTML page. The first two sections take about 90 seconds! :::tip package.json Check `package.json` to ensure that `"type": "module"` is set. If this package key is missing, Vite might not be able to build `vite.config.js`. ::: ## Install CRXJS ```sh npm install --save-dev @crxjs/vite-plugin ``` ## Create a web extension manifest Create a file named `manifest.json` next to `vite.config.js`. ```json title=manifest.json { "manifest_version": 3, "name": "CRXJS React Vite Example", "version": "1.0.0", "action": { "default_popup": "index.html" } } ``` ## Update the Vite config Update `vite.config.js` to match the code below. ```js title=vite.config.js import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' // highlight-start import { crx } from '@crxjs/vite-plugin' import manifest from './manifest.json' // highlight-end export default defineConfig({ plugins: [ react(), // highlight-next-line crx({ manifest }), ], }) ``` ## First development build Time to run the dev command. 🤞 ```sh npm run dev ``` That's it! CRXJS will do the rest. Your project directory should look like this: Next, we'll load the extension in the browser and give the development build a test run. --- ## File: packages/vite-plugin-docs/docs/getting-started/react/01-dev-basics.md --- id: dev-basics title: Development basics tags: - HTML page - Popup page - React - Vite config slug: dev-basics --- import Intro from '../\_dev-basics-intro.md'; import Installing from '../\_install-extension.md'; # Development Basics with React ## Install the extension ## Opening the extension ## Profit with Vite HMR Once you've found the extension icon, right-click it and choose "Inspect popup window". This will open the popup and the popup dev tools window. We need to inspect the popup to keep it open while making changes. And boom! HMR magic at work.