Skip to content

Browser Support

WebExtend is designed to help you build cross-browser extensions with ease. This guide covers everything you need to know about browser compatibility, configuration, and development workflow.

Browser Targets

WebExtend supports the following extension targets:

TargetDescriptionStatus
chrome-mv3Chrome Manifest V3Default, stable
firefox-mv2Firefox Manifest V2Recommended for Firefox
firefox-mv3Firefox Manifest V3Experimental, dev mode not supported
safari-mv3Safari Manifest V3Experimental
edge-mv3Edge Manifest V3Stable
opera-mv3Opera Manifest V3Stable

When using chrome-mv3, the built extension is compatible with most Chromium-based browsers, including:

  • Google Chrome
  • Microsoft Edge
  • Brave
  • Opera
  • Other Chromium-based browsers

To specify a target browser, use the --target or -t flag with web-extend commands:

shell
# Development mode
web-extend dev -t firefox-mv2

# Production build
web-extend build -t firefox-mv2

# Preview build
web-extend preview -t firefox-mv2

# Create zip package
web-extend zip -t firefox-mv2

Environment Variables

WebExtend injects the import.meta.env.WEB_EXTEND_TARGET environment variable during build, which helps handle browser-specific code:

src/background.js
js
const target = import.meta.env.WEB_EXTEND_TARGET || "";

// Chrome-specific code
if (target.includes("chrome")) {
  chrome.sidePanel
    .setPanelBehavior({ openPanelOnActionClick: true })
    .catch((error) => console.error(error));
}

// Firefox-specific code
if (target.includes("firefox")) {
  browser.sidebarAction
    .setPanel({ url: "sidepanel.html" })
    .catch((error) => console.error(error));
}

Browser Compatibility

When developing cross-browser extensions, you'll encounter two main types of compatibility challenges:

  1. Manifest configuration compatibility
  2. Extension API compatibility

Manifest Configuration

WebExtend automatically handles manifest compatibility by:

  • Parsing entry files from the file system
  • Reflecting them to manifest.json items
  • Supporting custom manifest configuration

Example of custom manifest configuration:

web-extend.config.ts
js
import { defineConfig } from "web-extend";

export default defineConfig({
  manifest: ({ target, mode }) => {
    return {
      // ...
    };
  },
});

Reference documentation:

Extension API

WebExtend currently doesn't handle Extension API compatibility automatically. You'll need to manage this yourself using the following approaches:

For Chromium-based Browsers

Use the chrome API directly:

ts
chrome.storage.local.set({ key: "value" });
chrome.runtime.sendMessage({ type: "message" });

Recommended packages: @types/chrome

For Firefox

Use the webextension-polyfill package:

ts
import browser from "webextension-polyfill";

// The API is similar to chrome.* but uses promises
browser.storage.local.set({ key: "value" });
browser.runtime.sendMessage({ type: "message" });

Recommended packages:

Browser Startup

WebExtend automatically opens the appropriate browser when running development or preview commands:

shell
# Development mode with auto-open
web-extend dev --open

# Preview production build
web-extend preview

The browser selection is based on the target:

  • Firefox for firefox-mv2 or firefox-mv3
  • Chrome for all other targets

To customize settings for the runner, you can create a web-ext.config.[m|c]js file in the root directory. See web-ext run for a full list of configurations.

Recipes

Open the specific URL

Open a tab at the specificed URL when the browser starts. Example:

web-ext.config.js
js
import { defineWebExtConfig } from "web-extend";

export default defineWebExtConfig({
  run: {
    startUrl: "https://www.google.com",
  },
});

Open the specific browser

Provide a custom Chromium or Firefox executable path to open the specific browser.

web-ext.config.js
js
import { defineWebExtConfig } from "web-extend";

export default defineWebExtConfig({
  run: {
    firefox: "/path/to/firefox",
    chromiumBinary: "/path/to/chrome",
  },
});

Preserve profile changes

web-ext creates a new temporary profile each time the browser starts. You can provide a profile path to keep profile changes. Example:

js
// web-ext.config.js
import { defineWebExtConfig } from "web-extend";

export default defineWebExtConfig({
  run: {
    args: ["--user-data-dir=path/to/profile"],
  },
});
js
// web-ext.config.js
import { resolve } from "node:path";
import { defineWebExtConfig } from "web-extend";

export default defineWebExtConfig({
  run: {
    chromiumProfile: resolve("/path/to/profile"),
    keepProfileChanges: true,
  },
});

Released under the MIT License.