npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

extension-develop

v4.0.8

Published

Develop, build, preview, and package Extension.js projects.

Readme

Powered by Extension.js

extension-develop Version Downloads workflow

Develop, build, preview, and package Extension.js projects.

This package powers Extension.js during local development and production builds. It provides the commands and build plugins that compile your extension, run it in browsers, and produce distributable artifacts.

Installation

pnpm add extension-develop

Usage

import {
  extensionDev,
  extensionBuild,
  extensionStart,
  extensionPreview,
  type DevOptions,
  type BuildOptions,
  type StartOptions,
  type PreviewOptions
} from 'extension-develop'

async function run() {
  // Development server
  await extensionDev(undefined, {
    browser: 'chrome',
    open: true
  } satisfies DevOptions)

  // Production build + zip
  await extensionBuild(undefined, {
    browser: 'firefox',
    zip: true
  } satisfies BuildOptions)

  // Build then preview from dist/<browser>
  await extensionStart(undefined, {browser: 'edge'} satisfies StartOptions)

  // Preview using an existing output folder or project path
  await extensionPreview(undefined, {
    browser: 'chrome',
    mode: 'production'
  } satisfies PreviewOptions)
}

run()

Features

  • Live reload/HMR development server with per-instance browser runners
  • Cross-browser support: Chrome, Edge, Firefox, Chromium-based, Gecko-based
  • Rspack-based build with opinionated plugin stack
  • Clean production output in dist/<browser>
  • Zipping: distribution and/or source packages (respects .gitignore)
  • Auto-install of missing build + optional dependencies on first run
  • Type generation for TS projects via extension-env.d.ts
  • User config via extension.config.(js|mjs) for commands, browser start, unified logger defaults, and webpack config hooks
  • Managed dependency guard to avoid conflicts

Commands

| Name | Summary | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | dev | - Starts a local development server with live reload/HMR- Auto-installs build + optional deps if missing- Generates TypeScript shim types (extension-env.d.ts) when applicable- Runs a target browser with an isolated/stable profile | | build | - Production build using the webpack/Rspack plugin stack- Cleans dist/<browser> before emitting- Optional packaging: distribution zip and/or source zip- Merges user config; excludes browser runners during compilation | | start | - Runs a silent production build, then runs preview from dist/<browser>- Mirrors the runtime environment of shipped output | | preview | - Runs the extension for manual testing without dev server- Uses dist/<browser> when present, otherwise uses the project directory- Preserves production settings; only browser runners are applied | | cleanup | - Removes orphaned browser instances and temporary profiles created during development |

Command options

Options accepted by each command. Values shown are typical types or enumerations; see the tables for specifics.

Common (browser/runtime)

| Option | Type / Values | Description | | -------------- | -------------------------------------------------- | --------------------------------------------------------------- | | browser | chrome, edge, firefox, chromium-based, gecko-based | Target browser/runtime | | profile | string or false | Profile path or disable profile persistence | | startingUrl | string | Initial URL to open | | open | boolean | Focus/open the browser window (CLI: use --no-open to disable) | | --no-browser | boolean | Skip launching the browser | | chromiumBinary | string | Custom Chromium-based executable path | | geckoBinary | string | Custom Gecko-based executable path |

dev

| Option | Type / Values | Description | | ------------------- | ----------------------------------- | --------------------------------------------------------------------------------- | | mode | development, production, none | Build mode | | polyfill | boolean | Include webextension-polyfill when possible | | port | number or string | Dev server port | | source | string | Inspect a source directory | | watchSource | boolean | Watch the source directory | | sourceFormat | pretty,json,ndjson | Output format for source HTML | | sourceSummary | boolean | Output a compact summary instead of full HTML | | sourceMeta | boolean | Output page metadata (readyState, viewport, frames) | | sourceProbe | string[] | CSS selectors to probe for quick validation | | sourceTree | off,root-only | Output a compact extension root tree | | sourceConsole | boolean | Output console summary (best-effort) | | sourceDom | boolean | Output DOM snapshots and diffs | | sourceMaxBytes | number | Limit HTML output size in bytes (0 disables truncation) | | sourceRedact | off,safe,strict | Redact sensitive content in HTML output | | sourceIncludeShadow | off,open-only,all | Control Shadow DOM inclusion | | sourceDiff | boolean | Include diff metadata on watch updates | | logs | off,error,warn,info,debug,trace,all | Unified logger verbosity (all shows everything) | | logContext | list or all | Comma-separated contexts (background,content,page,sidebar,popup,options,devtools) | | logFormat | pretty,json,ndjson | Pretty text or JSON/NDJSON output | | logTimestamps | boolean | Include timestamps in pretty output | | logColor | boolean | Colorize pretty output | | logUrl | string or /regex/flags | Filter by URL substring or JS-style regex literal | | logTab | number | Filter by tabId |

