--- url: /guide/introduction.md --- # Introduction **Addfox** is a browser extension development framework built on [Rsbuild](https://rsbuild.dev), helping you develop and build Chrome and Firefox extensions in a single project. ![Addfox Architecture](/addfox-architecture.png) ## Why Addfox Developing browser extensions should be simple—just HTML, JavaScript, and CSS. But in reality, issues like hot reload, error debugging, and frontend framework integration have plagued developers. Addfox's goal is to make extension development simple again: In the AI era, Addfox goes further to help AI better understand and assist with your extension development: - **AI-friendly project structure** — Automatically generates structured documents like `llms.txt` and `meta.md`, enabling AI assistants to quickly understand project architecture and configuration - **Terminal error output** — Errors are output directly to the terminal during development, no need to open browser DevTools, making it easy to use Ask AI features in any editor - **Skills support** — Built-in reusable AI skill library (e.g., migrate-to-addfox, addfox-debugging) enables AI assistants to assist development and debugging more professionally - **Minimal code constraints** — No enforced code organization patterns, allowing AI-generated code to integrate seamlessly into your project Whether you're a developer or using AI-assisted development, Addfox provides a better experience. ## Features ### For Developers Hot reload, multi-browser support, and minimal config so you can ship extensions faster. | Feature | Description | | ------------------------ | ----------------------------------------------------------------------------------------------- | | **Fast HMR** | Dedicated plugin for extension reload; content\_script and background both hot-update | | **Full browser support** | Support for mainstream Chromium-based browsers and Firefox; auto-detect install path and launch | | **Framework agnostic** | Vanilla, Vue, React, Preact, Svelte, Solid—use what you like | | **Content UI** | Built-in createContentUI for Iframe, ShadowDom, or inline content | | **Rstack ecosystem** | Built-in support for Rsdoctor and Rstest for bundle analysis and testing | | **Zip on build** | Running build automatically produces a zip of the extension | ### For AI Structured meta, terminal errors, and skills—so agents can understand and extend your extension. | Feature | Description | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **llms.txt and markdown metadata** | Provides clear plugin information, error details, and prompts to help AI agents develop | | **AI-friendly error monitor** | With `--debug`, terminal error output; capture all errors without opening DevTools, ready for Ask AI in any editor | | **Skills support** | Extensible skills for agents and automation | ## Core Concepts Addfox encapsulates common pain points in extension development: - **Entry auto-discovery** — Place files by convention, no need to manually configure entry - **Smart manifest handling** — Auto-inject built paths - **Dev auto-reload** — WebSocket listens for build completion, auto-refreshes extension ## Compared to Other Solutions The extension development ecosystem has been greatly enriched by excellent frameworks. **WXT** brings the power of Vite with a well-designed plugin system and intuitive conventions. **Plasmo** offers comprehensive cloud integration and a polished, batteries-included developer experience. **Extension.js** provides remarkable simplicity for quick prototypes. Each has made significant contributions to making extension development more accessible. Addfox stands on the shoulders of these giants while carving its own path: | Solution | Build Tool | Version | Dev Experience | Flexibility | | ------------------------- | ----------------- | ----------------- | ------------------- | -------------------------------------- | | Hand-written Webpack/Vite | Self-configured | - | Manual HMR handling | Fully controllable | | Plasmo | Parcel | latest | Out-of-the-box | Convention-based with cloud features | | WXT | Vite | ^0.20.18 | Out-of-the-box | Convention-based with plugin ecosystem | | Extension.js | Rspack | latest | Out-of-the-box | Zero-config, minimal setup | | **Addfox** | **Rsbuild 1.7.5** | **0.1.1-beta.12** | **Out-of-the-box** | **Minimal conventions + AI-native** | **Addfox's unique advantages:** - **Rsbuild-powered speed** — Faster cold starts and HMR compared to Vite/Parcel-based solutions - **AI-first design** — Built-in `llms.txt`, structured error output, and Skills support for AI-assisted development - **Maximum freedom** — No enforced file structures or custom APIs; use your preferred patterns - **Framework-agnostic core** — Works with any UI framework without wrapper components or special adapters ## Quick Start ```bash # Create project with scaffold npx addfox@latest create # or: pnpm dlx addfox@latest create # Enter project directory cd my-extension # Start dev server pnpm dev ``` Edit `app/popup/index.tsx`, and the extension will auto-reload on save. ## Next Steps - [Installation](/guide/install.md) — Detailed project creation steps - [App Directory](/guide/app-dir.md) — Learn about project organization - [Config Reference](/config/manifest.md) — View all configuration options --- url: /CHANGELOG.md --- # addfox-docs ## 0.1.8 ### Patch Changes - fix(entry,launcher): restore page-entry chunk splitting and unblock dev launch ## 0.1.7 ### Patch Changes - feat: MV2 support, config-level test field, and leaner dev output ## 0.1.6 ### Patch Changes - chore: update cache and config ## 0.1.5 ### Patch Changes - feat: HTML entry discovery, HTML page HMR reload, and dev experience improvements - Add HTML entry parsing and discovery in `@addfox/core` (support `data-addfox-entry` script tags and HTML-first entries) - Reload extension HTML pages on template changes during dev (`@addfox/rsbuild-plugin-extension-entry`) - Improve HMR scope handling, browser cleanup on dev shutdown, and Chromium launcher reliability - Add `--port` CLI flag for Rsbuild dev server; log extension size after first dev compile - Gracefully shut down dev server, browser, and HMR sockets on SIGINT/SIGTERM - Upgrade Rsbuild/Rspack catalog to 2.1.1 and refresh create-addfox-app templates ## 0.1.5 ### Patch Changes - feat: HTML entry discovery, HTML page HMR reload, and dev experience improvements - Add HTML entry parsing and discovery in `@addfox/core` (support `data-addfox-entry` script tags and HTML-first entries) - Reload extension HTML pages on template changes during dev (`@addfox/rsbuild-plugin-extension-entry`) - Improve HMR scope handling, browser cleanup on dev shutdown, and Chromium launcher reliability - Add `--port` CLI flag for Rsbuild dev server; log extension size after first dev compile - Gracefully shut down dev server, browser, and HMR sockets on SIGINT/SIGTERM - Upgrade Rsbuild/Rspack catalog to 2.1.1 and refresh create-addfox-app templates ## 0.1.4 ### Patch Changes - fix: recover sourcemap of content/background ## 0.1.3 ### Patch Changes - chore: resolve latest addfox versions from npm registry to avoid pnpm lowest-direct resolution ## 0.1.2 ### Patch Changes - feat: add create arg ## 0.1.1 ### Patch Changes - fix: watchOptions.ignored .addfox dir ## 0.1.0 ### Minor Changes - refactor: update browser launcher ## 0.0.3-beta.17 ### Patch Changes - chore: update lib ## 0.0.3-beta.16 ### Patch Changes - chore: update libs version ## 0.0.3-beta.15 ### Patch Changes - fix: export the monitor file - fix: fixed package.json files ## 0.0.3-beta.14 ### Patch Changes - chore: update manifest function ## 0.0.3-beta.13 ### Patch Changes - chore: update docs and plugins ## 0.0.3-beta.12 ### Patch Changes - feat: add agents.md for templates ## 0.0.3-beta.11 ### Patch Changes - docs: add es/ja/ko/ru i18n ## 0.0.3-beta.10 ### Patch Changes - chore: update locak file ## 0.0.3-beta.9 ### Patch Changes - chore:update docs ## 0.0.3-beta.8 ### Patch Changes - fix: fixed create-addfox-app template errors ## 0.0.3-beta.7 ### Patch Changes - update templates addfox version ## 0.0.3-beta.6 ### Patch Changes - update templates addfox version ## 0.0.3-beta.5 ### Patch Changes - chore: update templates ## 0.0.3-beta.4 ### Patch Changes - 21ee3c2: fixed hmr errors ## 0.0.3-beta.3 ### Patch Changes - update packages info ## 0.0.3-beta.2 ### Patch Changes - update core packages ## 0.0.3-beta.1 ### Patch Changes - Initial release of core and CLI packages ## 0.0.3-beta.0 ### Patch Changes - Initial release of core and CLI packages ## 0.0.2 ### Patch Changes - fix some errors --- url: /blog/index.md --- # Addfox Blog [May 25, 2026 ### Addfox 0.2.0: Architecture Refactoring & Dependency Slimming A deep dive into the latest architecture refactoring, including the new @addfox/launcher, dependency reductions, supply chain risk mitigation, and performance improvements. ![Gomi](https://github.com/gxy5202.png) Gomi](/blog/v0-2-0) --- url: /blog/v0-2-0.md --- # Addfox 0.2.0: Architecture Refactoring & Dependency Slimming _May 25, 2026_ [![Gomi](https://github.com/gxy5202.png)Gomi](https://github.com/gxy5202) We are excited to share the latest progress on the Addfox framework. Version `0.2.0` is now officially released, featuring a significant architecture refactoring. This update focuses on three core goals: **reducing dependencies**, **replacing black-box tools with built-in alternatives**, and **improving the developer experience** for browser extension development. ## Dependency Slimming & Supply Chain Security One of the most impactful changes in this refactoring is the aggressive removal of third-party dependencies that carried large transitive trees. Every external dependency is a potential supply-chain risk—whether through deprecation, malicious takeover, or breaking changes in transitive packages. By replacing large third-party tools with focused, built-in utilities, we have drastically shrunk the attack surface for Addfox users. Here is what we removed: - **`web-ext`** (\~586 KB + **26 transitive deps**) — completely removed. - **`chrome-launcher`** — removed. - **`archiver`** (\~40 KB + **9 transitive deps**) — replaced with a built-in zip alternative. - **`cli-table3`** (\~46 KB + 1 transitive dep) — removed from `@addfox/core`. - **`chalk`** (\~44 KB), **`kolorist`**, **`minimist`** — removed from `create-addfox-app` and replaced with lightweight built-in utilities. The result? The `pnpm-lock.yaml` shrank by approximately **2,156 lines**, meaning faster installs, smaller `node_modules`, and fewer supply-chain risks for end users. ### Before vs. After: Third-Party Runtime Dependencies | Package | 0.1.1 Third-Party Deps | Dev-Launch Third-Party Deps | | -------------------------------------- | ------------------------------------------ | -------------------------------- | | `@addfox/cli` | `archiver` | _(none)_ | | `@addfox/core` | `cli-table3`, `jiti` | `jiti` | | `create-addfox-app` | `chalk`, `kolorist`, `minimist`, `prompts` | `prompts` | | `@addfox/rsbuild-plugin-extension-hmr` | `chrome-launcher`, `web-ext` | _(none)_ | | `@addfox/launcher` | _N/A (new package)_ | _(none)_ | | `@addfox/common` | _(none)_ | _(none)_ | | `@addfox/pkg-manager` | _(none)_ | _(none)_ | | `@addfox/utils` | `@addfox/common` | `@addfox/common` | | `rsbuild-plugin-extension-entry` | `@addfox/core` | `@addfox/core` | | `rsbuild-plugin-extension-manifest` | `@addfox/core` | `@addfox/core` | | `rsbuild-plugin-extension-monitor` | `@addfox/common`, `@addfox/core` | `@addfox/common`, `@addfox/core` | **What remains?** Only two mature, tiny third-party runtime dependencies: - **`jiti`** — a lightweight TypeScript config loader (\~50 KB, zero transitive deps). - **`prompts`** — a minimal CLI prompt library (\~30 KB, zero transitive deps). Everything else is either internal (`@addfox/*`) or handled by the build toolchain (`@rspack/core` as a dev dependency). ## Introducing `@addfox/launcher` Previously, Firefox development relied on `web-ext run`, a powerful tool with heavy dependencies. We have built **`@addfox/launcher`** from the ground up: - **Zero runtime dependencies**. - Unified support for **Chromium** (Chrome, Edge, etc.) and **Gecko** (Firefox, Zen, etc.). - Firefox HMR now uses the **RDP protocol** to reload temporary add-ons directly, eliminating the need for `web-ext`'s complex process management. - Removed compatibility files such as `web-ext.d.ts`, `web-ext-logger.d.ts`, and `web-ext-console-stream-hook.ts`. This makes the dev server faster to start, easier to debug, and fully under our control. ## HMR Plugin Refactoring The `@addfox/rsbuild-plugin-extension-hmr` package saw the largest code reduction: - `launcher.ts` and `runner.ts` were heavily simplified after dropping `web-ext`. - The extension manager now handles profile directories and reload logic more cleanly. - Keyboard reload and WebSocket server paths were streamlined. Overall, the workspace diff shows roughly **50 files changed**, with a **net reduction of \~1,641 lines** of code—less code to maintain, fewer edge cases, and better reliability. ## Enhanced Test Coverage We did not just delete code; we also invested in quality: - `rsbuild-plugin-extension-entry`: +260 lines of tests - `rsbuild-plugin-extension-hmr`: +114 lines of tests - `rsbuild-plugin-extension-manifest`: +101 lines of tests - `rsbuild-plugin-extension-monitor`: +112 lines of tests ## Official Release The architecture refactoring and dependency slimming described above are now officially released as version `0.2.0`. Upgrade today and thank you for using Addfox! --- url: /config/app-dir.md --- # appDir `appDir` is the **app directory**, defaulting to `app/`. It is used as **baseDir for [entry](/config/entry.md)** and as the **root for manifest auto-load**. ## Type and default - **Type**: `string | undefined` - **Default**: `"app"` (framework convention) - **Resolved**: Framework resolves to an absolute path, e.g. `appDir: "src"` → `path.resolve(root, "src")`. ## Role 1. **baseDir for entry**\ All [entry](/config/entry.md) paths are **relative to appDir**. E.g. `appDir: "src"` and `entry: { popup: "popup/index.ts" }` → `src/popup/index.ts`. 2. **Entry discovery**\ When [entry](/config/entry.md) is not set, the framework discovers `background`, `content`, `popup`, `options`, `sidepanel`, `devtools` under appDir by directory name. 3. **Manifest auto-load**\ When [manifest](/config/manifest.md) is not set in config, the framework looks for: - `appDir/manifest.json`, `appDir/manifest.chromium.json`, `appDir/manifest.firefox.json` - `appDir/manifest/manifest.json`, etc. ## Examples ### App in `src/` ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ appDir: "src", entry: { background: "background/index.ts", content: "content/index.ts", popup: "popup/index.ts", options: "options/index.ts", }, }); ``` ### `app/` as source (default) ```ts export default defineConfig({ // appDir omitted → "app" entry: { background: "background/index.ts", popup: "popup/index.ts" }, }); ``` ## Related - [entry](/config/entry.md), [manifest](/config/manifest.md): Paths and auto-load are relative to appDir. --- url: /config/cache.md --- # keepBrowserProfile `keepBrowserProfile` controls whether **Chromium-based browsers reuse a dev user data directory** between `addfox dev` runs. It affects only dev mode and only Chromium-family browsers. ## Type and default - **Type**: `boolean | undefined` - **Default**: `false` - **CLI precedence**: - `--keep-browser-profile` forces profile keeping on for current run - `--no-keep-browser-profile` forces profile keeping off for current run - If both are provided, the **last flag wins** ## Role - When `true` (or CLI `--keep-browser-profile` is used): - Dev mode **keeps** a Chromium user data dir under `.addfox/cache/browser-profile/-user-data`, so: - extension install state - extension settings - login sessions and cookies are kept between `addfox dev` runs. - When `false`: - Each `addfox dev` run uses a fresh profile for Chromium-based browsers. - Does not affect Firefox; Firefox profile handling is delegated to `web-ext`. ## Priority `keepBrowserProfile` is resolved in this order (highest first): 1. CLI `--keep-browser-profile` / `--no-keep-browser-profile` 2. `browser..keepBrowserProfile` (per-browser override) 3. Top-level `keepBrowserProfile` 4. Deprecated `cache` (CLI `-c/--cache`, `--no-cache` or config `cache`) 5. Default `false` ## Examples ### Enable via config ```ts export default defineConfig({ keepBrowserProfile: true, }); ``` ### Per-browser override ```ts export default defineConfig({ browser: { chrome: { keepBrowserProfile: true }, }, }); ``` ### One-off via CLI **[object Object]** ```bash pnpm dev -- --keep-browser-profile ``` **[object Object]** ```bash npm run dev -- --keep-browser-profile ``` **[object Object]** ```bash yarn dev --keep-browser-profile ``` **[object Object]** ```bash bun run dev -- --keep-browser-profile ``` ### One-off disable via CLI **[object Object]** ```bash pnpm dev -- --no-keep-browser-profile ``` **[object Object]** ```bash npm run dev -- --no-keep-browser-profile ``` **[object Object]** ```bash yarn dev --no-keep-browser-profile ``` **[object Object]** ```bash bun run dev -- --no-keep-browser-profile ``` CLI flags override `keepBrowserProfile` in config for that run. :::warning The `cache` config field and the `-c/--cache`, `--no-cache` CLI flags are deprecated aliases; they still work but print a deprecation warning in the terminal. Migrate to `keepBrowserProfile` and `--keep-browser-profile` / `--no-keep-browser-profile`. ::: # buildCache `buildCache` controls the **Rspack persistent build cache**, which speeds up repeated builds. ## Type and default - **Type**: `boolean | { cacheDirectory?: string }` - **Default**: `true` - Cache files are stored in `/cache/build/` ## Examples ```ts export default defineConfig({ // Disable the build cache buildCache: false, }); ``` ```ts export default defineConfig({ // Custom cache directory buildCache: { cacheDirectory: "./node_modules/.cache/addfox-build" }, }); ``` For deeper rsbuild/rspack customization, use the existing [`rsbuild`](/config/rsbuild.md) config field (object deep-merge or function form). ## Related - Dev plugin [@addfox/rsbuild-plugin-extension-hmr](https://github.com/addfox/addfox/tree/main/packages/plugins/rsbuild-plugin-extension-hmr) which uses the cached profile. --- url: /config/debug.md --- # debug `debug` enables the **extension error monitor** in dev mode by adding the `@addfox/rsbuild-plugin-extension-monitor` plugin. It surfaces runtime errors from the extension into a dedicated panel and terminal-friendly output, designed to work well with AI assistants. ## Type and default - **Type**: `boolean | undefined` - **Default**: `false` - **CLI equivalence**: CLI flag `--debug` is equivalent to `debug: true` in config for that run and has higher priority. ## Role - When `debug` is `true` (or `--debug` is passed) **and the command is `addfox dev`**: - The monitor plugin is injected into the Rsbuild pipeline. - Dev builds stream extension errors into: - a browser UI panel (overlay or dedicated page, depending on setup), - and terminal error blocks formatted for "Ask AI" workflows. - When `debug` is `false` or omitted: - The monitor plugin is not added; dev behaves normally, without the extra error panel. - Has **no effect** on `addfox build`; the monitor is dev-only. ## Examples ### Always enable monitor in dev via config ```ts export default defineConfig({ debug: true, }); ``` ### Enable monitor only when needed via CLI **[object Object]** ```bash pnpm dev -- --debug ``` **[object Object]** ```bash npm run dev -- --debug ``` **[object Object]** ```bash yarn dev --debug ``` **[object Object]** ```bash bun run dev -- --debug ``` This does not require `debug` in config and is useful for temporary debugging sessions. ## Related - CLI parser maps `--debug` to the same behaviour as `debug: true` in `addfox.config`. - Dev plugin [@addfox/rsbuild-plugin-extension-monitor](https://github.com/addfox/addfox/tree/main/packages/plugins/rsbuild-plugin-extension-monitor). --- url: /config/entry.md --- # entry `entry` defines the **entry map**: keys are entry names, values are **JS/TS script paths** or **structured objects** relative to baseDir. When omitted, the framework discovers `background`, `content`, `popup`, `options`, `sidepanel`, `devtools` under [appDir](/config/app-dir.md) (default `app/`) by directory name. ## Type and baseDir - **Type**: `Record | undefined` - **baseDir**: When [appDir](/config/app-dir.md) is not set, baseDir = `app/`; when set, baseDir = `appDir`. All entry values are **relative to baseDir**. ## Reserved entry names These names are fixed by the extension spec and framework: | Name | Type | Description | | ------------ | ------------- | ---------------------------------- | | `background` | Script only | Service worker / background script | | `content` | Script only | Content script | | `popup` | Script + HTML | Popup page | | `options` | Script + HTML | Options page | | `sidepanel` | Script + HTML | Side panel | | `devtools` | Script + HTML | DevTools page | Other names can be **custom entries** (e.g. `capture`, `offscreen`) as long as the directory has the corresponding script. ## Path rules - **JS/TS entry only**: the real entry is always JS/TS (`.js`, `.jsx`, `.ts`, `.tsx`). HTML is **template only**. - **HTML template rules**: if you use an HTML template, **do not import CSS or other resources** in the HTML. The HTML is not compiled; only the JS/TS entry is compiled. - **Single main entry**: HTML templates must include **one** `` - `background` and `content` are script-only entries (no HTML generated). - For `popup`, `options`, `sidepanel`, `devtools`, HTML is generated by default. If a template exists, it is used as the template. ## When entry is omitted The framework scans baseDir and discovers the reserved names by looking for scripts (e.g. `background/index.ts`, `popup/index.ts`, `popup.ts`). If only an HTML template exists, the framework reads **`data-addfox-entry`** to locate the JS/TS entry and auto-generates `{ src, html }`. ## Supported layouts - Flat files under baseDir: `popup.ts`, `content.ts`, `background.js`, etc. - Single-level dirs: `popup/index.ts`, `content/index.ts`, `background/index.ts`. Nested multi-level entry folders are not supported. ## Examples ### Default discovery (no entry config) ```tree app/ background/index.ts content/index.ts popup/index.ts popup/index.html # optional HTML template options/index.ts options/index.html # optional HTML template ``` No `entry` needed in config. The framework discovers script entries; if an `index.html` exists alongside the script, it is used as the HTML template. ### HTML template only (data-addfox-entry) ```tree app/ popup/ index.html # template only main.ts # real entry ``` ```html ``` No `entry` needed. The framework reads `data-addfox-entry` and auto-declares `{ src, html }`. ### Custom entries and overrides ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ appDir: "src", entry: { background: "background/index.ts", content: "content/index.ts", popup: "popup/index.ts", options: "options/index.ts", sidepanel: "sidepanel/index.ts", capture: "capture/index.ts", offscreen: { src: "offscreen/index.ts", html: true }, settings: { src: "settings/index.ts", html: "settings/index.html" }, }, }); ``` When `entry` is set, **only** the declared entries are used. You can mix reserved and custom names. ## Related - [appDir](/config/app-dir.md): baseDir for entry paths. - [manifest](/config/manifest.md): Framework fills manifest paths from entry and [outDir](/config/out-dir.md). --- url: /config/env-prefix.md --- # Environment Variables Addfox uses Rsbuild's `loadEnv` to load `.env` files from the project root, and by default only exposes variables starting with `ADDFOX_PUBLIC_` to client code. ## Default Behavior - **Default Prefix**: `ADDFOX_PUBLIC_` - **Client Code**: background, content, popup, options, sidepanel, devtools entries - **Loaded Files**: `.env`, `.env.local`, `.env.{mode}`, `.env.{mode}.local` ## Scope Environment variables are injected into all **client code** entries, but **not** in the `manifest` configuration in `addfox.config.ts` (which uses build-time environment). ## Built-in Variables Addfox automatically injects these variables: | Variable | Description | | ---------------------------- | ---------------------------- | | `process.env.BROWSER` | Current build target browser | | `process.env.NODE_ENV` | Current environment mode | | `process.env.ADDFOX_VERSION` | Addfox version | ## Usage Example ### .env File ```bash ADDFOX_PUBLIC_API_URL=https://api.example.com ADDFOX_PUBLIC_APP_NAME=My Extension ADDFOX_PRIVATE_KEY=secret # Won't be exposed to client ``` ### Using in Code ```ts // app/popup/index.tsx const apiUrl = process.env.ADDFOX_PUBLIC_API_URL; ``` ## Security Recommendations - Always use `ADDFOX_PUBLIC_` prefix to mark variables safe for client exposure - Sensitive info (like API keys) should not start with `ADDFOX_PUBLIC_` - `.env.local` and `.env.{mode}.local` files should not be committed to Git ## Related Documentation - [guide/env-prefix](/guide/env-prefix.md) - Environment variables usage guide --- url: /config/hot-reload.md --- # hotReload `hotReload` configures **dev‑mode HMR** behaviour for the extension: the WebSocket port used by the reload manager and whether content pages are auto‑refreshed when content scripts change. ## Type and defaults - **Type**: ```ts hotReload?: { wsPort?: number; autoRefreshContentPage?: boolean; }; ``` - **Defaults**: - `wsPort`: `23333` (matches core `HMR_WS_PORT`) - `autoRefreshContentPage`: `true` ## Role - Only used in **dev** (`addfox dev`): - `wsPort` becomes the WebSocket server port used by the HMR plugin - `autoRefreshContentPage` controls whether the reload manager automatically refreshes the active tab when a **content entry** changes - Has no effect on `addfox build`. ## Examples ### Custom HMR port ```ts export default defineConfig({ hotReload: { wsPort: 30001, }, }); ``` ### Disable auto refresh for content pages ```ts export default defineConfig({ hotReload: { autoRefreshContentPage: false, }, }); ``` ### Custom port + no auto refresh ```ts export default defineConfig({ hotReload: { wsPort: 31000, autoRefreshContentPage: false, }, }); ``` ## Related - [`launch`](/config/launch.md): which browser dev mode opens (or use CLI `-b/--browser`). - Dev plugin [@addfox/rsbuild-plugin-extension-hmr](https://github.com/addfox/addfox/tree/main/packages/plugins/rsbuild-plugin-extension-hmr). --- url: /config/index.md --- # Config This page summarizes Addfox configuration options. Common entries: - [manifest](/config/manifest.md) - [entry](/config/entry.md) - [appDir](/config/app-dir.md) - [envPrefix](/config/env-prefix.md) - [hotReload](/config/hot-reload.md) --- url: /config/launch.md --- # browser `browser` configures the browsers used during `addfox dev` to open and load the extension: executable path, user-data (profile) directory, and whether to keep the profile between launches. ## Overview - **Type**: `Record` - **Default**: `undefined` (uses system default paths) - **Required**: No Each browser entry supports: - `path` — browser executable path - `profile` — custom user-data (profile) directory; relative paths resolve from the project root (default: `/cache/browser-profile/-user-data`) - `keepBrowserProfile` — keep this browser's profile between launches, overriding the top-level [`keepBrowserProfile`](/config/cache.md) ## Chromium-based Browsers The following Chromium-based browsers are supported: | Browser | Config Key | Default Path | | -------------- | ---------- | ------------- | | Google Chrome | `chrome` | Auto-detected | | Chromium | `chromium` | Auto-detected | | Microsoft Edge | `edge` | Auto-detected | | Brave | `brave` | Auto-detected | | Vivaldi | `vivaldi` | Auto-detected | | Opera | `opera` | Auto-detected | | Arc | `arc` | Auto-detected | ### Configuration Example ```ts // addfox.config.ts export default defineConfig({ browser: { chrome: { path: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" }, edge: { path: "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" }, }, }); ``` ### Launch via CLI **[object Object]** ```bash pnpm dev -- -b chrome pnpm dev -- -b edge pnpm dev -- -b brave ``` **[object Object]** ```bash npm run dev -- -b chrome npm run dev -- -b edge npm run dev -- -b brave ``` **[object Object]** ```bash yarn dev -b chrome yarn dev -b edge yarn dev -b brave ``` **[object Object]** ```bash bun run dev -- -b chrome bun run dev -- -b edge bun run dev -- -b brave ``` ## Firefox Firefox uses the `web-ext` tool to manage extensions. The path configuration is the same: ```ts export default defineConfig({ browser: { firefox: { path: "/Applications/Firefox.app/Contents/MacOS/firefox" }, }, }); ``` ### Launch Firefox **[object Object]** ```bash pnpm dev -- -b firefox ``` **[object Object]** ```bash npm run dev -- -b firefox ``` **[object Object]** ```bash yarn dev -b firefox ``` **[object Object]** ```bash bun run dev -- -b firefox ``` :::info Firefox development mode uses the `web-ext` tool. Extension reload is handled by `web-ext`, not Addfox's WebSocket. ::: ## Platform Examples ### macOS ```ts export default defineConfig({ browser: { chrome: { path: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" }, edge: { path: "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" }, firefox: { path: "/Applications/Firefox.app/Contents/MacOS/firefox" }, }, }); ``` ### Windows ```ts export default defineConfig({ browser: { chrome: { path: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" }, edge: { path: "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" }, }, }); ``` ### Linux ```ts export default defineConfig({ browser: { chrome: { path: "/usr/bin/google-chrome" }, chromium: { path: "/usr/bin/chromium-browser" }, firefox: { path: "/usr/bin/firefox" }, }, }); ``` ## Deprecated: `browserPath` `browserPath` still works but prints a deprecation warning in the terminal. Migrate to `browser`: ```ts // Before (deprecated) export default defineConfig({ browserPath: { chrome: "/path/to/chrome" }, }); // After export default defineConfig({ browser: { chrome: { path: "/path/to/chrome" } }, }); ``` If both `browserPath` and `browser` set a path for the same browser, `browser` takes precedence. ## Related Configuration - [guide/launch](/guide/launch.md) - Browser launch guide - [`keepBrowserProfile` / `buildCache`](/config/cache.md) - Cache configuration --- url: /config/manifest.md --- # manifest `manifest` declares the extension manifest (the content of the final `manifest.json` in the build output). It supports three styles: **inline object**, **object split by browser** (chromium/firefox), or **file paths**; it can also be **omitted** so the framework auto-loads manifest files from the source directory. ## Type and default behavior - **Type**: `ManifestConfig | ManifestPathConfig | undefined` - **Default**: When omitted, the framework loads from `appDir` or `appDir/manifest/`: - `manifest.json` (shared or single browser) - `manifest.chromium.json` (Chrome overrides) - `manifest.firefox.json` (Firefox overrides) - At build time, the branch is chosen by CLI `-b chrome|edge|brave|vivaldi|opera|santa|firefox` and merged with base, then written to `outputRoot/outDir/manifest.json`. ## Configuration styles ### 1. Single object (Chrome / Firefox shared) All fields in one object. The framework injects entry paths for `background`, `content_scripts`, `action`, `options_ui`, `side_panel`, `devtools_page` according to the current target; other fields are output as-is. ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ manifest: { name: "My Extension", version: "1.0.0", manifest_version: 3, permissions: ["storage", "activeTab"], action: { default_popup: "popup/index.html" }, background: { service_worker: "background/index.js" }, content_scripts: [ { matches: [""], js: ["content/index.js"], run_at: "document_start" }, ], }, }); ``` Entry paths (e.g. `popup/index.html`, `background/index.js`) are computed by the framework from [entry](/config/entry.md) and [outDir](/config/out-dir.md). You only need to keep these keys in manifest; see [MANIFEST\_ENTRY\_PATHS](https://github.com/addfox/addfox/blob/main/packages/core/src/constants.ts) for custom keys. ### 2. Split by browser (chromium / firefox) When Chrome and Firefox need different manifest fields (e.g. Chrome `action` vs Firefox `sidebar_action`, or `service_worker` vs `scripts`), use `chromium` and `firefox` branches. The framework picks the branch by current `-b` and deep-merges with base. ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ manifest: { chromium: { name: "My Ext", manifest_version: 3, action: { default_popup: "popup/index.html" }, background: { service_worker: "background/index.js" }, content_scripts: [{ matches: [""], js: ["content/index.js"] }], }, firefox: { name: "My Ext", manifest_version: 2, sidebar_action: { default_panel: "sidepanel/index.html" }, background: { scripts: ["background/index.js"] }, content_scripts: [{ matches: [""], js: ["content/index.js"] }], }, }, }); ``` ### 3. Path config (relative to appDir) To keep manifest in external JSON files, specify paths **relative to [appDir](/config/app-dir.md)**. ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ appDir: "src", manifest: { chromium: "manifest/manifest.chromium.json", firefox: "manifest/manifest.firefox.json", }, }); ``` ### 4. Omit (auto-load) When `manifest` is not set, the framework looks for: 1. `appDir/manifest.json`, `appDir/manifest.chromium.json`, `appDir/manifest.firefox.json` 2. `appDir/manifest/manifest.json`, `appDir/manifest/manifest.chromium.json`, `appDir/manifest/manifest.firefox.json` Any found file is used as base and merged with chromium/firefox files in the same directory. ## Specifying entry source files in manifest You can specify the **source file paths** of entries directly in the manifest. The framework automatically recognizes and builds them, replacing the paths with the output artifact paths. ```ts // addfox.config.ts export default defineConfig({ manifest: { name: "My Extension", version: "1.0.0", manifest_version: 3, // Specify source file paths directly background: { service_worker: "./background/index.ts", // source path }, action: { default_popup: "./popup/index.tsx", // source path }, content_scripts: [ { matches: [""], js: ["./content/index.ts"], // source path }, ], }, }); ``` The framework will: 1. Identify these source paths (`.ts`, `.tsx`, `.js`, `.jsx`). 2. Treat them as entries. 3. Replace them with build output paths (e.g. `background/index.js`) in the final `manifest.json`. ### Supported fields You can use source paths in the following manifest fields: | Field | Description | | ---------------------------------- | ---------------------- | | `background.service_worker` | MV3 background script | | `background.scripts` | MV2 background scripts | | `background.page` | Background page | | `action.default_popup` | MV3 popup page | | `browser_action.default_popup` | MV2 popup page | | `options_ui.page` / `options_page` | Options page | | `devtools_page` | DevTools page | | `side_panel.default_path` | Side panel | | `sandbox.pages` | Sandbox pages | | `chrome_url_overrides.newtab` | New tab override | | `chrome_url_overrides.bookmarks` | Bookmarks override | | `chrome_url_overrides.history` | History override | | `content_scripts[].js` | Content scripts | ### Entry resolution priority 1. **Highest**: Explicitly configured entries in `config.entry`. 2. **Second**: Source paths specified in `manifest`. 3. **Third**: Auto-discovery based on file conventions. ## Priority | Style | Description | | ----------------------------------- | ----------- | | manifest object or paths in config | Highest | | manifest\*.json in appDir root | Next | | manifest\*.json in appDir/manifest/ | Then | ## Related - [entry](/config/entry.md): Entry scripts and HTML determine manifest paths. - [appDir](/config/app-dir.md): Path config and auto-load are relative to appDir. - [outDir](/config/out-dir.md), [outputRoot](/config/out-dir.md): Build output directory. --- url: /config/out-dir.md --- # outDir `outDir` is the **build output directory name**, under [outputRoot](/config/out-dir.md). The full output path is `outputRoot/outDir`, default `.addfox/extension`. ## Type and default - **Type**: `string | undefined` - **Default**: `"extension"` - **Full path**: `path.resolve(root, outputRoot, outDir)`. ## Role - All entry outputs (JS, CSS, HTML) and the generated [manifest](/config/manifest.md) `manifest.json` go under this directory. - `addfox dev` loads the extension from this path. - When [zip](/config/zip.md) is enabled, `addfox build` produces `outDir.zip` (e.g. `extension.zip`) under outputRoot. ## Examples ### Default ```ts export default defineConfig({ // outDir default "extension" → output at .addfox/extension }); ``` ### Custom name ```ts export default defineConfig({ outDir: "build", outputRoot: ".addfox", // output at .addfox/build }); ``` ## Related - [outputRoot](/config/out-dir.md), [zip](/config/zip.md). --- url: /config/plugins.md --- # plugins `plugins` is the **Rsbuild plugins array** (like Vite), using function calls such as `plugins: [vue()]` or `plugins: [pluginReact()]`. Use it to add Vue (via `@addfox/rsbuild-plugin-vue`), React (via `@rsbuild/plugin-react`), or other Rsbuild plugins. ## Type and default - **Type**: `RsbuildConfig["plugins"]` - **Default**: When omitted, only framework-built-in plugins run (no Vue/React); you **must** add the Vue or React plugin explicitly if you use them. ## Framework-built-in plugins (auto-injected) These are injected by **@addfox/cli**; do **not** add them in config: | Plugin | Role | | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | **rsbuild-plugin-extension-entry** | Resolves [entry](/config/entry.md) and [appDir](/config/app-dir.md), sets Rsbuild entry, HTML templates, output paths, public copy | | **rsbuild-plugin-extension-manifest** | After build, writes resolved [manifest](/config/manifest.md) to `manifest.json` in the output dir (chromium/firefox by `-b`) | | **rsbuild-plugin-extension-hmr** | Dev only: WebSocket and browser reload | | **rsbuild-plugin-extension-monitor** | Dev only when `--debug` or `debug: true`: error monitoring, panel with Ask AI (ChatGPT, Cursor), theme toggle | ## User plugins: Vue / React Add the framework Vue or React plugin to enable that stack: ```ts // addfox.config.ts import { defineConfig } from "addfox"; import vue from "@addfox/rsbuild-plugin-vue"; // or for React: import { pluginReact } from "@rsbuild/plugin-react"; export default defineConfig({ plugins: [vue()], // or plugins: [pluginReact()], }); ``` ## With other Rsbuild plugins You can mix in Rsbuild plugins (e.g. Less): ```ts import { defineConfig } from "addfox"; import vue from "@addfox/rsbuild-plugin-vue"; import { pluginLess } from "@rsbuild/plugin-less"; export default defineConfig({ plugins: [vue(), pluginLess()], }); ``` ## Plugin order The framework assembles: **rsbuild-plugin-extension-entry** → user **plugins** (with Vue/React expanded) → **rsbuild-plugin-extension-manifest**. Do not add rsbuild-plugin-extension-entry, rsbuild-plugin-extension-manifest, or rsbuild-plugin-extension-hmr manually. ## Single plugin Always use an array: ```ts export default defineConfig({ plugins: [react()], }); ``` ## Related - [rsbuild](/config/rsbuild.md), [entry](/config/entry.md), [manifest](/config/manifest.md). --- url: /config/report.md --- # Build report (Rsdoctor) When enabled, addfox generates an **Rsdoctor** report for build analysis. The report is written under **`outputRoot/report`** (default **`.addfox/report`**), separate from the dist output. ## Enabling - **CLI**: `addfox build -r` or `addfox build --report` - **Config**: `report: true` in addfox.config ```ts export default defineConfig({ report: true, }); ``` ## Output - **Path**: `path.resolve(root, outputRoot, "report")`, e.g. `.addfox/report` - **Content**: Rsdoctor report (from `@rsdoctor/rspack-plugin`). Open the generated `index.html` in a browser to view compilation and bundle insights. ## Known limitation: Bundle Size tab With **multi-entry extension builds** (popup, options, content, background, etc.), the Rsdoctor UI **Bundle Size** tab may crash with: ```tree TypeError: Cannot destructure property 'size' of 'en.find(...)' as it is undefined. ``` This comes from the Rsdoctor client when some chunk does not have a matching size entry in the report data. It is an upstream/client bug, not addfox code. **Workarounds:** - Use other Rsdoctor tabs (e.g. Overview, Modules, Compilation) for analysis. - Try upgrading `@rsdoctor/rspack-plugin` / `@rsdoctor/core` to a newer version. - If the issue persists, consider opening an issue at [web-infra-dev/rsdoctor](https://github.com/web-infra-dev/rsdoctor). ## Related - [outputRoot](/config/out-dir.md), [outDir](/config/out-dir.md): dist output paths. --- url: /config/rsbuild.md --- # rsbuild `rsbuild` **overrides or extends Rsbuild config** (similar to Vite's `build.rollupOptions`, `esbuild`, etc.). It supports **object** (deep-merged with base) or **function** (full control, with `helpers.merge` for deep merge). ## Type and default - **Type**: `RsbuildConfig | ((base: RsbuildConfig, helpers?: RsbuildConfigHelpers) => RsbuildConfig | Promise) | undefined` - **Default**: Omitted → only framework base config (entry, HTML, output, manifest write are set by built-in plugins). ## Object form: deep merge An object is **deep-merged** with the framework base. Use for adding or overriding fields (e.g. `source.define`, `resolve.alias`). ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ rsbuild: { source: { define: { __APP_NAME__: JSON.stringify("my-ext") }, }, resolve: { alias: { "@": "/src" }, }, }, }); ``` ## Function form: full control A function receives `(base, helpers)`: - **base**: Framework-generated Rsbuild config. - **helpers.merge(base, overrides)**: Deep-merge overrides into base and return. Use when you need env, async logic, or complex conditions. ```ts export default defineConfig({ rsbuild(base, helpers) { return helpers!.merge(base, { source: { define: { __ENV__: JSON.stringify(process.env.NODE_ENV) } }, }); }, }); ``` Async: ```ts export default defineConfig({ async rsbuild(base, helpers) { const overrides = await loadSomeConfig(); return helpers!.merge(base, overrides); }, }); ``` ## Common use cases | Need | Example | | ----------------- | ----------------------------------------------------------------------------------------------- | | **define** | `rsbuild: { source: { define: { __BUILD_TIME__: JSON.stringify(Date.now()) } } }` | | **alias** | `rsbuild: { resolve: { alias: { "@": "/src" } } }` | | **Extra plugins** | In function form: `base.plugins = [...(base.plugins ?? []), myPlugin()]` or merge | | **output** | Prefer merging in function form so you don't override framework `distPath`, `assetPrefix`, etc. | ## Notes - The framework sets `output.distPath`, `output.cleanDistPath`, `output.assetPrefix`, and entry output filenames. Overriding `output` in rsbuild can break manifest paths; prefer incremental merge. ## Related - [plugins](/config/plugins.md). --- url: /config/test.md --- # test `test` passes test configuration directly to **Rstest** — it is equivalent to the export of a `rstest.config` file, so you don't need to create a separate config file. Similar to how Vite integrates Vitest via the `test` field. ## Type and default - **Type**: `RstestConfig & { framework?: "rstest" }` - **Default**: `undefined` `framework` is a reserved test framework discriminator: - Defaults to `"rstest"`, and only `"rstest"` is currently supported. - Any other value throws `ADDFOX_INVALID_ARGUMENT`. - Addfox strips the `framework` key before generating the pass-through config. ## Example ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ manifest: { /* ... */ }, test: { include: ["__tests__/**/*.test.ts"], globals: true, coverage: { provider: "istanbul" }, }, }); ``` ## Precedence with rstest.config Following the industry convention (same as `vitest.config` taking precedence over the `test` field in `vite.config`), `addfox test` resolves test config in this order (highest first): 1. `rstest.config.*` (if present) 2. `test` field in `addfox.config` When both exist, the `test` field is ignored and a warning is printed: ``` The `test` field in addfox.config is ignored because rstest.config.* takes precedence. ``` If neither exists, `addfox test` errors and asks you to create a `rstest.config.*` file or add a `test` field to `addfox.config`. ## How it works When the `test` field is used, addfox auto-generates a wrapper config at `.addfox/rstest.config.ts` that re-imports your `addfox.config` (live objects such as functions and reporters are preserved) and passes it to the rstest CLI via `--config`. The `.addfox` directory is already gitignored. `root` is set to the project root; you can override it with `test.root`. ## Browser tests `browser.enabled: true` written inside the `test` field is also recognized, so addfox will prompt you to install the `@rstest/browser` and `playwright` dependencies. ## CLI args All other `addfox test` behavior is unchanged: CLI arguments are forwarded to rstest as-is. --- url: /config/zip.md --- # zip `zip` controls whether `addfox build` packs the output directory into a zip file (e.g. for store upload or distribution). Only affects **build**; **dev** does not produce a zip. ## Type and default - **Type**: `boolean | undefined` - **Default**: `true` (zip is produced) ## Behavior - **`true` or omitted**: After build, creates `{outDir}.zip` under [outputRoot](/config/out-dir.md), e.g. `.addfox/extension.zip`, containing the full [outDir](/config/out-dir.md) contents. - **`false`**: Only outputs the directory, no zip. ## Examples ### Default (zip on) ```ts export default defineConfig({ outDir: "extension", outputRoot: ".addfox", // zip true → .addfox/extension.zip }); ``` ### Disable zip ```ts export default defineConfig({ zip: false, // only .addfox/extension, no zip }); ``` ## Related - [outDir](/config/out-dir.md), [outputRoot](/config/out-dir.md). --- url: /examples/index.md --- # Examples This page lists extension examples in the addfox repo. Each example is a separate directory with its own `package.json` and `addfox.config.ts`. Run install in the repo root (pnpm / npm / yarn / bun), then run dev or build in the example directory. | Example | Description | Repo link | | ---------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | **addfox-with-vue** | Vue 3 template: popup, options, content, background with simple messaging. | [examples/addfox-with-vue](https://github.com/addfox/addfox/tree/main/examples/addfox-with-vue) | | **addfox-with-react** | React template: popup, options, content, background with simple messaging. | [examples/addfox-with-react](https://github.com/addfox/addfox/tree/main/examples/addfox-with-react) | | **addfox-with-preact** | Preact template: popup, options, content, background with simple messaging. | [examples/addfox-with-preact](https://github.com/addfox/addfox/tree/main/examples/addfox-with-preact) | | **addfox-with-svelte** | Svelte template: popup, options, content, background with simple messaging. | [examples/addfox-with-svelte](https://github.com/addfox/addfox/tree/main/examples/addfox-with-svelte) | | **addfox-with-solid** | Solid template: popup, options, content, background with simple messaging. | [examples/addfox-with-solid](https://github.com/addfox/addfox/tree/main/examples/addfox-with-solid) | | **addfox-with-react-shadcn** | React + shadcn/ui: popup, options, content, background, sidepanel; Tailwind + component library. | [examples/addfox-with-react-shadcn](https://github.com/addfox/addfox/tree/main/examples/addfox-with-react-shadcn) | | **addfox-with-devtools** | Plain TypeScript: background + devtools\_page only, no React/Vue; demonstrates a DevTools extension. | [examples/addfox-with-devtools](https://github.com/addfox/addfox/tree/main/examples/addfox-with-devtools) | | **addfox-with-content-ui** | Content UI example for mounting extension UI on web pages. | [examples/addfox-with-content-ui](https://github.com/addfox/addfox/tree/main/examples/addfox-with-content-ui) | | **addfox-with-content-ui-react** | React-based Content UI example. | [examples/addfox-with-content-ui-react](https://github.com/addfox/addfox/tree/main/examples/addfox-with-content-ui-react) | | **addfox-with-tailwindcss** | Tailwind CSS integration example. | [examples/addfox-with-tailwindcss](https://github.com/addfox/addfox/tree/main/examples/addfox-with-tailwindcss) | | **addfox-with-uno** | UnoCSS integration example. | [examples/addfox-with-uno](https://github.com/addfox/addfox/tree/main/examples/addfox-with-uno) | | **addfox-with-vue-tsx** | Vue + TSX example. | [examples/addfox-with-vue-tsx](https://github.com/addfox/addfox/tree/main/examples/addfox-with-vue-tsx) | | **addfox-with-firefox** | Firefox target build and run example. | [examples/addfox-with-firefox](https://github.com/addfox/addfox/tree/main/examples/addfox-with-firefox) | | **addfox-with-mv2** | Manifest V2 compatibility example (migration/contrast use). | [examples/addfox-with-mv2](https://github.com/addfox/addfox/tree/main/examples/addfox-with-mv2) | | **addfox-with-manifest-entries** | Example using manifest-based entry declarations. | [examples/addfox-with-manifest-entries](https://github.com/addfox/addfox/tree/main/examples/addfox-with-manifest-entries) | | **addfox-with-react-entry-false** | React example for `entry: false` (entry managed by rsbuild). | [examples/addfox-with-react-entry-false](https://github.com/addfox/addfox/tree/main/examples/addfox-with-react-entry-false) | | **addfox-with-single-file** | Single-file/minimal structure example. | [examples/addfox-with-single-file](https://github.com/addfox/addfox/tree/main/examples/addfox-with-single-file) | | **addfox-with-sandbox** | Sandbox page example. | [examples/addfox-with-sandbox](https://github.com/addfox/addfox/tree/main/examples/addfox-with-sandbox) | | **addfox-with-newtab-override** | New Tab page override example. | [examples/addfox-with-newtab-override](https://github.com/addfox/addfox/tree/main/examples/addfox-with-newtab-override) | | **addfox-with-history-override** | History page override example. | [examples/addfox-with-history-override](https://github.com/addfox/addfox/tree/main/examples/addfox-with-history-override) | | **addfox-with-bookmarks-override** | Bookmarks page override example. | [examples/addfox-with-bookmarks-override](https://github.com/addfox/addfox/tree/main/examples/addfox-with-bookmarks-override) | | **addfox-with-rstest** | Rstest unit testing integration example. | [examples/addfox-with-rstest](https://github.com/addfox/addfox/tree/main/examples/addfox-with-rstest) | | **addfox-with-rstest-e2e** | Rstest + E2E testing example. | [examples/addfox-with-rstest-e2e](https://github.com/addfox/addfox/tree/main/examples/addfox-with-rstest-e2e) | | **addfox-with-env-vars** | Env variable injection and scoping example (`ADDFOX_PUBLIC_` + private vars). | [examples/addfox-with-env-vars](https://github.com/addfox/addfox/tree/main/examples/addfox-with-env-vars) | ## How to run From the addfox repo root, run install, then go to an example directory: **[object Object]** ```bash pnpm install cd examples/addfox-with-vue # or another example pnpm dev # dev mode pnpm build # build ``` **[object Object]** ```bash npm install cd examples/addfox-with-vue # or another example npm run dev # dev mode npm run build # build ``` **[object Object]** ```bash yarn install cd examples/addfox-with-vue # or another example yarn dev # dev mode yarn build # build ``` **[object Object]** ```bash bun install cd examples/addfox-with-vue # or another example bun run dev # dev mode bun run build # build ``` Output goes to `.addfox/extension` (or the example's outputRoot/outDir). Load that directory in the browser; with dev mode, the framework can open the browser and load the extension automatically. --- url: /gallery/index.md --- # Gallery ## Gallery Extensions built with Addfox [Showcase Your Work](https://github.com/addfox/addfox/issues) ![Video Roll](https://lh3.googleusercontent.com/6OTCPAnluByBbifpbtTkg8dZD3KyiZwHNyyEpOxpfrXffPbRK2cP8w9xY9dgdHJxSaferUfV18qSDRlvUZT3tOYT3kY=s128) ### Video Roll All-in-One browser extension to enhance your video watching experience. Rotate, zoom, download, record, VR mode, AI summarization, and more. [Chrome Web Store](https://chromewebstore.google.com/detail/video-roll/cokngoholafkeghnhhdlmiadlojpindm)[Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/video-roll/indeeigndpaahbcegcanpmbenmkbkmmn) --- url: /guide/ai/error.md --- # error.md When Addfox monitors a runtime error in a browser extension, it generates an `error.md` file in the `.addfox/` directory at the project root. ## 1. Core Structure The generated `error.md` contains the following standard sections: ### Error Summary Provides basic metadata, including: - **Entry**: The entry point where the error occurred (e.g., `content`, `background`, `popup`). - **Type**: Type of error (e.g., `error`, `warning`). - **Time**: Local time when the error occurred. - **Message**: Original error message content. - **Location**: Source code location or path of the compiled resource. ### Build Context Provides basic info about the build tech stack, such as: - **Bundler**: Build tool name (usually `rsbuild`). - **Framework**: Current UI framework used. ### Stack Trace Provides the full JavaScript error call stack. AI uses this section to quickly trace back to the specific line of code that caused the crash. *** > **Note**: This file only keeps information about the most recent error. When the dev server restarts or a new error occurs, the old content will be cleared. --- url: /guide/ai/llms.md --- # llms.txt `llms.txt` is the core context file for AI assistants provided by Addfox. It is located in the `.addfox/` directory at the project root and helps AI build a global understanding of the project at the beginning of the conversation. ## 1. Core Structure The generated `llms.txt` contains the following standard sections: ### Project Overview Lists standard metadata such as name, description, version, and framework information. ### Entry Points Index Lists all identified extension entries (e.g., background, content, popup) and their absolute source file paths. ### AI Context Files Guide Introduces the purpose of other auxiliary files in the `.addfox/` directory, including `llms.txt` itself, `meta.md`, and `error.md`. ### Quick Decision Guide Provides a scenario-based reference, telling AI which file to consult for situations like "first time seeing the project," "understanding structure," "build issues," or "runtime errors." ### Framework Conventions Explains core Addfox conventions, such as standard entry names and the meaning of entry configuration options (html, scriptInject, etc.). *** > **Note**: This file is automatically generated by the Addfox framework. It updates as project configurations change, so always guide AI to read the latest version. --- url: /guide/ai/meta.md --- # meta.md `meta.md` is the detailed structured context for AI assistants, located in the `.addfox/` directory at the project root. ## 1. Core Structure The generated `meta.md` contains the following standard sections: ### Basic Information Includes framework name, project name, description, version, and the current Manifest version number. ### Permissions Lists permissions requested by the extension in three categories: - **Permissions**: Core feature permissions. - **Host Permissions**: Permissions for specific hosts. - **Optional Permissions**: Permissions that can be requested at runtime. ### Entry Mappings The most critical section, listing detailed information for all extension entries: - **Source**: Absolute path to the source code file. - **HTML**: Path to the associated HTML template (if it exists). - **JS Output**: Path to the generated script in the build output. - **Flags**: Configuration flags for the entry (e.g., `html: true`, `scriptInject: body`). *** > **Note**: Before making complex architectural adjustments or modifying `addfox.config.ts`, always guide the AI to read this file to ensure compatibility with the current project structure. --- url: /guide/app-dir.md --- # App Directory Addfox follows a convention-over-configuration design philosophy. Understanding the standard directory structure helps you get started quickly and follow best practices. ## Project Root A typical Addfox project structure looks like this: ``` my-extension/ ├── .addfox/ # Build output and cache (auto-generated) ├── app/ # Application source code (configurable) ├── public/ # Static assets ├── addfox.config.ts # Addfox configuration file └── package.json # Project dependencies ``` ## .addfox Directory `.addfox` is **auto-generated** by the framework and contains: - **`extension/`** — Default build output directory (can be changed via `outDir`) - **`cache/`** — Persistent build cache (`cache/build/`), plus dev browser profiles (`cache/browser-profile/`) when `keepBrowserProfile` is enabled :::tip Avoid deleting the `cache` directory unless necessary — it speeds up subsequent builds. If you enabled `keepBrowserProfile`, it also holds the dev browser profile (login sessions, extension state). ::: ## app Directory `app/` is the default application source directory, containing all extension entries and manifest files. You can change it via the `appDir` config option: ```ts // addfox.config.ts export default defineConfig({ appDir: "src", // Change to src directory }); ``` ### Recommended Directory Structure **Multi-file structure (recommended)** ``` app/ ├── background/ │ └── index.ts # Service Worker / background script ├── content/ │ └── index.ts # Content script ├── popup/ │ ├── index.html # Popup HTML (optional) │ └── index.ts # Popup script ├── options/ │ ├── index.html # Options HTML (optional) │ └── index.ts # Options script ├── sidepanel/ │ └── index.ts # Side panel ├── manifest/ │ ├── manifest.json # Base configuration │ ├── manifest.chromium.json # Chrome overrides │ └── manifest.firefox.json # Firefox overrides └── ... ``` **Single-file structure** ``` app/ ├── background.ts # Background script ├── content.ts # Content script ├── popup.html # Popup page ├── popup.ts # Popup script ├── manifest.json # Extension manifest └── ... ``` :::info For more about entry discovery rules, see [File-based Entry](/guide/entry/file-based.md) and [`entry` config](/config/entry.md). ::: ## public Directory `public/` is for **static assets**, which are copied as-is to the output directory during build without processing: ``` public/ ├── icons/ # Extension icons │ ├── icon16.png │ ├── icon48.png │ └── icon128.png ├── _locales/ # Internationalization files │ └── zh_CN/ │ └── messages.json └── welcome.html # Welcome page ``` When referencing these resources in code, use paths relative to the output root: ```ts // Reference public/icons/icon16.png const iconPath = "icons/icon16.png"; ``` ## Entry Types Addfox supports the following built-in entries: | Entry Name | Type | Description | Generates HTML | | ------------ | ------------- | ---------------------------------- | -------------- | | `background` | Script only | Service Worker / background script | No | | `content` | Script only | Content script | No | | `popup` | Script + Page | Toolbar popup | Yes | | `options` | Script + Page | Extension options page | Yes | | `sidepanel` | Script + Page | Side panel | Yes | | `devtools` | Script + Page | Developer tools | Yes | | `offscreen` | Script + Page | Offscreen document | Yes | :::warning Built-in entry names **cannot be changed**, as Addfox relies on them for automatic recognition. ::: ## Configuration Files ### addfox.config.ts / addfox.config.js This is the **required configuration file** for Addfox, used to declare: - Extension manifest - Entry files - Output directory - Rsbuild plugins and configuration ### Minimal Configuration Example ```ts import { defineConfig } from "addfox"; export default defineConfig({ // When omitted, framework auto-discovers entries and manifest from app/ }); ``` ## Related Configuration - [`appDir`](/config/app-dir.md) — Customize application directory - [`entry`](/config/entry.md) — Manually configure entries - [`outDir`](/config/out-dir.md) — Customize output directory - [`manifest`](/config/manifest.md) — Manifest configuration methods --- url: /guide/cache.md --- # Cache Addfox creates a `.addfox/cache` directory in your project to speed up development. ## What is stored in `.addfox/cache` - **`cache/build/`** — Rspack persistent build cache. Enabled by default, it speeds up rebuilds and dev restarts. Configure it with [`buildCache`](/config/cache.md). - **`cache/browser-profile/`** — Chromium user-data (profile) directories. By default every `addfox dev` run starts from a **fresh profile**; the profile is only kept between runs when you enable [`keepBrowserProfile`](/config/cache.md) (top-level config, per-browser override, or the `--keep-browser-profile` CLI flag). The exact files can differ by platform and mode, but the goal is the same: **avoid repeated cold initialization**. ## Why it matters - **Faster rebuilds**: the persistent build cache skips recompiling unchanged modules. - **Optional profile persistence**: with `keepBrowserProfile` enabled, extension install state, settings, and login sessions survive across `addfox dev` runs. ## When to clear cache Clear `.addfox/cache` if you see: - Unexpected browser profile behavior - Extension load state inconsistencies - Need for a clean-slate debugging environment You can safely delete the directory; Addfox recreates it on next run. ## Related Configuration - [`keepBrowserProfile` / `buildCache`](/config/cache.md) - Cache configuration --- url: /guide/cli.md --- # CLI This page lists the supported `addfox` CLI commands and options. ## Basic Usage ```bash addfox [options] ``` ## Configure scripts in package.json ```json { "scripts": { "dev": "addfox dev", "dev:firefox": "addfox dev -b firefox", "build": "addfox build", "build:chrome": "addfox build -b chrome", "test": "addfox test" } } ``` ## Commands | Command | Description | | ------- | ----------------------------------------------- | | `dev` | Start development mode with hot reload support. | | `build` | Build production output. | | `test` | Run tests (forward args to rstest). | > `addfox test` reads its config from `rstest.config.*` or the [`test`](/config/test.md) field in `addfox.config`; when both exist, `rstest.config.*` takes precedence. ## Common Options (Defaults + Config Mapping) | Option | Built-in Default | `addfox.config` Field | Description | | --------------------------- | ------------------------------ | ------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `-b, --browser ` | `chromium` | No direct field (command-level target/launch selection) | Target/launch browser. See [Supported Browsers List](#supported-browsers-list) below. | | `--port ` | `3000` | No direct field | Rsbuild dev server port. Only applies to `dev`. | | `--keep-browser-profile` | `false` | `keepBrowserProfile` | Keep browser profile between launches (default: fresh profile each run). | | `--no-keep-browser-profile` | `false` (for this run) | `keepBrowserProfile` | Use a fresh browser profile for current run. | | `-r, --report` | `false` | `report` | Enable Rsdoctor build report. | | `--no-open` | `false` (default is auto-open) | No direct field | Do not auto-open browser. | | `--debug` | `false` | `debug` | Enable debug mode (error monitor in dev). | | `--help` | - | - | Print help. | | `--version` | - | - | Print version. | > `-c, --cache` and `--no-cache` are deprecated aliases of `--keep-browser-profile` / `--no-keep-browser-profile`; they still work but print a deprecation warning in the terminal. ## Supported Browsers List The `-b, --browser` option supports the following browsers: | Browser | Description | | ----------- | ---------------------------------------------------- | | `chromium` | Chromium (default) | | `chrome` | Google Chrome | | `edge` | Microsoft Edge | | `brave` | Brave Browser | | `vivaldi` | Vivaldi | | `opera` | Opera | | `santa` | Santa Browser | | `arc` | Arc Browser | | `yandex` | Yandex Browser | | `browseros` | BrowserOS | | `custom` | Custom browser (requires `browser.custom` in config) | | `firefox` | Mozilla Firefox | ## Examples ```bash # Development (Chromium) addfox dev -b chromium # Development on a custom port addfox dev --port 3100 -b edge # Development (Firefox) with debug monitor addfox dev -b firefox --debug # Production build addfox build -b chrome # Build without opening browser addfox build -b chrome --no-open # Build with report addfox build -r ``` ## Entry Paths and HTML Templates Entry paths passed to `entry` or discovered by the framework can point to either a **script** (`.ts/.tsx/.js/.jsx`) or an **HTML template** (`.html`). - **Script path**: the framework uses the script as the build entry and auto-generates HTML for entries that need it. - **HTML path**: you can write the entry path as `popup/index.html`, but you must still tell the framework which script is the entry. Do this by adding `data-addfox-entry` to a ` ``` ## Built-in and Custom Entries ### Built-in Entries (Reserved Names) The following names have special meanings and are automatically recognized by Addfox: | Entry Name | Description | | ------------ | --------------------------------------------- | | `background` | Service Worker (MV3) or background page (MV2) | | `content` | Content script | | `popup` | Toolbar popup | | `options` | Extension options page | | `sidepanel` | Side panel | | `devtools` | Developer tools | | `offscreen` | Offscreen document | :::warning Built-in entry names cannot be changed. The framework relies on these names for automatic recognition and manifest path filling. ::: ### Custom Entries In addition to built-in entries, you can configure any name in `entry` as a **custom entry** (e.g., `capture`, `my-page`): ```ts export default defineConfig({ entry: { capture: { src: "capture/index.ts", html: true }, }, }); ``` Custom entries produce standalone pages accessible via `chrome-extension:///capture/index.html`. ## Next Steps - [File-based Entry](/guide/entry/file-based.md) — Learn convention-based entry discovery - [Config-based Entry](/guide/entry/config-based.md) — Learn explicit entry + manifest configuration - [manifest configuration](/config/manifest.md) — Configure extension capabilities --- url: /guide/entry/config-based.md --- # Config-based Entry When configuring with `entry` and `manifest` in `addfox.config.ts`, you can: - Customize entry paths - Override auto-discovery results - Add **custom entries** (e.g., `capture`, `my-page`) Entries not listed in `entry` will still be auto-discovered via [file-based rules](/guide/entry/file-based.md). ## Core Principles Consistent with file-based entries: - **Entries must be JS/TS**: Built on Rsbuild, real entries can only be script files - **HTML handling**: Built-in HTML entries (popup/options, etc.) auto-generate; when using custom HTML templates, must mark entry script with `data-addfox-entry` - **When HTML is auto-generated** (no custom template): the page includes **`
`**; **``** matches **`manifest.name`**; the **favicon** is a **`<link rel="icon">`** pointing at **`manifest.icons`**. With a custom `index.html`, those are **not** injected automatically—add `<title>` and icon links yourself. ## Configuration Methods ### 1) Configure via `entry` `entry` is an object: **key = entry name, value = path or config object**. ### 2) Configure entry-related fields via `manifest` In `manifest`, declare entry-related capability fields (e.g., `background`, `action.default_popup`, `content_scripts`): ```ts export default defineConfig({ manifest: { manifest_version: 3, background: { service_worker: "background/index.js" }, action: { default_popup: "popup/index.html" }, content_scripts: [ { matches: ["<all_urls>"], js: ["content/index.js"] }, ], }, }); ``` ### 3) Priority between `entry` and `manifest` When both participate in entry resolution, the priority is: 1. Explicit configuration in `entry` 2. Entry-related fields in `manifest` 3. Auto-discovery (file-based) That is: `entry` will override entries from other sources with the same name. ### String path (recommended) Value is a path **relative to baseDir** (default `app/`): | Value Type | Meaning | Example | | ---------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------- | | Script path `.ts/.tsx` | Use this script as entry; built-in HTML entries auto-generate HTML or use `index.html` in same directory as template | `"popup/index.ts"` | | HTML path `.html` | Use this HTML as template; must resolve entry script via `data-addfox-entry` | `"popup/index.html"` | ### Object form: `{ src, html? }` More fine-grained control: | Field | Type | Description | | ------ | ------------------- | -------------------------------------------------------------------------------------------------- | | `src` | `string` | Entry script path (relative to baseDir) **required** | | `html` | `boolean \| string` | `true`: generate HTML without template; `false`: script only; `string`: specify HTML template path | ## Built-in Entries and Output Paths When configuring built-in entries via `entry`, default output paths are as follows: | Entry Name | Type | Output Script | Output HTML | | ------------ | ------------- | --------------------- | ---------------------- | | `background` | Script only | `background/index.js` | — | | `content` | Script only | `content/index.js` | — | | `popup` | Script + HTML | `popup/index.js` | `popup/index.html` | | `options` | Script + HTML | `options/index.js` | `options/index.html` | | `sidepanel` | Script + HTML | `sidepanel/index.js` | `sidepanel/index.html` | | `devtools` | Script + HTML | `devtools/index.js` | `devtools/index.html` | | `offscreen` | Script + HTML | `offscreen/index.js` | `offscreen/index.html` | :::info In the manifest, the framework automatically fills `action.default_popup`, `options_page`, and other fields with the above paths. ::: ## Configuration Examples ### Override some entries ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ entry: { // Only override these entries, others still auto-discovered popup: "popup/main.tsx", options: "options/settings.tsx", }, }); ``` ### Configure all entries completely ```ts export default defineConfig({ appDir: "src", entry: { background: "background/index.ts", content: "content/index.ts", popup: "popup/index.tsx", options: "options/index.tsx", sidepanel: "sidepanel/index.tsx", }, }); ``` ### Custom entry + force HTML generation ```ts export default defineConfig({ entry: { // Built-in entries background: "background/index.ts", content: "content/index.ts", popup: "popup/index.tsx", // Custom page entry (auto-generate HTML) capture: { src: "pages/capture/index.tsx", html: true }, // Custom page entry (use template) welcome: { src: "pages/welcome/index.tsx", html: "pages/welcome/template.html" }, // Script-only entry (no HTML) worker: { src: "worker/index.ts", html: false }, }, }); ``` ### Disable entry auto-discovery If you need full manual control of all entries: ```ts export default defineConfig({ entry: { background: "background/index.ts", content: "content/index.ts", popup: "popup/index.tsx", // ... list all required entries }, // Keep other config items undefined, framework only processes entries listed in entry }); ``` ## Path Resolution Rules ### Relative to baseDir All paths in `entry` are **relative to baseDir**, where baseDir is determined by [`appDir`](/config/app-dir.md) (default `app`): ```ts export default defineConfig({ appDir: "src", // baseDir = src/ entry: { popup: "popup/index.ts", // points to src/popup/index.ts }, }); ``` ### Path Quick Reference | Configuration | Entry Script Location | Typical Output | | -------------------------------------------------- | ------------------------- | ------------------------------------------------------------- | | `background: "background/index.ts"` | `app/background/index.ts` | `extension/background/index.js` | | `content: "content.ts"` | `app/content.ts` | `extension/content.js` | | `popup: "popup/index.ts"` | `app/popup/index.ts` | `extension/popup/index.html` + `extension/popup/index.js` | | `capture: { src: "capture/index.ts", html: true }` | `app/capture/index.ts` | `extension/capture/index.html` + `extension/capture/index.js` | ## Next Steps - [File-based Entry](/guide/entry/file-based.md) — Learn auto-discovery rules - [appDir configuration](/config/app-dir.md) — Modify source directory - [manifest configuration](/config/manifest.md) — Configure extension manifest --- url: /guide/entry/file-based.md --- # File-based Entry **Do not configure `entry`**, let the framework discover entries automatically by directory and file name under `appDir` (default is `app/`). ## Directory Convention Create directories under `app/` using entry names: ```tree app/ ├── background/ │ └── index.ts # → background entry ├── content/ │ └── index.ts # → content entry ├── popup/ │ └── index.ts # → popup entry ├── options/ │ └── index.ts # → options entry ├── sidepanel/ │ └── index.ts # → sidepanel entry ├── devtools/ │ └── index.ts # → devtools entry └── ... ``` ## Discovery Rules The framework automatically recognizes the following reserved entry names: | Entry Name | Type | Discovery Rule | | ------------ | ------------- | ---------------------------------------------------------- | | `background` | Script only | `app/background/index.{ts,js}` or `app/background.{ts,js}` | | `content` | Script only | `app/content/index.{ts,js}` or `app/content.{ts,js}` | | `popup` | Script + HTML | `app/popup/index.{ts,tsx,js,jsx}` | | `options` | Script + HTML | `app/options/index.{ts,tsx,js,jsx}` | | `sidepanel` | Script + HTML | `app/sidepanel/index.{ts,tsx,js,jsx}` | | `devtools` | Script + HTML | `app/devtools/index.{ts,tsx,js,jsx}` | | `offscreen` | Script + HTML | `app/offscreen/index.{ts,tsx,js,jsx}` | ## HTML Handling ### Entries without HTML `background` and `content` only need script files. The framework builds them as pure JS entries. ### Entries with HTML `popup`, `options`, `sidepanel`, `devtools`, `offscreen` need HTML templates: 1. **Auto-generated HTML** (no `index.html` in the entry folder): Rsbuild generates a page that includes: - **`<div id="root"></div>`** as the mount point (for `createRoot`, `mount`, etc.). - **`<title>`** taken from **`manifest.name`**. - A **favicon** via **`<link rel="icon">`**, whose **`href` comes from `manifest.icons`** (a suitable size is chosen; the URL is resolved relative to the emitted HTML). 2. **Custom HTML template**: Create `index.html` in the same directory and mark the entry script with `data-addfox-entry`. In this case, **manifest-driven `title` / icon injection is not applied**—set `<title>` and any `<link rel="icon">` yourself (you usually still keep **`id="root"`** for framework mounts). ### Example: Custom HTML Template ```html <!-- app/popup/index.html --> <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Popup
``` ## Advantages - **Zero configuration**: Follow conventions, no config needed - **Clear structure**: One directory per entry, easy to navigate - **Easy to extend**: Add new entries by creating directories - **Framework-agnostic**: Works with React, Vue, Svelte, or vanilla JS ## When to Use File-based entry is recommended when: - You follow standard extension architecture - You want minimal configuration - Your project structure aligns with entry organization ## Hybrid with Config-based File-based discovery works alongside config-based entry. If you need to override specific entries while keeping auto-discovery for others: ```ts export default defineConfig({ entry: { // Override popup only popup: "custom/popup/main.tsx", }, // background, content, options still auto-discovered }); ``` Priority: `config.entry` > manifest source paths > auto-discovery ## Next Steps - [Entry Concepts](/guide/entry/concept.md) — Learn about entry types and principles - [Config-based Entry](/guide/entry/config-based.md) — Learn explicit entry configuration - [manifest configuration](/config/manifest.md) — Configure extension manifest --- url: /guide/env-prefix.md --- # Environment Variables Addfox supports environment variables via `.env` files that can be safely used in client-side code. ## Basic Usage Create a `.env` file in the project root: ```bash # .env ADDFOX_PUBLIC_API_URL=https://api.example.com ADDFOX_PUBLIC_APP_NAME=My Extension ADDFOX_PRIVATE_API_KEY=secret_key_here ``` ## Default Prefix Addfox only exposes environment variables starting with `ADDFOX_PUBLIC_` by default: ```ts // app/popup/index.tsx console.log(process.env.ADDFOX_PUBLIC_API_URL); // ✅ "https://api.example.com" console.log(process.env.ADDFOX_PUBLIC_APP_NAME); // ✅ "My Extension" console.log(process.env.ADDFOX_PRIVATE_API_KEY); // ❌ undefined console.log(process.env.PRIVATE_API_KEY); // ❌ undefined ``` ## Scope Environment variables are injected into all **client code** entries: - **background** — Service Worker / Background script - **content** — Content Script - **popup** — Popup page - **options** — Options page - **sidepanel** — Side panel - **devtools** — Developer tools :::tip Server vs Client - `process.env.*` in `manifest` config is resolved at **build time** (server-side) - `process.env.*` in entry code is available at **runtime** (client-side) ::: ## Built-in Variables Addfox automatically injects the following built-in variables (no need to define in `.env`): | Variable | Description | Example | | ---------------------------- | -------------------- | --------------------------- | | `process.env.BROWSER` | Current build target | `chrome`, `firefox` | | `process.env.NODE_ENV` | Current environment | `development`, `production` | | `process.env.ADDFOX_VERSION` | Addfox version | `1.0.0` | ## Different Environments ### Development Create `.env.development`: ```bash # .env.development ADDFOX_PUBLIC_API_URL=http://localhost:3000 ADDFOX_PUBLIC_DEBUG=true ``` ### Production Create `.env.production`: ```bash # .env.production ADDFOX_PUBLIC_API_URL=https://api.example.com ADDFOX_PUBLIC_DEBUG=false ``` ### Environment File Priority 1. `.env.{mode}.local` — Local specific mode (highest priority, not committed to Git) 2. `.env.{mode}` — Specific mode 3. `.env.local` — Local environment (not committed to Git) 4. `.env` — Default (lowest priority) ## Complete Example ```bash # .env ADDFOX_PUBLIC_API_URL=https://api.example.com ADDFOX_PUBLIC_FEATURE_FLAG=true ADDFOX_PRIVATE_DATABASE_URL=secret ``` ```ts // addfox.config.ts export default defineConfig({ manifest: { name: process.env.ADDFOX_PUBLIC_APP_NAME || "My Extension", }, }); ``` ```ts // app/popup/index.tsx const apiUrl = process.env.ADDFOX_PUBLIC_API_URL; const showFeature = process.env.ADDFOX_PUBLIC_FEATURE_FLAG === "true"; ``` ## Notes - Environment variable values are always strings - Booleans need manual conversion: `process.env.ADDFOX_PUBLIC_DEBUG === "true"` - Restart dev server after modifying `.env` files - Don't use non-`ADDFOX_PUBLIC_` prefixed variables in client code, they will be `undefined` --- url: /guide/framework.md --- # Framework Support Addfox supports mainstream frontend frameworks and provides dedicated examples and guidance. Choose your stack below: - [React](/guide/framework/react.md) - [Vue](/guide/framework/vue.md) - [Svelte](/guide/framework/svelte.md) - [Solid](/guide/framework/solid.md) - [Preact](/guide/framework/preact.md) --- url: /guide/framework/preact.md --- # Preact Add `@rsbuild/plugin-preact` to **plugins** in `addfox.config.ts` to enable Preact and JSX/TSX. ## Setup **[object Object]** ```bash pnpm add preact pnpm add @rsbuild/plugin-preact -D ``` **[object Object]** ```bash npm install preact npm install @rsbuild/plugin-preact -D ``` **[object Object]** ```bash yarn add preact yarn add @rsbuild/plugin-preact -D ``` **[object Object]** ```bash bun add preact bun add @rsbuild/plugin-preact -D ``` ```ts // addfox.config.ts import { defineConfig } from "addfox"; import { pluginPreact } from "@rsbuild/plugin-preact"; export default defineConfig({ plugins: [pluginPreact()], }); ``` ## Related - [Basics](/guide/manifest.md), [entry](/guide/entry.md). --- url: /guide/framework/react.md --- # React Add `@rsbuild/plugin-react` to **plugins** in `addfox.config.ts` to enable React and JSX/TSX. ## Setup **[object Object]** ```bash pnpm add react react-dom pnpm add @rsbuild/plugin-react -D ``` **[object Object]** ```bash npm install react react-dom npm install @rsbuild/plugin-react -D ``` **[object Object]** ```bash yarn add react react-dom yarn add @rsbuild/plugin-react -D ``` **[object Object]** ```bash bun add react react-dom bun add @rsbuild/plugin-react -D ``` ```ts // addfox.config.ts import { defineConfig } from "addfox"; import { pluginReact } from "@rsbuild/plugin-react"; export default defineConfig({ plugins: [pluginReact()], }); ``` ## Related - [Basics](/guide/manifest.md), [entry](/guide/entry.md). --- url: /guide/framework/solid.md --- # Solid Add `@rsbuild/plugin-babel` and `@rsbuild/plugin-solid` to **plugins** in `addfox.config.ts` to enable Solid and JSX/TSX. Solid's JSX requires Babel, so both plugins are needed. ## Setup **[object Object]** ```bash pnpm add solid-js pnpm add @rsbuild/plugin-babel @rsbuild/plugin-solid -D ``` **[object Object]** ```bash npm install solid-js npm install @rsbuild/plugin-babel @rsbuild/plugin-solid -D ``` **[object Object]** ```bash yarn add solid-js yarn add @rsbuild/plugin-babel @rsbuild/plugin-solid -D ``` **[object Object]** ```bash bun add solid-js bun add @rsbuild/plugin-babel @rsbuild/plugin-solid -D ``` ```ts // addfox.config.ts import { defineConfig } from "addfox"; import { pluginBabel } from "@rsbuild/plugin-babel"; import { pluginSolid } from "@rsbuild/plugin-solid"; export default defineConfig({ plugins: [ pluginBabel({ include: /\.(?:jsx|tsx)$/ }), pluginSolid(), ], }); ``` ## Related - [Basics](/guide/manifest.md), [entry](/guide/entry.md). --- url: /guide/framework/svelte.md --- # Svelte Add `@rsbuild/plugin-svelte` to **plugins** in `addfox.config.ts` to enable Svelte (`.svelte` files). ## Setup **[object Object]** ```bash pnpm add svelte pnpm add @rsbuild/plugin-svelte -D ``` **[object Object]** ```bash npm install svelte npm install @rsbuild/plugin-svelte -D ``` **[object Object]** ```bash yarn add svelte yarn add @rsbuild/plugin-svelte -D ``` **[object Object]** ```bash bun add svelte bun add @rsbuild/plugin-svelte -D ``` ```ts // addfox.config.ts import { defineConfig } from "addfox"; import { pluginSvelte } from "@rsbuild/plugin-svelte"; export default defineConfig({ plugins: [pluginSvelte()], }); ``` ## Related - [Basics](/guide/manifest.md), [entry](/guide/entry.md). --- url: /guide/framework/vue.md --- # Vue Add `@addfox/rsbuild-plugin-vue` to **plugins** in `addfox.config.ts` to enable Vue 3 (SFC, Vue runtime). ## Setup **[object Object]** ```bash pnpm add vue pnpm add @addfox/rsbuild-plugin-vue -D ``` **[object Object]** ```bash npm install vue npm install @addfox/rsbuild-plugin-vue -D ``` **[object Object]** ```bash yarn add vue yarn add @addfox/rsbuild-plugin-vue -D ``` **[object Object]** ```bash bun add vue bun add @addfox/rsbuild-plugin-vue -D ``` ```ts // addfox.config.ts import { defineConfig } from "addfox"; import vue from "@addfox/rsbuild-plugin-vue"; export default defineConfig({ plugins: [vue()], }); ``` ## TSX/JSX Support `@addfox/rsbuild-plugin-vue` supports both Vue SFC (`.vue`) and TSX/JSX out of the box. No additional configuration needed. ### Manual Setup (if not using @addfox/rsbuild-plugin-vue) If you prefer to use the official Rsbuild plugins manually, you need to install additional dependencies: **[object Object]** ```bash pnpm add @rsbuild/plugin-babel @rsbuild/plugin-vue @rsbuild/plugin-vue-jsx -D ``` **[object Object]** ```bash npm install @rsbuild/plugin-babel @rsbuild/plugin-vue @rsbuild/plugin-vue-jsx -D ``` **[object Object]** ```bash yarn add @rsbuild/plugin-babel @rsbuild/plugin-vue @rsbuild/plugin-vue-jsx -D ``` **[object Object]** ```bash bun add @rsbuild/plugin-babel @rsbuild/plugin-vue @rsbuild/plugin-vue-jsx -D ``` ```ts // addfox.config.ts import { defineConfig } from "addfox"; import pluginBabel from "@rsbuild/plugin-babel"; import pluginVue from "@rsbuild/plugin-vue"; import pluginVueJsx from "@rsbuild/plugin-vue-jsx"; export default defineConfig({ plugins: [ pluginBabel({ include: /\.(?:jsx|tsx)$/ }), pluginVue(), pluginVueJsx(), ], }); ``` ## Related - [Basics](/guide/manifest.md), [entry](/guide/entry.md). --- url: /guide/hmr.md --- # Hot Reload (HMR) The `addfox dev` command provides a hot reload experience during development: after saving code, the project is automatically rebuilt and the browser extension is reloaded via WebSocket. ## How It Works ``` Source code changes ↓ Rsbuild Watch rebuilds ↓ Build complete → WebSocket notification ↓ Browser extension reloads ↓ Pages auto-refresh ``` ## Hot Reload Mechanisms by Entry ### Background / Service Worker Background scripts use **extension reload** mechanism: 1. Code changes → Rsbuild rebuilds 2. Build complete → WebSocket sends reload command 3. Calls `chrome.runtime.reload()` to reload entire extension 4. Service Worker restarts with new code :::warning State Loss Service Worker loses in-memory state after reload. Use `chrome.storage` API for persistent data. ::: ### Content Script Content Scripts use **re-injection** mechanism: 1. Code changes → Rsbuild rebuilds 2. Build complete → Extension reloads 3. Content Script auto-injects into matched pages 4. Open tabs can auto-refresh (see configuration) ```ts // addfox.config.ts export default defineConfig({ hotReload: { autoRefreshContentPage: true, // Auto-refresh page on content changes, default: true }, }); ``` :::tip Difference from Background Content Scripts run in the web page environment. After reload, they re-inject into matched pages without needing to manually refresh the extensions management page. ::: ### Popup / Options / Sidepanel Page entries use **Rsbuild HMR** mechanism: 1. Code changes → Rsbuild attempts HMR hot replacement 2. If HMR succeeds → Page updates locally, state preserved 3. If HMR fails → Automatically falls back to page refresh :::tip HMR Advantages - Faster update speed - Preserves component state (e.g., form inputs) - Smoother development experience ::: :::warning HTML template limitation Due to Rsbuild's mechanism, HTML template files (such as `popup/index.html`) do not support true HMR hot replacement.\ After changing HTML templates, Addfox will fall back to page refresh / extension reload behavior. ::: ## Firefox Special Handling Firefox dev mode uses the **web-ext** tool to manage extensions: - Extension reload is handled by `web-ext`, not Addfox's WebSocket - Firefox automatically opens and loads the extension on first start - Supports auto-reload (livereload) :::info When developing with Firefox, ensure Firefox browser is installed. Addfox automatically calls `web-ext` to handle Firefox extension loading and reloading. ::: ## Usage ```bash # Start dev server (HMR enabled by default) addfox dev # Specify target browser addfox dev -b chrome addfox dev -b firefox ``` ## First Start Flow After running `addfox dev`: 1. First build completes 2. Browser auto-starts based on configuration 3. Development extension is loaded 4. Extension popup/options pages auto-open (if `open` is configured) ## Configuration ### Hot Reload Port ```ts // addfox.config.ts export default defineConfig({ hotReload: { wsPort: 23333, // WebSocket port, default: 23333 autoRefreshContentPage: true, // Auto-refresh page on content changes, default: true }, }); ``` ## Next Steps - [browser config](/guide/launch.md) — Configure auto browser launch during dev - [monitor debugging](/guide/monitor.md) — Use error monitoring panel - [config/hot-reload](/config/hot-reload.md) — Complete hot reload configuration --- url: /guide/i18n.md --- # Internationalization (i18n) In an Addfox project, extension i18n assets (e.g. localized messages) live under the **`public`** directory. At build time, everything under `public` is copied into the output directory (e.g. `dist`), so structures like `_locales` are preserved in the built extension and loaded by Chrome according to [default\_locale](https://developer.chrome.com/docs/extensions/reference/manifest/default_locale) and the `chrome.i18n` API. A common setup is `public/_locales//messages.json` (e.g. `public/_locales/en/messages.json`), with `default_locale` set in the manifest. For message format, placeholders, and how to reference strings in manifest, CSS, and JS, see Chrome’s official docs: - [Internationalize your extension](https://developer.chrome.com/docs/extensions/develop/ui/internationalization) (full guide) - [chrome.i18n API](https://developer.chrome.com/docs/extensions/reference/i18n/) (API reference) --- url: /guide/icons.md --- # Extension icons In an Addfox project, extension icon assets (e.g. toolbar icon, store assets) live under the **`public`** directory. At build time, `public` is copied into the output directory (e.g. `dist`), so paths in the manifest should be relative to the extension root and point to files under `public` (e.g. `public/icons/icon16.png` → `icons/icon16.png` in the manifest). A common setup is an `icons` folder under `public` with PNGs at 16, 32, 48, and 128 px, referenced in the manifest via `icons` or `action.default_icon`. For required sizes, formats, and manifest fields, see Chrome’s official docs: - [Manifest - icons](https://developer.chrome.com/docs/extensions/reference/manifest/icons) --- url: /guide/index.md --- # Guide This is the Addfox guide entry page. Recommended reading order: - [Introduction](/guide/introduction.md) - [Installation](/guide/install.md) - [Entry System](/guide/entry.md) - [Framework Support](/guide/framework.md) - [Development & HMR](/guide/hmr.md) --- url: /guide/install.md --- # Installation ## Option 1: Scaffold a project (Recommended) Use the official scaffold to quickly create a project with pre-configured dev environment: **[object Object]** ```bash pnpm dlx addfox@latest create ``` **[object Object]** ```bash npx addfox@latest create ``` **[object Object]** ```bash yarn dlx addfox@latest create ``` **[object Object]** ```bash bunx addfox@latest create ``` ### Interactive Setup Steps (Latest) The scaffold will guide you through the following steps: 1. **Project name** — Enter your project directory name (default: `my-extension`) 2. **Framework** — Select your preferred framework: - Vanilla - Vue - React - Preact - Svelte - Solid 3. **Style engine** — Choose `none` / `tailwindcss` / `unocss` / `less` / `sass` 4. **Language** — Select TypeScript or JavaScript 5. **Package manager** — Choose pnpm, npm, yarn, or bun 6. **Entries** — Select which extension entries to include: - Background (Service Worker / Background script) - Content Script - Popup - Options Page - Side Panel - DevTools 7. **Test setup (optional)** — Choose whether to initialize: - Unit (rstest) - E2E (rstest + Playwright) 8. **Rsdoctor (optional)** — Choose whether to install `@rsdoctor/rspack-plugin` 9. **Install Skills** — Optionally install addfox skills to your project ### Scaffold Options You can also pass options directly (based on the current `create-addfox-app` CLI): ```bash addfox create [project-name] [options] ``` | Option | Description | | -------------------- | -------------------------------------------------------------------------------------------------- | | `[project-name]` | Project directory name (default: `my-extension`) | | `--framework ` | Set framework: `vanilla` \| `vue` \| `react` \| `preact` \| `svelte` \| `solid` | | `--language ` | Set language: `ts` \| `js` | | `--style ` | Set style engine: `none` \| `tailwindcss` \| `unocss` \| `less` \| `sass` (default: `tailwindcss`) | | `--unit` | Add unit test setup (rstest) | | `--e2e` | Add E2E test setup (rstest + Playwright) | | `--rsdoctor` | Install `@rsdoctor/rspack-plugin` (then use with `--report`) | | `--help` | Show help information | | `--version` | Show version number | > Note: `--style`, `--unit`, `--e2e`, and `--rsdoctor` are primarily used in non-interactive mode when `--framework` and `--language` are provided. **Examples:** ```bash # Create a React + TypeScript project pnpm dlx addfox@latest create my-extension --framework react --language ts # Create a Vue + JavaScript project with UnoCSS and unit tests npx addfox@latest create my-vue-ext --framework vue --language js --style unocss --unit # Create a Solid + TypeScript project with E2E and Rsdoctor pnpm dlx addfox@latest create my-solid-ext --framework solid --language ts --e2e --rsdoctor ``` After creation, the CLI will display the next steps: ```bash cd my-extension pnpm install pnpm dev ``` ## Option 2: Add to an existing project If you already have a project, you can manually integrate Addfox: ### 1. Install addfox Install **addfox** as a **dev dependency** (one package includes CLI and build): **[object Object]** ```bash pnpm add -D addfox ``` **[object Object]** ```bash npm install -D addfox ``` **[object Object]** ```bash yarn add -D addfox ``` **[object Object]** ```bash bun add -D addfox ``` ### 2. Add config file Create `addfox.config.ts` (or `addfox.config.js`) at the project root, and ensure you have `background`, `content`, `popup`, `options`, `sidepanel` entries under the root or under `appDir`. ### 3. Minimal config example ```ts // addfox.config.ts import { defineConfig } from "addfox"; import { pluginReact } from "@rsbuild/plugin-react"; // or vue from "@addfox/rsbuild-plugin-vue" export default defineConfig({ appDir: "src", outDir: "extension", manifest: { name: "My Extension", version: "1.0.0", manifest_version: 3, permissions: ["storage", "activeTab"], action: { default_popup: "popup/index.html" }, background: { service_worker: "background/index.js" }, content_scripts: [{ matches: [""], js: ["content/index.js"] }], }, plugins: [pluginReact()], }); ``` ### 4. Packages and imports - **Core**: `defineConfig`, types, entry discovery, manifest helpers are exported from `addfox`. Use: `import { defineConfig } from "addfox"`. - **Runtime**: For the `browser` API (Chrome/Firefox), install [webextension-polyfill](https://github.com/mozilla/webextension-polyfill) and use `import browser from "webextension-polyfill"`. **Content UI**: `@addfox/utils` provides `defineContentUI` / `mountContentUI` for injecting UI in content scripts; use `import { defineContentUI, mountContentUI } from "@addfox/utils"`. ### 5. Run commands - **Dev**: `addfox dev` or use your package manager's run script (e.g. `pnpm dev`, `npm run dev`, `yarn dev`, `bun run dev` if `"dev": "addfox dev"` in package.json). - **Build**: `addfox build`; output goes to `outputRoot/outDir/extension-` (default `.addfox/extension/extension-chromium`). Use `-b chrome|chromium|edge|brave|vivaldi|opera|santa|arc|yandex|browseros|custom|firefox` for target browser: **[object Object]** ```bash pnpm dev pnpm build ``` **[object Object]** ```bash npm run dev npm run build ``` **[object Object]** ```bash yarn dev yarn build ``` **[object Object]** ```bash bun run dev bun run build ``` Default is Chrome when not specified. --- url: /guide/launch.md --- # Browser Launch Addfox can automatically launch the browser and load the extension during development for improved efficiency. ## Quick Start Run the dev command: **[object Object]** ```bash pnpm dev ``` **[object Object]** ```bash npm run dev ``` **[object Object]** ```bash yarn dev ``` **[object Object]** ```bash bun run dev ``` On first start, the dev server will automatically: 1. Build the extension 2. Launch the browser 3. Load the development extension ## Using Scripts (Recommended) Configure scripts in `package.json` for cleaner browser launch commands: ```json { "scripts": { "dev": "addfox dev", "dev:chrome": "addfox dev -b chrome", "dev:edge": "addfox dev -b edge", "dev:brave": "addfox dev -b brave", "dev:firefox": "addfox dev -b firefox" } } ``` Then use directly: **[object Object]** ```bash # Chrome (default) pnpm dev # Other browsers pnpm dev:edge pnpm dev:firefox ``` **[object Object]** ```bash # Chrome (default) npm run dev # Other browsers npm run dev:edge npm run dev:firefox ``` **[object Object]** ```bash # Chrome (default) yarn dev # Other browsers yarn dev:edge yarn dev:firefox ``` **[object Object]** ```bash # Chrome (default) bun run dev # Other browsers bun run dev:edge bun run dev:firefox ``` ## Chromium-based Browsers Addfox natively supports the following Chromium-based browsers: | Browser | CLI Parameter | Description | | -------------- | -------------- | ------------------------------------------------- | | Google Chrome | `-b chrome` | Default browser | | Chromium | `-b chromium` | Open source version | | Microsoft Edge | `-b edge` | Windows built-in | | Brave | `-b brave` | Privacy browser | | Vivaldi | `-b vivaldi` | Customizable browser | | Opera | `-b opera` | Opera browser | | Santa | `-b santa` | Santa Browser | | Arc | `-b arc` | New concept browser | | Yandex | `-b yandex` | Yandex Browser | | BrowserOS | `-b browseros` | BrowserOS | | Custom | `-b custom` | Custom browser (requires `browser.custom` config) | ### Launch via CLI Directly If not using scripts, you can also launch directly via CLI: **[object Object]** ```bash # Chrome (default) pnpm addfox dev # Other browsers pnpm addfox dev -b edge pnpm addfox dev -b brave pnpm addfox dev -b vivaldi ``` **[object Object]** ```bash # Chrome (default) npx addfox dev # Other browsers npx addfox dev -b edge npx addfox dev -b brave npx addfox dev -b vivaldi ``` **[object Object]** ```bash # Chrome (default) yarn addfox dev # Other browsers yarn addfox dev -b edge yarn addfox dev -b brave yarn addfox dev -b vivaldi ``` **[object Object]** ```bash # Chrome (default) bunx addfox dev # Other browsers bunx addfox dev -b edge bunx addfox dev -b brave bunx addfox dev -b vivaldi ``` ### Chromium Browser Configuration If the browser is not in the default location, specify the `browser` object in config: ```ts // addfox.config.ts export default defineConfig({ browser: { chrome: { path: "/path/to/chrome" }, edge: { path: "/path/to/edge" }, brave: { path: "/path/to/brave" }, }, }); ``` Each browser entry supports: - `path` — browser executable path - `profile` — custom user-data (profile) directory; relative paths resolve from the project root (default: `/cache/browser-profile/-user-data`) - `keepBrowserProfile` — keep this browser's profile between launches, overriding the top-level `keepBrowserProfile` :::warning `browserPath` is deprecated. Migrate to `browser`: ```ts // Before (deprecated) export default defineConfig({ browserPath: { chrome: "/path/to/chrome" }, }); // After export default defineConfig({ browser: { chrome: { path: "/path/to/chrome" } }, }); ``` If both are set for the same browser, `browser` takes precedence. ::: #### Platform Examples **macOS:** ```ts export default defineConfig({ browser: { chrome: { path: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" }, edge: { path: "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge" }, }, }); ``` **Windows:** ```ts export default defineConfig({ browser: { chrome: { path: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" }, edge: { path: "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" }, }, }); ``` **Linux:** ```ts export default defineConfig({ browser: { chrome: { path: "/usr/bin/google-chrome" }, chromium: { path: "/usr/bin/chromium-browser" }, }, }); ``` ### Chromium User Data Cache By default, a new user data directory is used on each start. To preserve data (e.g., stay logged in), add to `package.json`: ```json { "scripts": { "dev:keep-profile": "addfox dev -b chrome --keep-browser-profile", "dev:edge:keep-profile": "addfox dev -b edge --keep-browser-profile" } } ``` Or run directly via CLI: **[object Object]** ```bash pnpm addfox dev --keep-browser-profile ``` **[object Object]** ```bash npx addfox dev --keep-browser-profile ``` **[object Object]** ```bash yarn addfox dev --keep-browser-profile ``` **[object Object]** ```bash bunx addfox dev --keep-browser-profile ``` Or enable in config: ```ts export default defineConfig({ keepBrowserProfile: true, }); ``` Or per browser (overrides the top-level `keepBrowserProfile`): ```ts export default defineConfig({ browser: { chrome: { keepBrowserProfile: true }, }, }); ``` User data is saved in `.addfox/cache/browser-profile/-user-data`. ## Firefox Firefox dev mode uses the **web-ext** tool to manage extension lifecycle. ### Launch Firefox Using the configured script: ```bash pnpm dev:firefox ``` Or run directly via CLI: **[object Object]** ```bash pnpm addfox dev -b firefox ``` **[object Object]** ```bash npx addfox dev -b firefox ``` **[object Object]** ```bash yarn addfox dev -b firefox ``` **[object Object]** ```bash bunx addfox dev -b firefox ``` ### Firefox Features - Extension reload is handled by `web-ext`, not Addfox's WebSocket - Automatically opens Firefox and loads the extension - Supports auto-reload on file changes ### Firefox Path Configuration ```ts export default defineConfig({ browser: { firefox: { path: "/Applications/Firefox.app/Contents/MacOS/firefox" }, }, }); ``` :::info Firefox profile is automatically managed by `web-ext`, no manual cache configuration needed. ::: ## Debugging Tips ### View Service Worker 1. Open `chrome://extensions/` 2. Find the extension under development 3. Click "Service Worker" to view background script console ### View Content Script 1. Right-click on the webpage → Inspect 2. Switch to Console panel 3. Select the extension's context ### Use Error Monitor Add debug scripts to `package.json`: ```json { "scripts": { "dev:debug": "addfox dev --debug", "dev:firefox:debug": "addfox dev -b firefox --debug" } } ``` Then run: ```bash pnpm dev:debug ``` Or enable directly via CLI: **[object Object]** ```bash pnpm addfox dev --debug ``` **[object Object]** ```bash npx addfox dev --debug ``` **[object Object]** ```bash yarn addfox dev --debug ``` **[object Object]** ```bash bunx addfox dev --debug ``` ## Related Configuration - [`browser`](/config/launch.md) - Browser configuration (path, profile, keepBrowserProfile) - [`keepBrowserProfile` / `buildCache`](/config/cache.md) - Cache configuration - [`hotReload`](/config/hot-reload.md) - Hot reload configuration - [`debug`](/config/debug.md) - Error monitoring configuration --- url: /guide/manifest.md --- # Manifest `manifest` declares the extension manifest (the content of the final `manifest.json` in the build output). It supports **inline object**, **object split by browser** (chromium/firefox), or **file paths**; it can also be **omitted** for auto-load from the source directory. ## Type and default - **Type**: `ManifestConfig | ManifestPathConfig | undefined` - **Default**: When omitted, the framework loads from `appDir` or `appDir/manifest/`: `manifest.json`, `manifest.chromium.json`, `manifest.firefox.json`. ## Configuration styles ### 1. Single object (Chrome / Firefox shared) Entry paths are computed from [entry](/guide/entry.md) and [output](/guide/output.md). > Entry output paths are computed by the framework from [entry](/guide/entry.md) and [output](/guide/output.md). Keep manifest fields semantically correct and let Addfox resolve generated paths. ### 2. Per-browser (chromium / firefox) Use `manifest: { chromium: { ... }, firefox: { ... } }`. ### 3. File paths (relative to appDir) Use `manifest: { chromium: "manifest/manifest.chromium.json", firefox: "manifest/manifest.firefox.json" }`. ### 4. Omit (auto-load) The framework looks for manifest files under `appDir`. ## Related - [entry](/guide/entry.md), [appDir](/guide/app-dir.md), [output](/guide/output.md). --- url: /guide/monitor.md --- # Error Monitor Addfox can inject runtime error monitoring in development. It aggregates multi-entry extension errors into terminal output and monitor UI for faster debugging. ## What you get - Automatic capture for `background`, `content`, `popup`, `options`, `sidepanel` and other entries - Structured terminal error blocks (entry, message, location, stack), optimized for AI-assisted troubleshooting - Monitor page at `/_addfox-monitor/` for visual inspection ## Enable Use in `addfox dev`: ```ts // addfox.config.ts export default defineConfig({ debug: true, }); ``` Or enable temporarily from CLI: ```bash addfox dev --debug ``` ## AI-friendly terminal output With monitor enabled, Addfox prints structured error context into terminal output.\ You can paste the block directly to AI tools with minimal extra explanation. Typical fields: - entry - message - location - stack ## Firefox note Firefox extension runtime/debug mechanics differ from Chromium (especially background lifecycle and debugging channels), so monitor behavior may not be identical across browsers. If behavior differs in Firefox, validate together with native Firefox debugging tools (`about:debugging`). ## Notes - Dev-only (`addfox dev`) - Removed from production build - Error data is local by default ## Related - [`debug`](/config/debug.md) - monitor switch --- url: /guide/output.md --- # Build Output Build artifacts are output to browser-specific subdirectories under `.addfox/extension/` (e.g., `extension-chromium` or `extension-firefox`). ## Default Output Structure ```tree .addfox/ ├── extension/ │ ├── extension-chromium/ # Chromium output │ │ ├── manifest.json │ │ ├── background/ │ │ │ └── index.js │ │ ├── content/ │ │ │ ├── index.js │ │ │ └── index.css │ │ ├── popup/ │ │ │ ├── index.html │ │ │ └── index.js │ │ ├── options/ │ │ │ ├── index.html │ │ │ └── index.js │ │ └── icons/ │ │ └── icon*.png │ └── extension-firefox/ # Firefox output └── cache/ # Build cache and dev browser profiles ``` ## Custom Output Directory Use `outDir` config to change the output directory name: ```ts // addfox.config.ts export default defineConfig({ outDir: "dist", // Output to .addfox/dist/ }); ``` ## Output Contents ### JavaScript Files - All entry scripts bundled by Rsbuild - Code transformation and minification (production mode) - Source maps (development mode) ### HTML Files - Generated by Rsbuild or custom templates - Entry scripts injected - **Auto-generated** pages (no custom `index.html`) include **`
`**; **``** matches **`manifest.name`**; the **tab icon** is set with **`<link rel="icon">`** from **`manifest.icons`**. Custom HTML templates must supply title and icon links yourself. ### CSS Files - Styles imported from entry scripts - Processed by PostCSS (if configured with Tailwind, etc.) ### Manifest - Final generated `manifest.json` - Contains all entry paths and configuration ### Static Assets - Files in `public/` copied as-is - Extension icons, i18n files, etc. ## Development vs Production ### Development Mode (`addfox dev`) - Output to `.addfox/extension/` - Includes source maps - Code not minified - Browser loads directly from this directory ### Production Mode (`addfox build`) - Also outputs to `.addfox/extension/` - Code minified and optimized - Can generate zip file (enabled by default) ## Zip Packaging After build, output is automatically packaged as zip: ```tree .addfox/ ├── extension/ # Build output └── extension.zip # Package file (for distribution) ``` Disable with `zip: false`: ```ts export default defineConfig({ zip: false, }); ``` ## Related Configuration - [`outDir`](/config/out-dir.md) - Output directory name - [`zip`](/config/zip.md) - Zip packaging configuration --- url: /guide/reload-manager.md --- # Reload Manager The Reload Manager is a built-in component during Addfox development, responsible for automatically reloading the extension after code changes. ## How It Works ``` Source code changes ↓ Rsbuild rebuilds ↓ WebSocket sends reload signal ↓ Reload Manager receives signal ↓ Disable extension → Enable extension ↓ Extension reloads ``` ## Why Reload Manager is Needed Browser extensions differ from regular web apps. After code changes: 1. **Extension needs reload** — For manifest changes to take effect 2. **Content Script needs re-injection** — To update scripts in pages 3. **Service Worker needs restart** — For background script updates The browser doesn't handle these automatically, so Addfox provides the Reload Manager to automate this process. ## Usage The Reload Manager is **automatically enabled** during `addfox dev`, no extra configuration needed. **[object Object]** ```bash pnpm dev ``` **[object Object]** ```bash npm run dev ``` **[object Object]** ```bash yarn dev ``` **[object Object]** ```bash bun run dev ``` ## Technical Implementation The Reload Manager is a **helper extension** loaded alongside the main extension: 1. Main extension — Your extension under development 2. Reload Manager extension — Listens to WebSocket and controls main extension The Reload Manager extension: - Auto-installs in dev mode - Receives notification via WebSocket after build completes - Sends `chrome.management` API commands to disable then enable main extension - Refreshes current tab when Content Script changes ## Configuration ### Hot Reload Port ```ts // addfox.config.ts export default defineConfig({ hotReload: { wsPort: 23333, // WebSocket port }, }); ``` ### Disable Page Refresh ```ts export default defineConfig({ hotReload: { autoRefreshContentPage: false, // Don't refresh page on content changes }, }); ``` ## Manual Reload If auto-reload has issues, you can manually reload: 1. Visit `chrome://extensions/` 2. Find the extension under development 3. Click the refresh icon Or use keyboard shortcuts: - macOS: `Cmd + R` (on extensions page) - Windows/Linux: `Ctrl + R` ## Related Configuration - [`hotReload`](/config/hot-reload.md) - Hot reload configuration - [guide/hmr](/guide/hmr.md) - Hot reload guide --- url: /guide/report.md --- # Analysis Report Addfox uses **Rsdoctor** to provide build analysis reports for bundle size, dependency structure, and build bottlenecks. ## Typical use cases - Unexpected bundle size growth - Slower builds after recent changes - Need to inspect chunk split and duplicated dependencies ## Enable From CLI: ```bash addfox build --report ``` Or via config: ```ts export default defineConfig({ report: true, }); ``` ## What you can inspect - Entry/chunk split details - Dependency size distribution and duplication - Build phase timing ## Recommended workflow 1. Generate a baseline report. 2. Generate another report after major changes. 3. Compare size and timing deltas before optimizing. ## Related - [Config: report](/config/report.md) - [Config: rsbuild](/config/rsbuild.md) - [Rsdoctor official docs](https://rsdoctor.rs/) --- url: /guide/rsbuild.md --- # Rsbuild config (rsbuild) `rsbuild` overrides or extends the Rsbuild configuration. It supports **object** (deep-merged with base) or **function** form for full control. ## Object form ```ts export default defineConfig({ rsbuild: { source: { define: { __APP_NAME__: JSON.stringify("my-ext") } }, resolve: { alias: { "@": "/src" } }, }, }); ``` ## Function form ```ts export default defineConfig({ rsbuild(base, helpers) { return helpers!.merge(base, { source: { define: { __ENV__: JSON.stringify(process.env.NODE_ENV) } }, }); }, }); ``` ## Related - [Framework support](/guide/framework/vue.md): plugins and rsbuild work together. --- url: /guide/skills.md --- # Skills It provides installable skills focused on browser extension development with Addfox. ## Install From your project root: ```bash # Install all skills from the repo npx skills add addfox/skills # Install only specific skills npx skills add addfox/skills --skill migrate-to-addfox npx skills add addfox/skills --skill addfox-best-practices npx skills add addfox/skills --skill extension-functions-best-practices npx skills add addfox/skills --skill addfox-debugging npx skills add addfox/skills --skill addfox-testing # List available skills first npx skills add addfox/skills --list ``` Or use the full GitHub URL: ```bash npx skills add https://github.com/addfox/skills ``` ## Available Skills | Skill | Description | | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **migrate-to-addfox** | Migrate existing projects to Addfox from WXT, Plasmo, Extension.js, or vanilla (no framework). | | **addfox-best-practices** | Best practices for Addfox extension projects: entry, config, manifest, permissions, cross-browser support, framework/style choices, and messaging. | | **extension-functions-best-practices** | Implementation guidance for extension feature domains (video/audio/image/download/AI/translation/password manager/web3, etc.), with recommended libraries and references. | | **addfox-debugging** | Troubleshoot build/runtime issues using terminal output, `.addfox/error.md`, `.addfox/meta.md`, and structured debugging workflow. | | **addfox-testing** | Testing guidance for Addfox projects: unit tests and E2E strategy, setup patterns, and framework-specific testing notes. | ## Repository Layout ```tree skills/ ├── migrate-to-addfox/ │ ├── SKILL.md │ └── references/ ├── addfox-best-practices/ │ ├── SKILL.md │ ├── reference.md │ └── rules/ ├── extension-functions-best-practices/ │ ├── SKILL.md │ └── reference.md ├── addfox-debugging/ │ ├── SKILL.md │ └── reference.md └── addfox-testing/ ├── SKILL.md └── reference.md ``` ## Notes - Skills are distributed via `skills CLI`, then copied into your project skill directory (for example `.cursor/skills/` or `.agents/skills/`). - You can install all skills first, then keep only what your team needs. --- url: /guide/style-integration/less.md --- # Less ## Install You need to install the `@rsbuild/plugin-less` plugin: **[object Object]** ```bash pnpm add -D @rsbuild/plugin-less less ``` **[object Object]** ```bash npm install -D @rsbuild/plugin-less less ``` **[object Object]** ```bash yarn add -D @rsbuild/plugin-less less ``` **[object Object]** ```bash bun add -D @rsbuild/plugin-less less ``` ## Configuration Add the plugin in `addfox.config.ts`: ```ts import { defineConfig } from "addfox"; import { pluginLess } from "@rsbuild/plugin-less"; export default defineConfig({ plugins: [pluginLess()], }); ``` ## Usage After installing and configuring, you can create and import `.less` files directly: ```less /* app/popup/index.less */ @brand: #2563eb; .btn { background: @brand; color: #fff; } ``` ```ts import "./index.less"; ``` ## Notes - For content scripts, prefer prefixed class names to avoid style leakage to host pages - The plugin automatically handles Less file compilation and imports --- url: /guide/style-integration/sass.md --- # Sass ## Install You need to install the `@rsbuild/plugin-sass` plugin: **[object Object]** ```bash pnpm add -D @rsbuild/plugin-sass sass ``` **[object Object]** ```bash npm install -D @rsbuild/plugin-sass sass ``` **[object Object]** ```bash yarn add -D @rsbuild/plugin-sass sass ``` **[object Object]** ```bash bun add -D @rsbuild/plugin-sass sass ``` ## Configuration Add the plugin in `addfox.config.ts`: ```ts import { defineConfig } from "addfox"; import { pluginSass } from "@rsbuild/plugin-sass"; export default defineConfig({ plugins: [pluginSass()], }); ``` ## Usage After installing and configuring, you can create and import `.scss` files directly: ```scss /* app/popup/index.scss */ $brand: #7c3aed; .card { border: 1px solid $brand; color: $brand; } ``` ```ts import "./index.scss"; ``` ## Notes - If needed, use `*.module.scss` for CSS Modules style isolation - The plugin automatically handles Sass file compilation and imports --- url: /guide/style-integration/tailwindcss.md --- # Tailwind CSS ## Install **[object Object]** ```bash pnpm add -D tailwindcss @tailwindcss/postcss postcss ``` **[object Object]** ```bash npm install -D tailwindcss @tailwindcss/postcss postcss ``` **[object Object]** ```bash yarn add -D tailwindcss @tailwindcss/postcss postcss ``` **[object Object]** ```bash bun add -D tailwindcss @tailwindcss/postcss postcss ``` ## Configure Create `postcss.config.mjs` in project root: ```js export default { plugins: { "@tailwindcss/postcss": {}, }, }; ``` ## Usage Import Tailwind in your style entry: ```css /* app/popup/index.css */ @import "tailwindcss"; ``` Then import that CSS in your entry script: ```ts import "./index.css"; ``` Now you can use Tailwind utility classes directly in components. --- url: /guide/style-integration/unocss.md --- # UnoCSS ## Install **[object Object]** ```bash pnpm add -D unocss @unocss/postcss ``` **[object Object]** ```bash npm install -D unocss @unocss/postcss ``` **[object Object]** ```bash yarn add -D unocss @unocss/postcss ``` **[object Object]** ```bash bun add -D unocss @unocss/postcss ``` ## Configure Create `postcss.config.mjs`: ```js export default { plugins: { "@unocss/postcss": {}, }, }; ``` Optional: create `uno.config.ts` for presets and custom rules. ## Usage Import UnoCSS in your style entry: ```css /* app/popup/index.css */ @unocss; ``` And import CSS in your entry script: ```ts import "./index.css"; ``` You can then use UnoCSS atomic classes in components. --- url: /guide/testing.md --- # Testing Addfox has built-in support for **Rstest** and recommends running tests through `addfox test`. ## Check dependencies first Before running tests, make sure required dependencies are installed: ```bash pnpm add -D @rstest/core ``` For browser E2E tests, also install: ```bash pnpm add -D @rstest/browser playwright ``` ## Unified command Use: ```bash addfox test ``` This runs tests through the Addfox test workflow instead of manually wiring low-level commands. ## Unit Tests Best for: - utility functions - message handlers - storage/state logic Common file naming: - `*.test.ts` - `*.spec.ts` ## E2E Tests Best for: - extension loading checks - popup/content/background integration flows - user-facing regression paths Run E2E as part of CI or release validation. ## Test configuration You can configure tests with the [`test`](/config/test.md) field in `addfox.config` — no separate config file needed: ```ts // addfox.config.ts import { defineConfig } from "addfox"; export default defineConfig({ test: { include: ["**/*.test.ts", "**/*.spec.ts"], }, }); ``` A standalone `rstest.config.ts` is also supported: ```ts // rstest.config.ts import { defineConfig } from "@rstest/core"; export default defineConfig({ test: { include: ["**/*.test.ts", "**/*.spec.ts"], }, }); ``` When both exist, `rstest.config.*` takes precedence and the `test` field is ignored (a warning is printed). See [test](/config/test.md) for details. ## Suggested script ```json { "scripts": { "test": "addfox test" } } ``` ## References - [Rstest official docs](https://rstest.dev/) - [Rstest browser testing guide](https://rstest.dev/guide/browser-testing) --- url: /guide/typescript.md --- # TypeScript Addfox is built on top of Rsbuild and provides TypeScript support out of the box. You can use `.ts` / `.tsx` directly without adding an extra compile pipeline. ## Built-in support - **Out-of-the-box transpilation**: `.ts` and `.tsx` are handled automatically. - **Separated type checking**: build focuses on transpile and bundle; use `tsc --noEmit` or IDE diagnostics for type checks. - **Works across all entries**: TypeScript can be used directly in `background`, `content`, `popup`, and `options`. ## Path aliases (reads tsconfig directly) Addfox directly reads `compilerOptions.baseUrl` and `compilerOptions.paths` from `tsconfig.json` (or `tsconfig.base.json`) for module resolution.\ In practice, common alias setup does not need to be duplicated in Addfox config. ```json { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["app/*"], "@shared/*": ["shared/*"] } } } ``` Then import with aliases directly: ```ts import { getEnv } from "@/shared/env"; import { logger } from "@shared/logger"; ``` ## Recommendation - Keep alias definitions centralized in root `tsconfig`. - Add `tsc --noEmit` in CI to catch type issues earlier. ## References - [Rsbuild TypeScript Guide](https://rsbuild.rs/guide/basic/typescript) --- url: /guide/zip.md --- # Zip Packaging After build, Addfox automatically packages the output directory into a zip file for distribution. ## Default Behavior **[object Object]** ```bash pnpm build ``` **[object Object]** ```bash npm run build ``` **[object Object]** ```bash yarn build ``` **[object Object]** ```bash bun run build ``` After build completes: ```tree .addfox/ ├── extension/ # Build output └── extension.zip # Package file ``` ## Configuration ### Disable Packaging ```ts // addfox.config.ts export default defineConfig({ zip: false, }); ``` ### Enable Packaging (Default) ```ts // addfox.config.ts export default defineConfig({ zip: true, }); ``` Or omit configuration (uses default). ## Package Contents The zip file contains all build output: - `manifest.json` — Extension manifest - `background/` — Background scripts - `content/` — Content scripts - `popup/` — Popup page - `options/` — Options page - Other entries - Static assets from `public/` (icons, i18n files, etc.) ## Usage Packaged zip files can be used for: ### Chrome Web Store Submission 1. Visit [Chrome Web Store Developer Dashboard](https://chrome.google.com/webstore/devconsole/) 2. Create or select a project 3. Upload `extension.zip` ### Firefox Add-ons Submission 1. Visit [Firefox Add-ons Developer Hub](https://addons.mozilla.org/developers/) 2. Submit new add-on 3. Upload `extension.zip` ### Internal Distribution - Share via email/cloud storage - Internal test deployment ## Output Path Package file output path: ``` {outputRoot}/{outDir}.zip ``` Default: `.addfox/extension.zip` After modifying `outDir`: ```ts export default defineConfig({ outDir: "dist", }); // Output: .addfox/dist.zip ``` ## Related Configuration - [`zip`](/config/zip.md) - Zip packaging toggle - [`outDir`](/config/out-dir.md) - Output directory configuration --- url: /index.md --- # Build Better Extensionsfor Developers and AI Accelerate your browser extension development. Built on Rsbuild — fast, simple, and free. [Get Started](/guide/install) npx addfox@latest create [Star us](https://github.com/addfox/addfox) bash $ addfox dev [Addfox] Addfox 0.2.7 with Rsbuild 2.2.1 [Rsbuild] start build started...[Rsbuild] ready built in 0.62 s [Addfox] Press r + enter to reload, o + enter to reopen browser (Ctrl-C to quit) URLs├── Dev server -> http://localhost:3000└── WebSocket -> ws://127.0.0.1:23333 [Addfox] ● chrome started, extensions loaded. 300ms[Addfox] ● Extension size: 2.21 MB 🔒chrome-extension://.../welcome.html Addfox Popup Page Options Manage Extension ## Addfox + React Your extension is ready. Happy building! ## Ultimate Experience Start your business, instant startup and optimized builds ### Dev Server Startup addfoxv0.2.9 · Rsbuild 2.2.1 1.56s WXTv0.21.4 · Vite 8.1.2 1.99s extensionjsv4.1.5 · Rspack 2.2.1 2.86s plasmov0.90.5 · Parcel 2.9.3 2.91s Minimum time to start dev server (lower is better) ### Build Time addfoxv0.2.9 · Rsbuild 2.2.1 1.04s extensionjsv4.1.5 · Rspack 2.2.1 1.61s WXTv0.21.4 · Vite 8.1.2 1.64s plasmov0.90.5 · Parcel 2.9.3 2.54s Minimum time to build extension (lower is better) ### Build Output Size WXTv0.21.4 · Vite 8.1.2 810KB addfoxv0.2.9 · Rsbuild 2.2.1 837KB plasmov0.90.5 · Parcel 2.9.3 1.36MB extensionjsv4.1.5 · Rspack 2.2.1 1.91MB Production build output size (lower is better) Benchmarked on identical projects. Results may vary based on project complexity. [benchmark详情 →](https://github.com/addfox/benchmark) ## For developers Hot reload, multi-browser support, and minimal config to help you ship extensions faster. ### Fast HMR Dedicated Reloader controls extension updates — not only fast, but both content_script and background achieve ultra-fast HMR. ReloaderExtensionAddfoxRsbuild ### Full browser support Support for mainstream Chromium-based browsers and Firefox. Auto-detects browser default install path and launches without configuration. ![Chrome](https://cdn.jsdelivr.net/npm/@browser-logos/chrome/chrome.svg)![Firefox](https://cdn.jsdelivr.net/npm/@browser-logos/firefox/firefox.svg)![Opera](https://cdn.jsdelivr.net/npm/@browser-logos/opera/opera.svg)![Brave](https://cdn.jsdelivr.net/npm/@browser-logos/brave/brave.svg) ![Vivaldi](https://cdn.jsdelivr.net/npm/@browser-logos/vivaldi/vivaldi.svg)![Arc](https://cdn.simpleicons.org/arc)![Yandex](https://cdn.jsdelivr.net/npm/@browser-logos/yandex/yandex_48x48.png)![Chromium](https://cdn.jsdelivr.net/npm/@browser-logos/chromium/chromium.svg) ### Framework agnostic Vanilla, Vue, React, Preact, Svelte, Solid, or React+UnoCSS — use what you like. ![Vue](https://cdn.jsdelivr.net/gh/devicons/devicon/icons/vuejs/vuejs-original.svg)![React](https://cdn.jsdelivr.net/gh/devicons/devicon/icons/react/react-original.svg)![Preact](https://cdn.simpleicons.org/preact/673AB8)![Svelte](https://cdn.jsdelivr.net/gh/devicons/devicon/icons/svelte/svelte-original.svg)![Solid](data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1.08em' height='1em' viewBox='256 239 256 239'%3E%3Cdefs%3E%3ClinearGradient id='SVGWXvcOcqs' x1='27.5' x2='152' y1='3' y2='63.5' gradientTransform='translate(249.56 233.12)scale(1.61006)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='.1' stop-color='%2376b3e1'/%3E%3Cstop offset='.3' stop-color='%23dcf2fd'/%3E%3Cstop offset='1' stop-color='%2376b3e1'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGtXBLjbrF' x1='95.8' x2='74' y1='32.6' y2='105.2' gradientTransform='translate(249.56 233.12)scale(1.61006)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%2376b3e1'/%3E%3Cstop offset='.5' stop-color='%234377bb'/%3E%3Cstop offset='1' stop-color='%231f3b77'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVG44i0wdWH' x1='18.4' x2='144.3' y1='64.2' y2='149.8' gradientTransform='translate(249.56 233.12)scale(1.61006)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23315aa9'/%3E%3Cstop offset='.5' stop-color='%23518ac8'/%3E%3Cstop offset='1' stop-color='%23315aa9'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGxEBrkbOG' x1='75.2' x2='24.4' y1='74.5' y2='260.8' gradientTransform='translate(249.56 233.12)scale(1.61006)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%234377bb'/%3E%3Cstop offset='.5' stop-color='%231a336b'/%3E%3Cstop offset='1' stop-color='%231a336b'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cpath fill='%2376b3e1' d='M512 289.472s-85.333-62.791-151.347-48.301l-4.829 1.61c-9.66 3.221-17.711 8.05-22.542 14.491l-3.219 4.829l-24.152 41.862l41.863 8.051c17.71 11.27 40.251 16.101 61.182 11.27l74.063 14.491z'/%3E%3Cpath fill='url(%23SVGWXvcOcqs)' d='M512 289.472s-85.333-62.791-151.347-48.301l-4.829 1.61c-9.66 3.221-17.711 8.05-22.542 14.491l-3.219 4.829l-24.152 41.862l41.863 8.051c17.71 11.27 40.251 16.101 61.182 11.27l74.063 14.491z' opacity='.3'/%3E%3Cpath fill='%23518ac8' d='m333.282 289.472l-6.439 1.611c-27.371 8.05-35.421 33.811-20.932 56.352c16.101 20.931 49.913 32.201 77.284 24.151l99.824-33.811s-85.334-62.792-149.737-48.303'/%3E%3Cpath fill='url(%23SVGtXBLjbrF)' d='m333.282 289.472l-6.439 1.611c-27.371 8.05-35.421 33.811-20.932 56.352c16.101 20.931 49.913 32.201 77.284 24.151l99.824-33.811s-85.334-62.792-149.737-48.303' opacity='.3'/%3E%3Cpath fill='url(%23SVG44i0wdWH)' d='M465.308 361.925c-18.439-23.036-49.008-32.588-77.283-24.15l-99.823 32.201L256 426.328l180.327 30.592l32.201-57.963c6.441-11.271 4.831-24.15-3.22-37.032'/%3E%3Cpath fill='url(%23SVGxEBrkbOG)' d='M433.106 418.277c-18.439-23.036-49.006-32.588-77.282-24.15L256 426.328s85.333 64.402 151.346 48.303l4.83-1.612c27.371-8.049 37.031-33.81 20.93-54.742'/%3E%3C/svg%3E) ![TypeScript](https://cdn.jsdelivr.net/gh/devicons/devicon/icons/typescript/typescript-original.svg)![JavaScript](https://cdn.jsdelivr.net/gh/devicons/devicon/icons/javascript/javascript-original.svg) ### Content UI support Built-in createContentUI method for easy integration of Iframe, ShadowDom, and native content. https://example.com/article Translate Original Selected text... Translation Translated result CopyEN → ZH ### Rstack Ecosystem Built-in support for Rsdoctor and Rstest to quickly complete bundle analysis, unit and e2e testing. ### Zip on build Build automatically outputs an extension zip package for easy installation and distribution. .json.js.css.html.png.zip ## For AI Structured meta, terminal error output, and Skills — so AI can understand and work with your extension. ### llms.txt and markdown metadata support Provides clear extension info, error details, and prompts to help AI agents develop. AIllms.txtMmeta.md!error.mdAI Agent ### AI-friendly error monitor Enable terminal error output with --debug. Capture all extension errors without browser DevTools, so you can Ask AI directly in any editor. bash $ addfox dev --debug error --- BEGIN AI PROMPT --- You are a frontend and browser extension development expert, proficient with the Addfox framework. This is an Addfox-based browser extension runtime error (MV3). Before proposing fixes: 1) Read `.addfox/llms.txt` first. 2) Apply the `addfox-debugging` skills to analyze this report (and `.addfox/error.md` / `.addfox/meta.md` if available). --- END AI PROMPT --- --- Addfox extension error --- bundler: rsbuild front-end-framework: React entry: content type: error time: 2026/3/21 20:58:51 message: fff is not defined location: chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:2966:1 stack: ReferenceError: fff is not defined at ./app/content/index.ts (chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:1635:45) at __webpack_require__ (chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:2962:29) at chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:4125:27 at chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:4126:3 --------------------------- --- BEGIN AI PROMPT --- You are a frontend and browser extension development expert, proficient with the Addfox framework. This is an Addfox-based browser extension runtime error (MV3). Before proposing fixes: 1) Read `.addfox/llms.txt` first. 2) Apply the `addfox-debugging` skills to analyze this report (and `.addfox/error.md` / `.addfox/meta.md` if available). --- END AI PROMPT --- --- Addfox extension error --- bundler: rsbuild front-end-framework: React entry: content type: error time: 2026/3/21 20:58:51 message: fff is not defined location: chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:2966:1 stack: ReferenceError: fff is not defined at ./app/content/index.ts (chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:1635:45) at __webpack_require__ (chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:2962:29) at chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:4125:27 at chrome-extension://fbnnalickbkocmeokpogajmocmcejemg/content/index.js:4126:3 --------------------------- ### Skills support Extensible Skills to support Agents and automation. migrate-to-addfox addfox-best-practices extension-functions-best-practices addfox-debugging addfox-testing migrate-to-addfox addfox-best-practices extension-functions-best-practices addfox-debugging addfox-testing migrate-to-addfox addfox-best-practices extension-functions-best-practices addfox-debugging addfox-testing migrate-to-addfox addfox-best-practices extension-functions-best-practices addfox-debugging addfox-testing addfox-debugging addfox-testing addfox-best-practices migrate-to-addfox extension-functions-best-practices addfox-debugging addfox-testing addfox-best-practices migrate-to-addfox extension-functions-best-practices addfox-debugging addfox-testing addfox-best-practices migrate-to-addfox extension-functions-best-practices addfox-debugging addfox-testing addfox-best-practices migrate-to-addfox extension-functions-best-practices ## What Creator Says " ![Gomi](/creator.jpg) Gomi Creator of [VideoRoll](https://videoroll.app) and Addfox > I'm Gomi, the creator of [Video Roll](https://videoroll.app), a browser extension featured on both Chrome Web Store and Edge with over 35K users. Despite its success, I still felt unsatisfied with the extension development experience. After trying Parcel, Vite, and other tools, I decided to tackle the pain points myself. Even with excellent solutions like WXT and Plasmo available, I didn't want to reinvent the wheel. The speed of Rsbuild and the AI-friendly development paradigm fascinated me, so I created Addfox. ## Frequently Asked Questions Quick answers to common questions about Addfox Is Addfox open source? Yes, Addfox is fully open source under the MIT license. You can view the source code on GitHub, contribute to the project, or fork it for your own needs. Does it support Safari? Currently, Addfox focuses on Chromium-based browsers (Chrome, Edge, Arc, Brave, etc.) and Firefox. Safari support is not available at this time due to its different extension API and packaging requirements. Does it support mainstream frontend frameworks? Absolutely! Addfox is framework-agnostic and works with React, Vue, Preact, Svelte, Solid, and vanilla JavaScript/TypeScript. You can use your preferred framework with minimal configuration. What are the differences compared to WXT/Plasmo/Extension.js? WXT, Plasmo, and Extension.js are all excellent choices that have greatly advanced the extension development ecosystem. WXT brings the power of Vite and a well-designed plugin system; Plasmo offers comprehensive cloud integration and a polished developer experience; Extension.js provides simplicity and ease of use. Addfox takes a different approach: built on Rsbuild for exceptional build speed, designed specifically for AI-assisted development with structured metadata and terminal error output, and offering maximum flexibility through minimal conventions—you can organize your code however you prefer while still getting out-of-the-box HMR and multi-browser support. Resources [GitHub](https://github.com/addfox/addfox) Friendly links [WXT](https://wxt.dev)[Plasmo](https://www.plasmo.com)[Extension.js](https://extension.js.org)[crxsoso](https://www.crxsoso.com) Tools[![Featured on AgentWork.Tools](https://agentwork.tools/badge/badge_dark.svg)](https://agentwork.tools) --- url: /resources/cli.md --- # @addfox/cli The `addfox` CLI entry point: it parses arguments, runs the config → entry → Rsbuild pipeline, wraps terminal output, and drives Rsbuild for `dev` / `build`. You can use it programmatically to build custom extension tooling on top of Addfox. ## Installation ```bash npm install @addfox/cli ``` ## What it does - Parses `addfox dev | build | test [options]` from `process.argv` - Loads and resolves `addfox.config.ts` - Discovers or validates extension entries - Builds the final Rsbuild configuration - Starts the dev server or runs a production build - Optionally launches the browser with the extension loaded ## Commands | Command | Description | | ------- | ---------------------------------------------- | | `dev` | Start development mode with hot reload support | | `build` | Build production output | | `test` | Run tests (forwards args to rstest) | > `addfox test` reads its config from `rstest.config.*` or the [`test`](/config/test.md) field in `addfox.config`; when both exist, `rstest.config.*` takes precedence. ## Common Options | Option | Description | | --------------------------- | -------------------------------------------------- | | `-b, --browser <browser>` | Target/launch browser | | `--port <port>` | Rsbuild dev server port (dev only, default `3000`) | | `--no-open` | Do not auto-open browser | | `--keep-browser-profile` | Keep browser profile between launches | | `--no-keep-browser-profile` | Use a fresh browser profile for this run | | `-r, --report` | Enable Rsdoctor build report | | `--debug` | Enable debug mode | > `-c, --cache` and `--no-cache` are deprecated aliases of `--keep-browser-profile` / `--no-keep-browser-profile`; they still work but print a deprecation warning. ## Dev server and HMR `addfox dev` uses **Rsbuild dev server** with `writeToDisk: true` so the extension can be loaded from `.addfox/<outDir>`. The `@addfox/rsbuild-plugin-extension-hmr` plugin handles full extension reload when build output changes, so the extension works from both disk and `chrome-extension://` origins. ## Programmatic usage Most users will call the CLI binary. If you need to embed the CLI in another tool, import from `@addfox/cli` and call the same pipeline functions used by the binary. --- url: /resources/create-addfox-app.md --- # create-addfox-app Interactive scaffolder that generates a new Addfox-based browser extension project from a few prompts. ## Usage Use it as an `addfox` subcommand: ```bash addfox create [project-name] # or npx addfox@latest create [project-name] ``` Or use the legacy package name: ```bash npx create-addfox-app [project-name] # or pnpm create addfox-app [project-name] ``` ## Flow 1. Select a framework: `vanilla`, `vue`, `react`, `preact`, `svelte`, or `solid` 2. Choose language: **TypeScript** or **JavaScript** 3. Choose package manager: `pnpm`, `npm`, `yarn`, or `bun` 4. Select entries to include (multi-select) 5. Decide whether to install Addfox skills The project is written to the current directory or to the directory you specify. ## Output The generated project includes: - `addfox.config.ts` (or `.js`) with minimal manifest and entry discovery - A scaffold matching your selected framework and entries - No hard-coded entry paths in the manifest by default ## Templates Templates ship inside the package under `templates/` (e.g. `template-vanilla-ts`, `template-react-ts`). The chosen folder is copied into your new project without remote downloads. The template's `addfox.config` is preserved; the CLI only merges Rsbuild Less/Sass plugins when those style engines are selected. --- url: /resources/index.md --- # Resources Addfox is published as a collection of packages. While most users only need the main `addfox` CLI, several packages can also be used independently in your own tooling or workflows. This section documents the standalone packages: | Package | Purpose | | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | | [`@addfox/launcher`](/resources/launcher.md) | Launch Chromium/Gecko browsers with extensions loaded, with file watching and remote debugging support. | | [`@addfox/cli`](/resources/cli.md) | The `addfox` CLI parser, pipeline, and Rsbuild runner. Use it programmatically to build custom extension tooling. | | [`create-addfox-app`](/resources/create-addfox-app.md) | Scaffold a new Addfox extension project interactively. | Choose a package above to learn how to install and use it. --- url: /resources/launcher.md --- # @addfox/launcher Browser launcher for extension development. Supports the Chromium family (Chrome, Edge, Brave, etc.) and the Gecko family (Firefox, Zen, LibreWolf, etc.). ## Installation ```bash npm install @addfox/launcher ``` ## CLI Usage ```bash npx addfox-launcher <browser> [url] [options] ``` ### Supported Browsers - **Chromium**: `chrome`, `chromium`, `edge`, `brave`, `vivaldi`, `opera`, `santa`, `arc`, `yandex`, `browseros`, `custom` - **Gecko**: `firefox`, `zen`, `librewolf`, `waterfox`, `floorp` ### Options | Option | Description | | -------------------------------- | ---------------------------------------------------- | | `--binary <path>` | Path to browser binary | | `--extension <path>` | Extension directory to load (repeatable) | | `--profile <path>` | User profile / data directory | | `--watch <path>` | Watch directory for changes and restart (repeatable) | | `--devtools` | Open DevTools automatically | | `--remote-debugging-port <port>` | Enable remote debugging | | `--args "<flags>"` | Extra browser arguments | | `--verbose, -v` | Verbose logging | | `--help, -h` | Show help | ### Examples ```bash # Launch Chrome with an extension npx addfox-launcher chrome --extension ./dist # Launch Firefox with extension and file watching npx addfox-launcher firefox --extension ./dist --watch ./src --verbose ``` ## Programmatic API ```ts import { launchBrowser } from "@addfox/launcher"; const browser = await launchBrowser({ target: "chrome", extensionPaths: ["./dist"], devtools: true, }); // Later await browser.exit(); ``` ### Subpath Exports ```ts // Chromium-specific APIs import { launchChromium } from "@addfox/launcher/chromium"; // Gecko-specific APIs import { launchGecko, createGeckoProfile, reinstallTemporaryAddonViaRDP } from "@addfox/launcher/gecko"; ```