web-ext

repository·master·Indexed 25 days ago

https://github.com/mozilla/web-ext

A command-line tool and NodeJS library designed to help developers build, run, lint, and test WebExtensions, with an initial focus on Firefox extensions. It provides core CLI commands such as `run`, `lint`, `sign`, `build`, and `docs`, and can be integrated into NodeJS projects as an ESM module to programmatically execute extension workflows.

Tokens
7.5K
Snippets
5
Records
54
Agent score
84%

What's inside web-ext

  1. Install web-ext via npm

    master

    You can install web-ext either globally on your machine or as a development dependency within a specific project. Ensure you are running a current LTS version of Node.js.

    Global Installation

    To install the command globally:

    npm install --global web-ext

    Project-specific Installation

    To install as a devDependency (recommended for team version control):

    npm install --save-dev web-ext

    You can then use it in your package.json scripts. For example, to run an extension from a specific directory:

    package.json

    "scripts": {
      "start:firefox": "web-ext run --source-dir ./extension-dist/"
    }

    You can pass additional arguments to npm scripts using the -- suffix, such as specifying a Firefox version:

    npm run start:firefox -- --firefox=nightly
    npm install --global web-ext
  2. Install web-ext from source

    master

    To build and install web-ext from the source repository, follow these steps:

    1. Uninstall any existing global npm installation:
      npm uninstall --global web-ext
    2. Clone the repository and install dependencies:
      git clone https://github.com/mozilla/web-ext.git
      cd web-ext
      npm ci
    3. Build the command:
      npm run build
    4. Link it to your Node installation:
      npm link

    To update, simply pull the latest changes and rebuild:

    cd /path/to/web-ext
    git pull
    npm run build
    git clone https://github.com/mozilla/web-ext.git
    cd web-ext
    npm ci
    npm run build
    npm link
  3. Connect to Firefox for Android via TCP port

    master

    When running the FirefoxAndroidExtensionRunner, it automatically discovers a remote debugging protocol (RDP) Unix socket on the Android device and forwards it to a free local TCP port.

    The runner will log the specific TCP port it has chosen. You can use this port to connect Firefox DevTools to the Firefox for Android instance running on your device.

  4. Run extension on Firefox for Android via NodeJS API

    master

    To run an extension on Firefox for Android, use web-ext/util/adb to manage devices and APKs, then call webExt.cmd.run with the firefox-android target.

    import webExt from 'web-ext';
    import * as adbUtils from "web-ext/util/adb";
    
    // Path to adb binary (optional, auto-detected if missing)
    const adbBin = "/path/to/adb";
    
    // Get device and APK info
    const deviceIds = await adbUtils.listADBDevices(adbBin);
    const adbDevice = ... // select device from deviceIds
    const firefoxAPKs = await adbUtils.listADBFirefoxAPKs(adbDevice, adbBin);
    const firefoxApk = ... // select APK from firefoxAPKs
    
    webExt.cmd.run({
      target: 'firefox-android',
      firefoxApk,
      adbDevice,
      sourceDir: ...
    }).then((extensionRunner) => {
      // Handle extension runner
    });
  5. Sign an extension via NodeJS API

    master

    Use webExt.cmd.sign() to request a signed .xpi from Mozilla. This is the recommended method over using the internal submit-addon module.

    import webExt from 'web-ext';
    
    webExt.cmd.sign({
      // Set userAgentString to a custom one of your choice
      userAgentString: 'YOUR-CUSTOM-USERAGENT',
      apiKey: 'YOUR_API_KEY',
      apiSecret: 'YOUR_API_SECRET',
      amoBaseUrl: 'https://addons.mozilla.org/api/v5/',
      sourceDir: '...',
      channel: 'unlisted',
    });
  6. Use web-ext in NodeJS code (ESM)

    master

    Since version 7.0.0, the web-ext npm package exports NodeJS native ES modules only. If you are using CommonJS, you must use dynamic imports.

    Use webExt.cmd.run() to execute commands programmatically. Note that web-ext is primarily a CLI tool, and its internal API has limited support and may change in minor/patch updates.

    Example of running an extension:

    import webExt from 'web-ext';
    
    webExt.cmd
      .run(
        {
          // Command options (e.g., --source-dir becomes sourceDir)
          firefox: '/path/to/Firefox-executable',
          sourceDir: '/path/to/your/extension/source/',
        },
        {
          // Non-CLI related options
          // Set shouldExitProgram to false to keep your Node app running
          shouldExitProgram: false,
        },
      )
      .then((extensionRunner) => {
        console.log(extensionRunner);
        // extensionRunner.reloadAllExtensions();
        // extensionRunner.exit();
      });
    import webExt from 'web-ext';
    
    webExt.cmd
      .run(
        {
          firefox: '/path/to/Firefox-executable',
          sourceDir: '/path/to/your/extension/source/',
        },
        {
          shouldExitProgram: false,
        },
      )
      .then((extensionRunner) => {
        console.log(extensionRunner);
      });
  7. Configure web-ext logging and input

    master

    You can control the behavior of the web-ext execution via the options object in the second argument of webExt.cmd.run().

    Verbose Logging

    Use web-ext/util/logger to enable verbose logging:

    import * as webExtLogger from 'web-ext/util/logger';
    
    webExtLogger.consoleStream.makeVerbose();
    webExt.cmd.run({ sourceDir: './src' }, { shouldExitProgram: false });

    Disable Standard Input

    To prevent web-ext from using standard input, pass noInput: true in the command options:

    webExt.cmd.run({ sourceDir: './src', noInput: true }, { shouldExitProgram: false });
  8. Configure ESLint for web-ext

    master
    The web-ext project uses ESLint with a flat configuration (eslint.config.mjs). The configuration utilizes @babel/eslint-parser for parsing and includes eslint-plugin-import for module resolution and organization. It enforces strict coding standards including eslint:recommended and specific rules for import ordering and spacing.
  9. Configure ChromiumExtensionRunner parameters

    master

    When instantiating ChromiumExtensionRunner, pass a params object with the following configuration keys:

    KeyDescription
    extensionsAn array of objects, each containing a sourceDir (the path to the extension's root directory).
    chromiumBinaryPath to the Chromium executable.
    chromiumProfilePath to a Chromium profile or user-data-dir.
    keepProfileChangesBoolean. If true, changes made to the profile are preserved. If false, the profile is copied to a temporary directory.
    argsAn array of additional command-line arguments to pass to Chromium.
    startUrlA single URL or an array of URLs to open on startup.
    verboseBoolean. If true, enables verbose logging.
    customChromiumPrefsAn object of key-value pairs representing Chromium preferences.
    chromiumLaunch(Internal/Advanced) A function used to launch the Chromium instance.
  10. Available web-ext CLI commands

    master

    The web-ext CLI provides several core commands for extension development. You can view detailed documentation for any command by appending --help (e.g., web-ext build --help).

    • run: Run the extension.
    • lint: Validate the extension source.
    • sign: Sign the extension so it can be installed in Firefox.
    • build: Create an extension package from source.
    • docs: Open the web-ext documentation in a browser.
  11. Reload extensions in Firefox Desktop

    master

    When using FirefoxDesktopExtensionRunner, you can reload extensions without restarting the browser instance.

    • To reload all extensions: Call await runner.reloadAllExtensions(). This returns an array of results. If multiple extensions fail to reload, it returns a MultiExtensionsReloadError containing a map of errors keyed by sourceDir.
    • To reload a specific extension: Call await runner.reloadExtensionBySourceDir(extensionSourceDir). This requires the extensionSourceDir used during the initial setup. If the extension is not found or cannot be reloaded, it returns a WebExtError.