build

| Option | Type / Values | Description | | ----------- | ------------- | -------------------------------------------------------------- | | zip | boolean | Package dist/<browser> as an artifact (e.g., .zip, .xpi) | | zipSource | boolean | Package source files (respects .gitignore) | | zipFilename | string | Custom base name for artifacts | | polyfill | boolean | Include webextension-polyfill when possible | | silent | boolean | Suppress non-error logs |

start

| Option | Type / Values | Description | | -------- | ------------- | --------------------------------------------- | | mode | production | Build mode | | polyfill | boolean | Include webextension-polyfill when possible |

preview

| Option | Type / Values | Description | | ---------- | ------------- | ------------------------------------------------------------------- | | mode | production | Build mode | | outputPath | string | Directory to run from (defaults to dist/<browser> when available) |

Project detection and inputs

  • Path or remote: Commands accept a local path or a remote URL.
    • GitHub repo URL: downloaded via go-git-it into a subfolder named after the repository.
    • Other HTTP(S) URLs: treated as zip archives and extracted locally.
  • Monorepos: The nearest manifest.json is resolved recursively; the nearest valid package.json is then located and validated.

Root semantics (manifest vs package.json)

  • manifest.json may live in any subdirectory of your project.
  • The project root for build/dev is the directory containing the nearest valid package.json (i.e., webpack context).
  • Special folders and root-relative paths are anchored at the package root:
    • public/, pages/, scripts/, and URLs starting with / resolve relative to the package root (e.g., /logo.png<packageRoot>/public/logo.png).
  • Web-only mode: if no package.json is found, the manifest directory is used as a fallback project root.

User config

  • Provide extension.config.js or extension.config.mjs in your project root.
  • Supported sections:
    • config(config: Configuration): mutate the assembled Rspack config. Supports a function or a plain object. When an object is provided, it is deep‑merged on top of the assembled config.
    • commands.dev | .build | .start | .preview: per‑command options (browser, profile, binaries, flags, preferences, unified logger defaults, packaging). These defaults are applied for all respective commands.
  • browser.chrome | .firefox | .edge | .chromium-based | .gecko-based: start flags, excluded flags, preferences, binaries, profile reuse (persistProfile), and per-browser extensions.
    • extensions: load-only companion extensions (unpacked dirs) loaded alongside your extension in dev/preview/start.
      • Example: { dir: "./extensions" } loads every "./extensions/*" folder that contains a manifest.json.
  • Precedence when composing options: browser._ → commands._ → CLI flags. CLI flags always win over config defaults.
  • Browser key aliases when resolving browser.* from extension.config.*:
    • When the runtime asks for chromium, loadBrowserConfig prefers browser.chromium and then falls back to browser['chromium-based'].
    • When the runtime asks for chromium-based, it prefers browser['chromium-based'] and then browser.chromium.
    • When the runtime asks for firefox, it prefers browser.firefox and then browser['gecko-based'].
    • When the runtime asks for gecko-based, it prefers browser['gecko-based'] and then browser.firefox.
  • When detected, a one‑time notice is printed to indicate config is active.

Companion extensions (load-only)

