How to Build the Extension for Firefox Versus Chrome Using the Vite React Boilerplate

The boilerplate uses a single source tree controlled by the CLI_CEB_FIREFOX environment flag; set it to false (default) for Chrome or true for Firefox using the npm scripts pnpm dev/pnpm build for Chrome and pnpm dev:firefox/pnpm build:firefox for Firefox.

The jonghakseo/chrome-extension-boilerplate-react-vite repository provides a modern development environment for browser extensions using React and Vite. When you need to build the extension for Firefox versus Chrome, the project avoids code duplication by using environment-driven configuration to target each browser from the same codebase.

The Environment Flag That Controls the Build

The build system relies on the CLI_CEB_FIREFOX environment variable to toggle between Chrome and Firefox targets. When this flag is false or undefined, the build pipeline generates a Manifest V3 bundle optimized for Chrome. When set to true, the configuration activates Firefox-specific polyfills and manifest adjustments.

The flag is managed by the helper script located at bash-scripts/set_global_env.sh. This script validates the input and writes the appropriate values to the .env file, ensuring that subsequent Vite processes inherit the correct configuration consistently.

Development Workflow

For active development with hot module replacement, the boilerplate provides distinct npm scripts that automatically configure the environment before starting the Vite dev server.

To develop for Chrome:

pnpm dev

This command sets CLI_CEB_DEV=true and keeps CLI_CEB_FIREFOX=false, starting the watch mode with Chrome-compatible output in the dist folder.

To develop for Firefox:

pnpm dev:firefox

This script invokes pnpm set-global-env to write CLI_CEB_FIREFOX=true to the environment before launching Vite. The build pipeline then generates a Firefox-compatible bundle in the same dist directory, allowing you to test in Firefox while maintaining the same source files.

Production Builds

When preparing the extension for distribution, use the production build commands defined in package.json.

For Chrome production builds:

pnpm build

This generates a production-optimized bundle in the dist folder containing a Chrome Manifest V3 manifest.json and all associated assets.

For Firefox production builds:

pnpm build:firefox

This command first sets CLI_CEB_FIREFOX=true via the environment helper script, then executes the production build. The output in dist contains a Firefox-compatible manifest and any necessary polyfills, ready for submission to the Firefox Add-ons store.

How the Manifest Adapts to Each Browser

The manifest generation logic resides in chrome-extension/manifest.ts. This TypeScript file imports the IS_FIREFOX constant from packages/env/lib/const.ts, which reflects the value of process.env.CLI_CEB_FIREFOX.

Based on the IS_FIREFOX boolean, the manifest generator conditionally includes browser-specific fields. For example, Firefox may require different background script configurations or specific permissions that differ from Chrome's Manifest V3 implementation. This approach keeps the manifest logic DRY while allowing precise control over each browser's requirements.

Loading the Built Extension

After building, you must load the extension differently in each browser.

Chrome:

  1. Navigate to chrome://extensions
  2. Enable Developer mode using the toggle in the top-right corner
  3. Click Load unpacked
  4. Select the dist folder from your project directory

Firefox:

  1. Navigate to about:debugging#/runtime/this-firefox
  2. Click Load Temporary Add-on...
  3. Select the manifest.json file inside the dist folder

These steps are documented in the repository's README under the respective installation sections for Chrome and Firefox.

Summary

  • The boilerplate uses a single codebase for both browsers, controlled by the CLI_CEB_FIREFOX environment flag.
  • Use pnpm dev for Chrome development and pnpm dev:firefox for Firefox development.
  • Use pnpm build for Chrome production and pnpm build:firefox for Firefox production.
  • The bash-scripts/set_global_env.sh script manages environment variables by writing to .env.
  • Manifest adaptation occurs in chrome-extension/manifest.ts based on the IS_FIREFOX constant from packages/env/lib/const.ts.
  • Load the extension in Chrome via chrome://extensions and in Firefox via about:debugging.

Frequently Asked Questions

How do I switch between Chrome and Firefox builds without manually editing files?

The npm scripts pnpm dev:firefox and pnpm build:firefox automatically invoke pnpm set-global-env, which runs bash-scripts/set_global_env.sh to write the correct CLI_CEB_FIREFOX value to your .env file. You do not need to manually edit environment variables.

Can I build for both browsers simultaneously?

The boilerplate is designed to build for one target at a time. The dist folder is shared between targets, so running pnpm build after pnpm build:firefox will overwrite the Firefox bundle with the Chrome version. To maintain both builds, you should copy the dist folder to a separate location between builds or modify the output directory in your Vite configuration.

What specific manifest differences does the boilerplate handle automatically?

The chrome-extension/manifest.ts file uses the IS_FIREFOX boolean (from packages/env/lib/const.ts) to conditionally include browser-specific fields. This typically includes differences in background script configuration, specific permission keys, and Firefox-specific manifest keys that differ from Chrome's Manifest V3 implementation. The exact differences depend on the current state of the repository's manifest generator.

Where does the built extension output go?

Regardless of whether you target Chrome or Firefox, the build output always goes to the dist folder at the project root. The contents of this folder will contain the appropriate manifest.json and assets for whichever browser you last built for. This consistent output location simplifies the loading process in both chrome://extensions and about:debugging.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →