UNPKG

wxt

Version:

⚡ Next-gen Web Extension Framework

1,407 lines (1,405 loc) 60.7 kB
/** * Called before WXT writes .wxt/tsconfig.json and .wxt/wxt.d.ts, allowing * addition of custom references and declarations in wxt.d.ts, or directly * modifying the options in `tsconfig.json`. * * @example * wxt.hooks.hook('prepare:types', (wxt, entries) => { * // Add a file, ".wxt/types/example.d.ts", that defines a global * // variable called "example" in the TS project. * entries.push({ * path: 'types/example.d.ts', * text: 'declare const a: string;', * tsReference: true, * }); * // use module to add Triple-Slash Directive in .wxt/wxt.d.ts * // eg: /// <reference types="@types/example" /> * entries.push({ * module: '@types/example', * }); * }); */import { ContentScriptContext } from "./utils/content-script-context.mjs"; import { ManifestContentScript } from "./core/utils/types.mjs"; import { Hookable, NestedHooks } from "hookable"; import { Import, UnimportOptions } from "unimport"; import { PluginVisualizerOptions } from "@aklinker1/rollup-plugin-visualizer"; import * as Nypm from "nypm"; import { ResolvedConfig } from "c12"; import { LogLevel } from "consola"; import { Browser } from "@wxt-dev/browser"; import * as vite from "vite"; //#region src/types.d.ts interface InlineConfig { /** * Your project's root directory containing the `package.json` used to fill * out the `manifest.json`. * * @default process.cwd() */ root?: string; /** * Directory containing all source code. Set to `"src"` to move all source * code to a `src/` directory. * * After changing, remember to move the `public/` and `entrypoints/` * directories into the new source dir. * * @default config.root */ srcDir?: string; /** * Directory containing files that will be copied to the output directory * as-is. * * @default '${config.root}/public' */ publicDir?: string; /** @default '${config.srcDir}/entrypoints' */ entrypointsDir?: string; /** @default '${config.root}/modules' */ modulesDir?: string; /** * A list of entrypoint names (`"popup"`, `"options"`, etc.) to build. Will * speed up the build if your extension has lots of entrypoints, and you don't * need to build all of them to develop a feature. If specified, this * completely overrides the `include`/`exclude` option provided * per-entrypoint. */ filterEntrypoints?: string[]; /** * Output directory that stored build folders and ZIPs. * * @default '.output' */ outDir?: string; /** * Template string for customizing the output directory structure. Available * variables: * * - <span v-pre>`{{browser}}`</span>: The target browser (e.g., 'chrome', * 'firefox') * - <span v-pre>`{{manifestVersion}}`</span>: The manifest version (e.g., 2 or * 3) * - <span v-pre>`{{mode}}`</span>: The build mode (e.g., 'development', * 'production') * - <span v-pre>`{{modeSuffix}}`</span>: A suffix based on the mode ('-dev' for * development, '' for production) * - <span v-pre>`{{command}}`</span>: The WXT command being run (e.g., 'build', * 'serve') * * @example * '{{browser}}-mv{{manifestVersion}}'; * * @default <span v-pre>`"{{browser}}-mv{{manifestVersion}}{{modeSuffix}}"`</span> */ outDirTemplate?: string; /** * > Only available when using the JS API. Not available in `wxt.config.ts` * > files * * Path to `wxt.config.ts` file or `false` to disable config file discovery. * * @default 'wxt.config.ts' */ configFile?: string | false; /** * Set to `true` to show debug logs. Overridden by the command line `--debug` * option. * * @default false */ debug?: boolean; /** * Explicitly set a mode to run in. This will override the default mode for * each command, and can be overridden by the command line `--mode` option. */ mode?: string; /** * Customize auto-import options. Set to `false` to disable auto-imports. * * For example, to add a directory to auto-import from, you can use: * * ```ts * export default defineConfig({ * imports: { * dirs: ['some-directory'], * }, * }); * ``` */ imports?: WxtUnimportOptions | false; /** * Explicitly set a browser to build for. This will override the default * browser for each command, and can be overridden by the command line * `--browser` option. * * @default * "chrome" */ browser?: TargetBrowser; /** * Target browsers to support. When set, `import.meta.env.BROWSER` will be * narrowed to a string literal type containing only the specified browser * names. * * @default [ ] */ targetBrowsers?: TargetBrowser[]; /** * Explicitly set a manifest version to target. This will override the default * manifest version for each command, and can be overridden by the command * line `--mv2` or `--mv3` option. */ manifestVersion?: TargetManifestVersion; /** * Chokidar options used by dev-mode file watchers. This is useful in * containers, WSL, and network file systems where native file events can be * unreliable. * * @example * export default defineConfig({ * watchOptions: { * usePolling: true, * interval: 1000, * }, * }); */ watchOptions?: vite.WatchOptions; /** * Override the logger used. * * @default * consola */ logger?: Logger; /** * Customize the `manifest.json` output. Can be an object, promise, or * function that returns an object or promise. */ manifest?: UserManifest | Promise<UserManifest> | UserManifestFn; /** * Suppress specific warnings during the build process. * * @example * export default defineConfig({ * suppressWarnings: { * firefoxDataCollection: true, * }, * }); */ suppressWarnings?: { /** * Suppress warnings for: * https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent */ firefoxDataCollection?: boolean; /** * Suppress warnings when the Firefox extension ID is missing. * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings#id */ firefoxId?: boolean; }; /** * Configure browser startup. Options set here can be overridden in a * `web-ext.config.ts` file. */ webExt?: WebExtConfig; zip?: { /** * Configure the filename output when zipping files. * * Available template variables: * * - <span v-pre>`{{name}}`</span> - The project's name converted to * kebab-case * - <span v-pre>`{{version}}`</span> - The version from the manifest * - <span v-pre>`{{versionName}}`</span> - The `version_name` from the * manifest or, if not set (i.e. if built for Firefox), the `version` from * the manifest * - <span v-pre>`{{packageVersion}}`</span> - The version from the * package.json * - <span v-pre>`{{browser}}`</span> - The target browser from the * `--browser` CLI flag * - <span v-pre>`{{mode}}`</span> - The current mode * - <span v-pre>`{{modeSuffix}}`</span>: A suffix based on the mode ('-dev' * for development, '' for production) * - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3" * * @default '{{name}}-{{packageVersion}}-{{browser}}{{modeSuffix}}.zip' */ artifactTemplate?: string; /** * When zipping the extension, also zip sources. * * - `undefined`: zip sources if the target browser is "firefox" or "opera" * - `true`: always zip sources * - `false`: never zip sources * * @default undefined */ zipSources?: boolean; /** * Configure the filename output when zipping files. * * Available template variables: * * - <span v-pre>`{{name}}`</span> - The project's name converted to * kebab-case * - <span v-pre>`{{version}}`</span> - The version from the manifest * - <span v-pre>`{{versionName}}`</span> - The `version_name` from the * manifest or, if not set (i.e. if built for Firefox), the `version` from * the manifest * - <span v-pre>`{{packageVersion}}`</span> - The version from the * package.json * - <span v-pre>`{{browser}}`</span> - The target browser from the * `--browser` CLI flag * - <span v-pre>`{{mode}}`</span> - The current mode * - <span v-pre>`{{modeSuffix}}`</span>: A suffix based on the mode ('-dev' * for development, '' for production) * - <span v-pre>`{{manifestVersion}}`</span> - Either "2" or "3" * * @default '{{name}}-{{packageVersion}}-sources{{modeSuffix}}.zip' */ sourcesTemplate?: string; /** * Override the artifactTemplate's `{name}` template variable. Defaults to * the `package.json`'s name, or if that doesn't exist, the current working * directories name. */ name?: string; /** * Root directory to ZIP when generating the sources ZIP. * * @default config.root */ sourcesRoot?: string; /** * [Tinyglobby](https://npmjs.org/tinyglobby) patterns of files to include * when creating a ZIP of all your source code for Firefox. Patterns are * relative to your `config.zip.sourcesRoot`. * * Sources ZIP files are created using standard allowlist/blocklist * behavior: * * - You specify a pattern to "include" (via `includeSources`), then a pattern * to "exclude" from the included files (via `excludeSources`). * * By default, this option includes all files except for hidden files and * directories (files/directories starting with a `.`). * * If you want to include hidden files/directories in your sources ZIP, see * `InlineConfig.zip.dotSources`. * * @example * ['entrypoints/**', 'wxt.config.ts', 'package.json', 'tsconfig.json']; */ includeSources?: string[]; /** * [Tinyglobby](https://npmjs.org/tinyglobby) patterns of files to exclude * when creating a ZIP of all your source code for Firefox. Patterns are * relative to your `config.zip.sourcesRoot`. * * By default, WXT excludes some files: * * - `node_modules` * - Tests files and directories * - Output directory * * Any values specified in this option will be merged with the ones above - * you cannot replace the default values, only add to them. * * @example * [ * 'coverage', // Ignore the coverage directory in the `sourcesRoot` * ]; */ excludeSources?: string[]; /** * Include hidden files/directories in your sources ZIP. * * [Tinyglobby](https://npmjs.org/tinyglobby) does not match against files * and directory that start with a `.` by default. For example, if you need * to include a `.env` file, you need to set this to `true`, then exclude * other hidden files/directories in `excludeSources`. * * **Be very careful when this is enabled - WXT may include files with * secrets in your ZIP you did not intend to share with Mozilla or upload to * other places**. Make sure all hidden files you don't want to include are * added to `excludeSources`. * * @default false */ dotSources?: boolean; /** * [Tinyglobby](https://npmjs.org/tinyglobby) patterns of files to exclude * when zipping the extension. * * @example * [ * '**\/*.map', // Exclude all sourcemaps * ]; * * @default [ ] */ exclude?: string[]; /** * The Firefox review process requires the extension be buildable from * source to make reviewing easier. This field allows you to use private * packages without exposing your auth tokens. * * Just list the name of all the packages you want to download and include * in the sources zip. Usually, these will be private packages behind auth * tokens, but they don't have to be. * * All packages listed here will be downloaded to in `.wxt/local_modules/` * and an `overrides` or `resolutions` field (depending on your package * manager) will be added to the `package.json`, pointing to the downloaded * packages. * * > _**DO NOT include versions or version filters.**_ Just the package name. * > If multiple versions of a package are present in the project, all * > versions will be downloaded and referenced in the package.json * > correctly. * * @example * // Correct: * ['@scope/package-name', 'package-name']; * * // Incorrect, don't include versions!!! * ['@scope/package-name@1.1.3', 'package-name@^2']; * * @default [ ] */ downloadPackages?: string[]; /** * Compression level to use when zipping files. * * Levels: 0 (no compression) to 9 (maximum compression). * * @default 9 */ compressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; }; analysis?: { /** * Explicitly include bundle analysis when running `wxt build`. This can be * overridden by the command line `--analyze` option. * * @default false */ enabled?: boolean; /** * Set to true to automatically open the `stats.html` file when the build is * finished. When building in CI, the browser will never open. * * @default false */ open?: boolean; /** * When running `wxt build --analyze` or setting `analysis.enabled` to true, * customize how the bundle will be visualized. See * [`rollup-plugin-visualizer`](https://github.com/btd/rollup-plugin-visualizer#how-to-use-generated-files) * for more details. * * @default 'treemap' */ template?: PluginVisualizerOptions['template']; /** * Name of the output HTML file. Relative to the project's root directory. * * Changing the filename of the outputFile also effects the names of the * artifacts generated when setting `keepArtifacts` to true: * * - "stats.html" => "stats-*.json" * - "stats/bundle.html" => "bundle-*.json" * - ".analysis/index.html" => "index-*.json" * * @default 'stats.html' */ outputFile?: string; /** * By default, the `stats-*.json` artifacts generated during bundle analysis * are deleted. Set to `true` to keep them. * * One stats file is output per build step. * * @default false */ keepArtifacts?: boolean; }; /** * Add additional paths to the `.wxt/tsconfig.json`. Use this instead of * overwriting the `paths` in the root `tsconfig.json` if you want to add new * paths. * * The key is the import alias and the value is either a relative path to the * root directory or an absolute path. * * @example * { "testing": "src/utils/testing.ts" } */ alias?: Record<string, string>; /** Experimental settings - use with caution. */ experimental?: {}; /** Config effecting dev mode only. */ dev?: { server?: { /** * Host to bind the dev server to. * * @default 'localhost' */ host?: string; /** * Port to run the dev server on. Defaults to the first open port from * 3000 to 3010. */ port?: number; /** * Origin to use to connect from the extension ui runtime to the dev * server. * * @default 'http://localhost:3000' */ origin?: string; /** * Whether the dev server should fail if the specified port is already in * use. When `false` and a `port` is specified, the next available port * will be used instead of throwing an error. * * @default false */ strictPort?: boolean; }; /** * Controls whether a custom keyboard shortcut command, `Alt+R`, is added * during dev mode to quickly reload the extension. * * If false, the shortcut is not added during development. * * If set to a custom string, you can override the key combo used. See * [Chrome's command * docs](https://developer.chrome.com/docs/extensions/reference/api/commands) * for available options. * * @default 'Alt+R' */ reloadCommand?: string | false; }; /** Project hooks for running logic during the build process. */ hooks?: NestedHooks<WxtHooks>; /** * List of WXT module names to include. Can be the full package name * ("wxt-module-analytics"), or just the suffix ("analytics" would resolve to * "wxt-module-analytics"). */ modules?: string[]; } interface InlineConfig { /** * Return custom Vite options from a function. See * [https://vitejs.dev/config/shared-options.html](https://vitejs.dev/config/shared-options.html). * * [`root`](#root), [`configFile`](#configfile), and [`mode`](#mode) should be * set in WXT's config instead of Vite's. * * This is a function because any vite plugins added need to be recreated for * each individual build step, in case they have internal state causing them * to fail when reused. */ vite?: (env: ConfigEnv) => WxtViteConfig | Promise<WxtViteConfig>; } interface ResolvedConfig$1 { vite: (env: ConfigEnv) => WxtViteConfig | Promise<WxtViteConfig>; } type WxtViteConfig = Omit<vite.UserConfig, 'root' | 'configFile' | 'mode'>; interface WxtHooks { /** * Called when WXT has created Vite's config for a build step. Useful if you * want to add plugins or update the vite config per entrypoint group. * * @param entrypoints The list of entrypoints being built with the provided * config. * @param viteConfig The config that will be used for the dev server. */ 'vite:build:extendConfig': (entrypoints: readonly Entrypoint[], viteConfig: vite.InlineConfig) => HookResult; /** * Called when WXT has created Vite's config for the dev server. Useful if you * want to add plugins or update the vite config per entrypoint group. * * @param viteConfig The config that will be used to build the entrypoints. * Can be updated by reference. */ 'vite:devServer:extendConfig': (config: vite.InlineConfig) => HookResult; } interface BuildOutput { manifest: Browser.runtime.Manifest; publicAssets: OutputAsset[]; steps: BuildStepOutput[]; } type OutputFile = OutputChunk | OutputAsset; interface OutputChunk { type: 'chunk'; /** * Relative, normalized path relative to the output directory. * * Ex: "content-scripts/overlay.js" */ fileName: string; /** Absolute, normalized paths to all dependencies this chunk relies on. */ moduleIds: string[]; } interface OutputAsset { type: 'asset'; /** * Relative, normalized path relative to the output directory. * * Ex: "icons/16.png" */ fileName: string; } interface BuildStepOutput { entrypoints: EntrypointGroup; chunks: OutputFile[]; } interface WxtDevServer extends Omit<WxtBuilderServer, 'listen' | 'close'>, ServerInfo { /** Stores the current build output of the server. */ currentOutput: BuildOutput | undefined; /** Start the server. */ start(): Promise<void>; /** Stop the server. */ stop(): Promise<void>; /** * Close the browser, stop the server, rebuild the entire extension, and start * the server again. */ restart(): Promise<void>; /** Transform the HTML for dev mode. */ transformHtml(url: string, html: string, originalUrl?: string | undefined): Promise<string>; /** Tell the extension to reload by running `browser.runtime.reload`. */ reloadExtension: () => void; /** * Tell an extension page to reload. * * The path is the bundle path, not the input paths, so if the input paths is * "src/options/index.html", you would pass "options.html" because that's * where it is written to in the dist directory, and where it's available at * in the actual extension. * * @example * server.reloadPage('popup.html'); * server.reloadPage('sandbox.html'); */ reloadPage: (path: string) => void; /** * Tell the extension to restart a content script. * * @param payload Information about the content script to reload. */ reloadContentScript: (payload: ReloadContentScriptPayload) => void; /** Grab the latest runner config and restart the browser. */ restartBrowser: () => void; } interface ReloadContentScriptPayload { registration?: BaseContentScriptEntrypointOptions['registration']; contentScript: Omit<Browser.scripting.RegisteredContentScript, 'id'>; } type TargetBrowser = string; type TargetManifestVersion = 2 | 3; type UserConfig = Omit<InlineConfig, 'configFile'>; interface Logger { debug(...args: any[]): void; log(...args: any[]): void; info(...args: any[]): void; warn(...args: any[]): void; error(...args: any[]): void; fatal(...args: any[]): void; success(...args: any[]): void; level: LogLevel; } interface BaseEntrypointOptions { /** * List of target browsers to include this entrypoint in. Defaults to being * included in all builds. Cannot be used with `exclude`. You must choose one * of the two options. * * @default undefined */ include?: TargetBrowser[]; /** * List of target browsers to exclude this entrypoint from. Cannot be used * with `include`. You must choose one of the two options. * * @default undefined */ exclude?: TargetBrowser[]; } interface BackgroundEntrypointOptions extends BaseEntrypointOptions { persistent?: PerBrowserOption<boolean>; /** * Set to `"module"` to output the background entrypoint as ESM. ESM outputs * can share chunks and reduce the overall size of the bundled extension. * * When `undefined`, the background is bundled individually into an IIFE * format. * * @default undefined */ type?: PerBrowserOption<'module'>; } interface BaseScriptEntrypointOptions extends BaseEntrypointOptions { /** * The variable name for the IIFE in the output bundle. * * This option is relevant for scripts inserted into the page context where * the default IIFE variable name may conflict with an existing variable on * the target page. This applies to content scripts with world=MAIN, and * others, such as unlisted scripts, that could be dynamically injected into * the page with a <script> tag. * * Available options: * * - `true`: automatically generate a name for the IIFE based on the entrypoint * name * - `false`: Output the IIFE without a variable name, making it anonymous. This * is the safest option to avoid conflicts with existing variables on the * page. * - `string`: Use the provided string as the global variable name. * - `function`: A function that receives the entrypoint and returns a string to * use as the variable name. * * @default false */ globalName?: string | boolean | ((entrypoint: Entrypoint) => string); } interface BaseContentScriptEntrypointOptions extends BaseScriptEntrypointOptions { matches?: PerBrowserOption<NonNullable<ManifestContentScript['matches']>>; /** * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/ * * @default 'documentIdle' */ runAt?: PerBrowserOption<Browser.scripting.RegisteredContentScript['runAt']>; /** * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/ * * @default false */ matchAboutBlank?: PerBrowserOption<ManifestContentScript['match_about_blank']>; /** * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/ * * @default [ ] */ excludeMatches?: PerBrowserOption<ManifestContentScript['exclude_matches']>; /** * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/ * * @default [ ] */ includeGlobs?: PerBrowserOption<ManifestContentScript['include_globs']>; /** * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/ * * @default [ ] */ excludeGlobs?: PerBrowserOption<ManifestContentScript['exclude_globs']>; /** * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/ * * @default false */ allFrames?: PerBrowserOption<ManifestContentScript['all_frames']>; /** * See https://developer.chrome.com/docs/extensions/mv3/content_scripts/ * * @default false */ matchOriginAsFallback?: PerBrowserOption<boolean>; /** * Customize how imported/generated styles are injected with the content * script. Regardless of the mode selected, CSS will always be built and * included in the output directory. * * - `"manifest"` - Include the CSS in the manifest, under the content script's * `css` array. * - `"manual"` - Exclude the CSS from the manifest. You are responsible for * manually loading it onto the page. Use * `browser.runtime.getURL("content-scripts/<name>.css")` to get the file's * URL * - `"ui"` - Exclude the CSS from the manifest. CSS will be automatically added * to your UI when calling `createShadowRootUi` * * @default 'manifest' */ cssInjectionMode?: PerBrowserOption<'manifest' | 'manual' | 'ui'>; /** * Specify how the content script is registered. * * - `"manifest"`: The content script will be added to the `content_scripts` * entry in the manifest. This is the normal and most well known way of * registering a content script. * - `"runtime"`: The content script's `matches` is added to `host_permissions` * and you are responsible for using the scripting API to register/execute * the content script dynamically at runtime. * * @default 'manifest' */ registration?: PerBrowserOption<'manifest' | 'runtime'>; /** * Do not send the `wxt:content-script-started` message via * `window.postMessage`. * * This has been replaced with custom events. The `postMessage` call is kept * for backwards compatibility. For some websites the `postMessage` call is * undesirable, such as those with poorly written message event listeners. * * Setting this to `true` opts into the behavior that will become the default * in a future version of WXT, where the `postMessage` call is removed * entirely. * * See https://github.com/wxt-dev/wxt/pull/1938 and * https://github.com/wxt-dev/wxt/pull/2035 for a detailed discussion. */ noScriptStartedPostMessage?: boolean; } interface MainWorldContentScriptEntrypointOptions extends BaseContentScriptEntrypointOptions { /** * See * https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts#isolated_world */ world: 'MAIN'; } interface IsolatedWorldContentScriptEntrypointOptions extends BaseContentScriptEntrypointOptions { /** * See * https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts#isolated_world * * @default 'ISOLATED' */ world?: 'ISOLATED'; } /** * Firefox theme icon definition for light/dark mode support. * * @see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_action#theme_icons */ interface ThemeIcon { /** Path to the icon shown when the browser uses a light theme. */ light: string; /** Path to the icon shown when the browser uses a dark theme. */ dark: string; /** Icon size in pixels. */ size: number; } interface PopupEntrypointOptions extends BaseEntrypointOptions { /** * The type of action to use in the manifest. * * In MV2, defaults to `"browser_action"`. In MV3, `"browser_action"` is * converted to `"action"`, while `"page_action"` is kept as-is (Firefox MV3 * only). */ actionType?: PerBrowserOption<'browser_action' | 'page_action'>; /** @deprecated Use `actionType` instead. */ mv2Key?: PerBrowserOption<'browser_action' | 'page_action'>; defaultIcon?: Record<string, string>; defaultTitle?: PerBrowserOption<string>; /** * Chrome only. Controls the initial enabled/disabled state of the action. * * @see https://developer.chrome.com/docs/extensions/reference/api/action#enabled_state */ defaultState?: PerBrowserOption<'enabled' | 'disabled'>; browserStyle?: PerBrowserOption<boolean>; /** * Firefox only. Defines the part of the browser in which the button is * initially placed. * * @see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/action#default_area */ defaultArea?: PerBrowserOption<'navbar' | 'menupanel' | 'tabstrip' | 'personaltoolbar'>; /** * Firefox only. Icons for light and dark themes. * * @see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/action#theme_icons */ themeIcons?: ThemeIcon[]; } interface OptionsEntrypointOptions extends BaseEntrypointOptions { title?: string; openInTab?: PerBrowserOption<boolean>; browserStyle?: PerBrowserOption<boolean>; chromeStyle?: PerBrowserOption<boolean>; } interface SidepanelEntrypointOptions extends BaseEntrypointOptions { /** * Firefox only. See * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sidebar_action#syntax * * @default false */ openAtInstall?: PerBrowserOption<boolean>; /** * @deprecated See * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/sidebar_action#syntax */ browserStyle?: PerBrowserOption<boolean>; defaultIcon?: string | Record<string, string>; defaultTitle?: PerBrowserOption<string>; } interface BaseEntrypoint { /** * The entrypoint's name. This is the filename or dirname without the type * suffix. * * Examples: * * - `popup.html` → `popup` * - `options/index.html` → `options` * - `named.sandbox.html` → `named` * - `named.sandbox/index.html` → `named` * - `sandbox.html` → `sandbox` * - `sandbox/index.html` → `sandbox` * - `overlay.content.ts` → `overlay` * - `overlay.content/index.ts` → `overlay` * * The name is used when generating an output file: * `<entrypoint.outputDir>/<entrypoint.name>.<ext>` */ name: string; /** Absolute path to the entrypoint's input file. */ inputPath: string; /** * Absolute path to the entrypoint's output directory. Can be * `wxt.config.outDir` or a subdirectory of it. */ outputDir: string; /** * When true, the entrypoint will not be built by WXT. Normally this is set * based on the `filterEntrypoints` config or the entrypoint's * `include`/`exclude` options defined inside the file. * * See * https://wxt.dev/guide/essentials/target-different-browsers.html#filtering-entrypoints */ skipped?: boolean; } interface GenericEntrypoint extends BaseEntrypoint { type: 'sandbox' | 'bookmarks' | 'history' | 'newtab' | 'devtools' | 'unlisted-page' | 'unlisted-style' | 'content-script-style'; options: ResolvedPerBrowserOptions<BaseEntrypointOptions>; } interface UnlistedScriptEntrypoint extends BaseEntrypoint { type: 'unlisted-script'; options: ResolvedPerBrowserOptions<BaseScriptEntrypointOptions>; } interface BackgroundEntrypoint extends BaseEntrypoint { type: 'background'; options: ResolvedPerBrowserOptions<BackgroundEntrypointOptions>; } interface ContentScriptEntrypoint extends BaseEntrypoint { type: 'content-script'; options: ResolvedPerBrowserOptions<MainWorldContentScriptEntrypointOptions | IsolatedWorldContentScriptEntrypointOptions>; } interface PopupEntrypoint extends BaseEntrypoint { type: 'popup'; options: ResolvedPerBrowserOptions<PopupEntrypointOptions, 'defaultIcon'>; } interface OptionsEntrypoint extends BaseEntrypoint { type: 'options'; options: ResolvedPerBrowserOptions<OptionsEntrypointOptions>; } interface SidepanelEntrypoint extends BaseEntrypoint { type: 'sidepanel'; options: ResolvedPerBrowserOptions<SidepanelEntrypointOptions, 'defaultIcon'>; } type Entrypoint = GenericEntrypoint | BackgroundEntrypoint | UnlistedScriptEntrypoint | ContentScriptEntrypoint | PopupEntrypoint | OptionsEntrypoint | SidepanelEntrypoint; interface EntrypointInfo { name: string; /** Absolute path to the entrypoint file. */ inputPath: string; type: Entrypoint['type']; } type EntrypointGroup = Entrypoint | Entrypoint[]; type OnContentScriptStopped = (cb: () => void) => void; interface IsolatedWorldContentScriptDefinition extends IsolatedWorldContentScriptEntrypointOptions { /** * Main function executed when the content script is loaded. * * When running a content script with `browser.scripting.executeScript`, * values returned from this function will be returned in the `executeScript` * result as well. Otherwise returning a value does nothing. */ main(ctx: ContentScriptContext): any | Promise<any>; } interface MainWorldContentScriptDefinition extends MainWorldContentScriptEntrypointOptions { /** * Main function executed when the content script is loaded. * * When running a content script with `browser.scripting.executeScript`, * values returned from this function will be returned in the `executeScript` * result as well. Otherwise returning a value does nothing. */ main(): any | Promise<any>; } type ContentScriptDefinition = IsolatedWorldContentScriptDefinition | MainWorldContentScriptDefinition; interface BackgroundDefinition extends BackgroundEntrypointOptions { /** * Main function executed when the background script is started. Cannot be * async. */ main(): void; } interface UnlistedScriptDefinition extends BaseScriptEntrypointOptions { /** * Main function executed when the unlisted script is ran. * * When running a content script with `browser.scripting.executeScript`, * values returned from this function will be returned in the `executeScript` * result as well. Otherwise returning a value does nothing. */ main(): any | Promise<any>; } /** * Either a single value or a map of different browsers to the value for that * browser. */ type PerBrowserOption<T> = T | PerBrowserMap<T>; type PerBrowserMap<T> = { [browser: TargetBrowser]: T; }; /** * Convert `{ key: PerBrowserOption<T> }` to just `{ key: T }`, stripping away * the `PerBrowserOption` type for all fields inside the object. * * A optional second list of keys can be passed if a field isn't compatible with * `PerBrowserOption`, like `defaultIcon`. */ type ResolvedPerBrowserOptions<T, TOmitted extends keyof T = never> = { [key in keyof Omit<T, TOmitted>]: T[key] extends PerBrowserOption<infer U> ? U : T[key] } & { [key in TOmitted]: T[key] }; /** * Firefox data collection permission types for personal data. See: * https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/#specifying-data-types */ type FirefoxDataCollectionType = 'locationInfo' | 'browsingActivity' | 'websiteContent' | 'websiteActivity' | 'searchTerms' | 'bookmarksInfo' | 'healthInfo' | 'contactInfo' | 'socialInfo' | (string & {}); /** * Firefox data collection permissions configuration. See: * https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/#specifying-data-types */ interface FirefoxDataCollectionPermissions { /** * Required data collection permissions. Users must opt in to use the * extension. Can include personal data types or "none" to explicitly indicate * no data collection. */ required?: Array<FirefoxDataCollectionType | 'none'>; /** * Optional data collection permissions. Users can opt in after installation. * Can include personal data types or "technicalAndInteraction" (which can * only be optional). */ optional?: Array<FirefoxDataCollectionType | 'technicalAndInteraction'>; } /** * Manifest customization available in the `wxt.config.ts` file. You cannot * configure entrypoints here, they are configured inline. */ type UserManifest = { [key in keyof Browser.runtime.ManifestV3 as key extends 'action' | 'background' | 'chrome_url_overrides' | 'devtools_page' | 'manifest_version' | 'options_page' | 'options_ui' | 'permissions' | 'sandbox' | 'web_accessible_resources' ? never : key]?: Browser.runtime.ManifestV3[key] } & { action?: Browser.runtime.ManifestV3['action'] & { default_area?: 'navbar' | 'menupanel' | 'tabstrip' | 'personaltoolbar'; theme_icons?: ThemeIcon[]; }; browser_action?: Browser.runtime.ManifestV2['browser_action'] & { browser_style?: boolean; default_area?: 'navbar' | 'menupanel' | 'tabstrip' | 'personaltoolbar'; theme_icons?: ThemeIcon[]; }; page_action?: Browser.runtime.ManifestV2['page_action'] & { browser_style?: boolean; }; browser_specific_settings?: { gecko?: { id?: string; strict_min_version?: string; strict_max_version?: string; update_url?: string; /** * Firefox data collection permissions configuration. See: * https://extensionworkshop.com/documentation/develop/firefox-builtin-data-consent/#specifying-data-types */ data_collection_permissions?: FirefoxDataCollectionPermissions; }; gecko_android?: { strict_min_version?: string; strict_max_version?: string; }; safari?: { strict_min_version?: string; strict_max_version?: string; }; }; permissions?: (Browser.runtime.ManifestPermission | (string & Record<never, never>))[]; web_accessible_resources?: string[] | Browser.runtime.ManifestV3['web_accessible_resources']; }; type UserManifestFn = (env: ConfigEnv) => UserManifest | Promise<UserManifest>; interface ConfigEnv { /** * The build mode passed into the CLI. By default, `wxt` uses `"development"` * and `wxt build|zip` uses `"production"`. */ mode: string; /** * The command used to run WXT. `"serve"` during development and `"build"` for * any other command. */ command: WxtCommand; /** * Browser passed in from the CLI via the `-b` or `--browser` flag. Defaults * to `"chrome"` when not passed. */ browser: TargetBrowser; /** * Manifest version passed in from the CLI via the `--mv2` or `--mv3` flags. * When not passed, it depends on the target browser. See [the * guide](https://wxt.dev/guide/key-concepts/multiple-browsers.html#target-manifest-version) * for more details. */ manifestVersion: 2 | 3; } type WxtCommand = 'build' | 'serve'; /** * Options for how [`web-ext`](https://github.com/mozilla/web-ext) starts the * browser. */ interface WebExtConfig { /** * Whether or not to open the browser with the extension installed in dev * mode. * * @default false */ disabled?: boolean; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#browser-console */ openConsole?: boolean; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#devtools */ openDevtools?: boolean; /** * List of browser names and the binary that should be used to open the * browser. * * @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#chromium-binary * @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#firefox */ binaries?: Record<string, string>; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#firefox-profile */ firefoxProfile?: string; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#chromium-profile */ chromiumProfile?: string; /** * An map of chrome preferences from * https://chromium.googlesource.com/chromium/src/+/main/chrome/common/pref_names.h * * @example * // change your downloads directory * { * download: { * default_directory: "/my/custom/dir", * }, * } * * @default * // Enable dev mode and allow content script sourcemaps * { * devtools: { * synced_preferences_sync_disabled: { * skipContentScripts: false, * }, * } * extensions: { * ui: { * developer_mode: true, * }, * } * } */ chromiumPref?: Record<string, any>; /** * By default, chrome opens a random port for debugging. Set this value to use * a specific port. */ chromiumPort?: number; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#pref */ firefoxPref?: Record<string, boolean | number | string>; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#args */ firefoxArgs?: string[]; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#args */ chromiumArgs?: string[]; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#start-url */ startUrls?: string[]; /** @see https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#keep-profile-changes */ keepProfileChanges?: boolean; } interface WxtBuilder { /** Name of tool used to build. Ex: "Vite" or "Webpack". */ name: string; /** Version of tool used to build. Ex: "5.0.2" */ version: string; /** * Import a JS entrypoint file, returning the default export containing the * options. */ importEntrypoint<T>(this: WxtBuilder, path: string): Promise<T>; /** Import a list of JS entrypoint files, returning their options. */ importEntrypoints(paths: string[]): Promise<Record<string, unknown>[]>; /** * Build a single entrypoint group. This is effectively one of the multiple * "steps" during the build process. */ build(group: EntrypointGroup): Promise<BuildStepOutput>; /** Start a dev server at the provided port. */ createServer(info: ServerInfo): Promise<WxtBuilderServer>; } interface WxtBuilderServer { /** Start the server. */ listen(): Promise<void>; /** Stop the server. */ close(): Promise<void>; /** Transform the HTML for dev mode. */ transformHtml(url: string, html: string, originalUrl?: string | undefined): Promise<string>; /** The web socket server used to communicate with the extension. */ ws: { /** * Send a message via the server's websocket, with an optional payload. * * @example * ws.send("wxt:reload-extension"); * ws.send("wxt:reload-content-script", { ... }); */ send(message: string, payload?: any): void; /** Listen for messages over the server's websocket. */ on(message: string, cb: (payload: any) => void): void; }; /** Chokidar file watcher instance. */ watcher: vite.ViteDevServer['watcher']; on?(event: string, callback: () => void): void; } interface ServerInfo { /** Ex: `"localhost"` */ host: string; /** Ex: `3000` */ port: number; /** Ex: `"http://localhost:3000"` */ origin: string; } type PrepareTsconfigs = { /** The JSON contents of the `.wxt/tsconfig.json` file. */tsconfig: any; }; type HookResult = Promise<void> | void; interface WxtHooks { /** * Called after WXT modules are initialized, when the WXT instance is ready to * be used. `wxt.server` isn't available yet, use `server:created` to get it. * * @param wxt The configured WXT object */ ready: (wxt: Wxt) => HookResult; /** * Called whenever config is loaded or reloaded. Use this hook to modify * config by modifying `wxt.config`. * * @param wxt The configured WXT object */ 'config:resolved': (wxt: Wxt) => HookResult; 'prepare:types': (wxt: Wxt, entries: WxtDirEntry[]) => HookResult; /** * Called before WXT writes your tsconfig to the disk, allowing full * customization by modifying the object by reference. * * @since 0.20.28 * @example * wxt.hooks.hook('prepare:tsconfig', (wxt, { tsconfig }) => { * tsconfig.compilerOptions.lib.push('WebWorker'); * }); */ 'prepare:tsconfig': (wxt: Wxt, configs: PrepareTsconfigs) => HookResult; /** * Called before generating the list of public paths inside * `.wxt/types/paths.d.ts`. Use this hook to add additional paths (relative to * output directory) WXT doesn't add automatically. * * @example * wxt.hooks.hook('prepare:publicPaths', (wxt, paths) => { * paths.push('icons/128.png'); * paths.push({ * type: 'templateLiteral', * path: '_favicon/?${string}', * }); * }); * * @param wxt The configured WXT object * @param paths This list of paths TypeScript allows `browser.runtime.getURL` * to be called with. */ 'prepare:publicPaths': (wxt: Wxt, paths: PublicPathEntry[]) => HookResult; /** * Called before the build is started in both dev mode and build mode. * * @param wxt The configured WXT object */ 'build:before': (wxt: Wxt) => HookResult; /** * Called once the build process has finished. You can add files to the build * summary here by pushing to `output.publicAssets`. * * @param wxt The configured WXT object * @param output The results of the build */ 'build:done': (wxt: Wxt, output: Readonly<BuildOutput>) => HookResult; /** * Called once the manifest has been generated. Used to transform the manifest * by reference before it is written to the output directory. * * @param wxt The configured WXT object * @param manifest The manifest that was generated */ 'build:manifestGenerated': (wxt: Wxt, manifest: Browser.runtime.Manifest) => HookResult; /** * Called once the names and paths of all entrypoints have been resolved. * * @param wxt The configured WXT object * @param infos List of entrypoints found in the project's `entrypoints` * directory */ 'entrypoints:found': (wxt: Wxt, infos: EntrypointInfo[]) => HookResult; /** * Called once all entrypoints have been loaded from the `entrypointsDir`. Use * `wxt.builder.importEntrypoint` to load entrypoint options from the file, or * manually define them. * * @param wxt The configured WXT object * @param entrypoints The list of entrypoints to be built */ 'entrypoints:resolved': (wxt: Wxt, entrypoints: Entrypoint[]) => HookResult; /** * Called once all entrypoints have been grouped into their build groups. * * @param wxt The configured WXT object * @param entrypoints The list of groups to build in each build step */ 'entrypoints:grouped': (wxt: Wxt, groups: EntrypointGroup[]) => HookResult; /** * Called when public assets are found. You can modify the `files` list by * reference to add or remove public files. * * @param wxt The configured WXT object * @param entrypoints The list of files that will be copied into the output * directory */ 'build:publicAssets': (wxt: Wxt, files: ResolvedPublicFile[]) => HookResult; /** * Called before the zip process starts. * * @param wxt The configured WXT object */ 'zip:start': (wxt: Wxt) => HookResult; /** * Called before zipping the extension files. * * @param wxt The configured WXT object */ 'zip:extension:start': (wxt: Wxt) => HookResult; /** * Called after zipping the extension files. * * @param wxt The configured WXT object * @param zipPath The path to the created extension zip file */ 'zip:extension:done': (wxt: Wxt, zipPath: string) => HookResult; /** * Called before zipping the source files (for Firefox). * * @param wxt The configured WXT object */ 'zip:sources:start': (wxt: Wxt) => HookResult; /** * Called after zipping the source files (for Firefox). * * @param wxt The configured WXT object * @param zipPath The path to the created sources zip file */ 'zip:sources:done': (wxt: Wxt, zipPath: string) => HookResult; /** * Called after the entire zip process is complete. * * @param wxt The configured WXT object * @param zipFiles An array of paths to all created zip files */ 'zip:done': (wxt: Wxt, zipFiles: string[]) => HookResult; /** * Called when the dev server is created (and `wxt.server` is assigned). * Server has not been started yet. * * @param wxt The configured WXT object * @param server Same as `wxt.server`, the object WXT uses to control the dev * server. */ 'server:created': (wxt: Wxt, server: WxtDevServer) => HookResult; /** * Called when the dev server is started. * * @param wxt The configured WXT object * @param server Same as `wxt.server`, the object WXT uses to control the dev * server. */ 'server:started': (wxt: Wxt, server: WxtDevServer) => HookResult; /** * Called when the dev server is stopped. * * @param wxt The configured WXT object * @param server Same as `wxt.server`, the object WXT uses to control the dev * server. */ 'server:closed': (wxt: Wxt, server: WxtDevServer) => HookResult; } interface Wxt { config: ResolvedConfig$1; hooks: Hookable<WxtHooks>; /** Alias for `wxt.hooks.hook(...)`. */ hook: Hookable<WxtHooks>['hook']; /** Alias for config.logger */ logger: Logger; /** Reload config file and update `wxt.config` with the result. */ reloadConfig: () => Promise<void>; /** Package manager utilities. */ pm: WxtPackageManager; /** If the dev server was started, it will be available. */ server?: WxtDevServer; /** The module in charge of executing all the build steps. */ builder: WxtBuilder; } interface ResolvedConfig$1 { root: string; srcDir: string; publicDir: string; /** * Absolute path pointing to `.wxt` directory in project root. * * @example * '/path/to/project/.wxt'; */ wxtDir: string; typesDir: string; entrypointsDir: string; modulesDir: string; filterEntrypoints?: Set<string>; /** * Absolute path to the `.output` directory * * @example * '/path/to/project/.output'; */ outBaseDir: string; /** * Absolute path to the target output directory. * * @example * '/path/to/project/.output/chrome-mv3'; */