Use this when you have other unpacked extensions you want loaded alongside your main extension during dev, start, and preview.

  • What it loads: directories that contain a manifest.json at their root (unpacked extension roots).
  • How they’re loaded: they’re appended into the browser runner’s --load-extension list (Chromium) / addon install list (Firefox) before your extension. Your extension is always loaded last for precedence.
  • Discovery:
    • extensions.dir: scans one level deep (e.g. ./extensions/*/manifest.json)
      • When dir points to ./extensions, browser folders like ./extensions/chrome/* and ./extensions/firefox/* are also scanned.
    • extensions.paths: explicit directories (absolute or relative to the project root)
  • Overrides: top-level extensions applies to all commands, but commands.<cmd>.extensions overrides it for that command.
  • Invalid entries: ignored. In author mode (EXTENSION_AUTHOR_MODE=true) we print a warning if extensions is configured but nothing resolves.
  • Store URLs: entries pointing to Chrome Web Store, Edge Addons, or AMO are downloaded on-demand into ./extensions/<browser>/<id-or-slug>.
  • Local paths: only paths under ./extensions/ are accepted for companion extensions.
  • CLI: use --extensions <csv> to provide a comma-separated list of paths or store URLs.

Example:

// extension.config.mjs
export default {
  // Applies to dev/start/preview unless overridden per-command
  extensions: {
    dir: './extensions',
    paths: ['./vendor/some-unpacked-extension']
  },
  commands: {
    dev: {
      // Override only for dev
      extensions: ['./extensions/debug-helper']
    }
  }
}

Environment variables in extension.config.*

  • extension.config.* runs in a Node context during command startup.
    • Use process.env.* to read environment variables inside the config file.
    • import.meta.env.* is available in your extension code at bundle time (via the Env plugin), not in the Node config.
  • During config loading, develop preloads environment files from the project directory into process.env using the following order (first match wins):
    1. .env.defaults (always merged first when present)
    2. .env.development
    3. .env.local
    4. .env
  • In monorepos, if none of the files above exist in the project directory, develop falls back to the nearest workspace root (directory containing pnpm-workspace.yaml) and applies the same loading order there.
  • Only variables you read explicitly in the config are used there; client-side injection still requires the EXTENSION_PUBLIC_* prefix.
  • Example:
// extension.config.js (Node-based)
export default {
  browser: {
    chrome: {
      startingUrl:
        process.env.EXTENSION_PUBLIC_START_URL || 'https://example.com'
    }
  },
  commands: {
    dev: {
      // Unified logger defaults for `extension dev`
      logLevel: 'off',
      // omit or set to undefined to include all
      logContexts: ['background', 'content'],
      logFormat: 'pretty',
      logTimestamps: true,
      logColor: true,
      // Optional filters
      logUrl: '/example\\.com/i',
      logTab: 123
    }
  },
  // Either a function
  config: (config) => config
  // Or a plain object to merge
  // config: { resolve: { alias: { react: 'preact/compat' } } }
}

Safety and ergonomics

  • Managed dependency guard: If your extension.config.* references dependencies that are managed by Extension.js itself, the command aborts with a detailed message to prevent version conflicts.
  • Auto‑install: If node_modules is missing, the appropriate package manager is detected and dependencies are installed before running.
  • Type generation: For TypeScript projects, extension-env.d.ts is generated/updated to include required types and polyfills.

Packaging outputs

  • Distribution artifacts live under dist/<browser>/ and source artifacts under dist/.
  • File names default to a sanitized form of manifest.name plus manifest.version (override with zipFilename).
  • Source packaging respects .gitignore.

Example layout when both zip and zipSource are enabled:

dist/
  chrome/
    <name>-<version>.zip
  <name>-<version>-source.zip

Notes and compatibility

  • Built on the same Rspack stack as @/webpack; user config is loaded when an extension.config.* is present.
  • Only EXTENSION_PUBLIC_* variables are injected into client code; avoid secrets in templated .json/.html.

Plugins

| Name | Group | Summary | | -------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | plugin-extension | core | - Core builder: emits pages and scripts- Validates and rewrites manifest.json- Ships icons, JSON, locales, and web resources- Ensures dev parity between local and shipped output | | plugin-css | core | - Auto‑wires CSS for HTML and content scripts- Optional SASS/LESS/PostCSS when configs exist- Integrates Stylelint when configured | | plugin-js-frameworks | core | - Detects React/Preact/Vue/Svelte and TypeScript- Configures SWC parsing, loaders/plugins, and safe aliases- Sets tsconfig resolution- Defers heavy work to beforeRun in production | | plugin-static-assets | core | - Emits images, fonts, and misc files to assets/- Inlines small SVGs (≤2KB), emits larger ones- Content hashing in production; stable names in development- Respects existing custom SVG rules | | plugin-compatibility | core | - Cross‑browser helpers- Normalizes browser‑specific manifest fields- Optional webextension-polyfill for Chromium | | plugin-compilation | core | - Loads env and templating (EXTENSION_PUBLIC_*)- Optional dist/<browser> cleaning- Compact, de‑duplicated compilation summary |

Notes and compatibility

  • Built against @rspack/core; Webpack 5 may work for some plugins but is not officially supported here.
  • Only EXTENSION_PUBLIC_* variables are injected into client code; avoid embedding secrets in templated .json/.html.

Related files in this folder

  • webpack/webpack-config.ts: Assembles the plugin stack and shared configuration.
  • dev-server/: Local development server wiring and reload orchestration.
  • webpack/webpack-types.ts: Common types for the plugin stack.

License

MIT (c) Cezar Augusto and the Extension.js authors.