Skip to content

Development

WXT's main goal is providing the best DX it possibly can. When running your extension in dev mode, each part of your extension is reloaded separately when possible.

HMRReloaded individuallyReload extensionRestart browser
HTML File
HTML Dependency
MV3 Content Script
MV2 Content Script
Background
manifest.json🟡 See #16
wxt.config.ts🟡 See #10
web-ext.config.ts🟡 See #10

Dev Mode vs Production Builds

There are some notable differences between the development and production versions of an extension. During development:

  1. Content scripts are not listed in the manifest.json when targeting MV3. Instead, the scripting permission is used to register content scripts at runtime so they can be reloaded individually.

    To get the list of content scripts during development, run the following in the background's console:

    ts
    await chrome.scripting.getRegisteredContentScripts();
  2. The CSP is modified to allow loading scripts from the dev server. Make sure you're using Chrome v110 or above for HMR to work.

  3. If you don't include a background script/service worker, one will be created to perform various tasks in dev mode, mostly related to reloading different parts of the extension on change.

For production builds, none of the above modifications will be applied, and you're extension/manifest will only include what you have defined.

Configure Browser Startup

WXT uses web-ext by Mozilla to automatically open a browser with the extension installed. You can configure the runner's behavior via the runner option, or in a separate gitignored file, web-ext.config.ts.

ts
import { defineConfig } from 'wxt';

export default defineConfig({
  runner: {
    // Runner config
  },
});
ts
import { defineRunnerConfig } from 'wxt';

export default defineRunnerConfig({
  // Runner config
});

Browser Binaries

web-ext's browser discovery is very limited. By default, it only guesses at where Chrome and Firefox are installed. If you've customized your install locations, you may need to tell web-ext where the binaries/executables are located using the binaries option. For other Chromium based browsers, like Edge or Opera, you'll need to explicitly list them in the binaries option as well, otherwise they will open in Chrome by default.

ts
// ~/web-ext.config.ts
import { defineRunnerConfig } from 'wxt';

export default defineRunnerConfig({
  binaries: {
    chrome: '/path/to/chrome-beta', // Use Chrome Beta instead of regular Chrome
    firefox: 'firefoxdeveloperedition', // Use Firefox Developer Edition instead of regular Firefox
    edge: '/path/to/edge', // Open MS Edge when running "wxt -b edge"
  },
});

TIP

When configuring browser binaries, it's helpful to put them in ~/web-ext.config.ts instead of the project directory's web-ext.config.ts file. When placed in your home directory (~/), this config will be used by all WXT projects, so you only need to configure the binaries once.

Other options

You can customize other options as well, like startup URLs, profiles, or additional command line arguments:

ts
// web-ext.config.ts
import { defineRunnerConfig } from 'wxt';

export default defineRunnerConfig({
  startUrls: ['https://google.com', 'https://duckduckgo.com'],
  chromiumProfile: '/path/to/profile/to/use',
  chromiumArgs: ['--window-size=400,300'],
});

For a full list of options, see the API Reference.

Reload the Extension

Normally, to manually reload an extension, you have to visit chrome://extensions and click the reload button for your extension.

When running wxt command to start the dev server, WXT adds a keyboard shortcut Alt+R, that reloads the extension when pressed, without visiting chrome://extensions. This can also be customized or disabled:

ts
import { defineConfig } from 'wxt';

export default defineConfig({
  dev: {
    reloadCommand: 'Alt+T', // false, to disable
  },
});

INFO

This shortcut is only available during development, and is not be added to your extension when running wxt build or wxt-zip.