diff --git a/docs/guide/essentials/extension-apis.md b/docs/guide/essentials/extension-apis.md
index 529558d83..d014f98fd 100644
--- a/docs/guide/essentials/extension-apis.md
+++ b/docs/guide/essentials/extension-apis.md
@@ -4,52 +4,29 @@
Different browsers provide different global variables for accessing the extension APIs (chrome provides `chrome`, firefox provides `browser`, etc).
-WXT simplifies this - always use `browser`:
+WXT merges these two into a unified API accessed through the `browser` variable.
```ts
+import { browser } from 'wxt/browser';
+
browser.action.onClicked.addListener(() => {
// ...
});
```
-Other than that, refer to Chrome and Mozilla's documentation for how to use specific APIs. Everything a normal extension can do, WXT can do as well, just via `browser` instead of `chrome`.
-
-## Webextension Polyfill
-
-> Since `v0.1.0`
-
-By default, WXT uses the [`webextension-polyfill` by Mozilla](https://www.npmjs.com/package/webextension-polyfill) to make the extension API consistent between browsers.
-
-To access types, you should import the relevant namespace from `wxt/browser`:
-
-```ts
-import { Runtime } from 'wxt/browser';
-
-function handleMessage(message: any, sender: Runtime.Sender) {
- // ...
-}
-```
-
-### Disabling the polyfill
-
-> Since `v0.19.0`
-
-After the release of MV3 and Chrome's official deprecation of MV2 in June 2024, the polyfill isn't really doing anything useful anymore.
+:::tip
+With auto-imports enabled, you don't even need to import this variable from `wxt/browser`!
+:::
-You can disable it with a single line:
+The `browser` variable WXT provides is a simple export of the `browser` or `chrome` globals provided by the browser at runtime:
-```ts
-// wxt.config.ts
-export default defineConfig({
- extensionApi: 'chrome',
-});
-```
+<<< @/../packages/wxt/src/browser.ts#snippet
-This will change `wxt/browser` to simply export the `browser` or `chrome` globals based on browser at runtime:
+This means you can use the promise-style API for both MV2 and MV3, and it will work across all browsers (Chromium, Firefox, Safari, etc).
-<<< @/../packages/wxt/src/browser/chrome.ts#snippet
+## Accessing Types
-Accessing types is a little different with the polyfill disabled. They do not need to be imported; they're available on the `browser` object itself:
+All types can be accessed via WXT's `browser` object:
```ts
function handleMessage(message: any, sender: browser.runtime.Sender) {
@@ -59,7 +36,7 @@ function handleMessage(message: any, sender: browser.runtime.Sender) {
## Feature Detection
-Depending on the manifest version and browser, some APIs are not available at runtime. If an API is not available, it will be `undefined`.
+Depending on the manifest version, browser, and permissions, some APIs are not available at runtime. If an API is not available, it will be `undefined`.
:::warning
Types will not help you here. The types WXT provides for `browser` assume all APIs exist. You are responsible for knowing whether an API is available or not.
diff --git a/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts b/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts
index 62f79bed1..0383bac5a 100644
--- a/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts
+++ b/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts
@@ -11,7 +11,7 @@ describe('Background Entrypoint', () => {
fakeBrowser.reset();
});
- it("should log the extenion's runtime ID", () => {
+ it("should log the extension's runtime ID", () => {
const id = 'some-id';
fakeBrowser.runtime.id = id;
diff --git a/packages/wxt-demo/wxt.config.ts b/packages/wxt-demo/wxt.config.ts
index 57f8d5204..f92b5ae63 100644
--- a/packages/wxt-demo/wxt.config.ts
+++ b/packages/wxt-demo/wxt.config.ts
@@ -2,7 +2,6 @@ import { defineConfig } from 'wxt';
export default defineConfig({
srcDir: 'src',
- extensionApi: 'chrome',
manifest: {
permissions: ['storage'],
default_locale: 'en',
diff --git a/packages/wxt/e2e/tests/auto-imports.test.ts b/packages/wxt/e2e/tests/auto-imports.test.ts
index 167b33a44..118c52e2b 100644
--- a/packages/wxt/e2e/tests/auto-imports.test.ts
+++ b/packages/wxt/e2e/tests/auto-imports.test.ts
@@ -54,6 +54,7 @@ describe('Auto Imports', () => {
///
///
///
+ ///
///
"
`);
@@ -93,6 +94,7 @@ describe('Auto Imports', () => {
///
///
///
+ ///
"
`,
);
diff --git a/packages/wxt/e2e/tests/modules.test.ts b/packages/wxt/e2e/tests/modules.test.ts
index 367099b52..1108ddbe6 100644
--- a/packages/wxt/e2e/tests/modules.test.ts
+++ b/packages/wxt/e2e/tests/modules.test.ts
@@ -191,10 +191,7 @@ describe('Module Helpers', () => {
);
const expectedText = addPluginModule(project);
- await project.build({
- // reduce build output when comparing test failures
- extensionApi: 'chrome',
- });
+ await project.build();
await expect(project.serializeOutput()).resolves.toContain(expectedText);
});
@@ -211,10 +208,7 @@ describe('Module Helpers', () => {
);
const expectedText = addPluginModule(project);
- await project.build({
- // reduce build output when comparing test failures
- extensionApi: 'chrome',
- });
+ await project.build();
await expect(project.serializeOutput()).resolves.toContain(expectedText);
});
@@ -232,10 +226,7 @@ describe('Module Helpers', () => {
);
const expectedText = addPluginModule(project);
- await project.build({
- // reduce build output when comparing test failures
- extensionApi: 'chrome',
- });
+ await project.build();
await expect(project.serializeOutput()).resolves.toContain(expectedText);
});
@@ -248,10 +239,7 @@ describe('Module Helpers', () => {
);
const expectedText = addPluginModule(project);
- await project.build({
- // reduce build output when comparing test failures
- extensionApi: 'chrome',
- });
+ await project.build();
await expect(project.serializeOutput()).resolves.toContain(expectedText);
});
diff --git a/packages/wxt/e2e/tests/output-structure.test.ts b/packages/wxt/e2e/tests/output-structure.test.ts
index 260157ae7..f882b8595 100644
--- a/packages/wxt/e2e/tests/output-structure.test.ts
+++ b/packages/wxt/e2e/tests/output-structure.test.ts
@@ -262,9 +262,6 @@ describe('Output Directory Structure', () => {
project.addFile('entrypoints/popup/main.ts', `logHello('popup')`);
await project.build({
- // Simplify the build output for comparison
- extensionApi: 'chrome',
-
vite: () => ({
build: {
// Make output for snapshot readible
@@ -347,9 +344,6 @@ describe('Output Directory Structure', () => {
project.addFile('entrypoints/popup/main.ts', `logHello('popup')`);
await project.build({
- // Simplify the build output for comparison
- extensionApi: 'chrome',
-
vite: () => ({
build: {
// Make output for snapshot readible
diff --git a/packages/wxt/e2e/tests/typescript-project.test.ts b/packages/wxt/e2e/tests/typescript-project.test.ts
index 34c372af6..20e8e8db0 100644
--- a/packages/wxt/e2e/tests/typescript-project.test.ts
+++ b/packages/wxt/e2e/tests/typescript-project.test.ts
@@ -238,6 +238,7 @@ describe('TypeScript Project', () => {
///
///
///
+ ///
///
"
`);
diff --git a/packages/wxt/e2e/tests/user-config.test.ts b/packages/wxt/e2e/tests/user-config.test.ts
index c0b497508..b444b07b8 100644
--- a/packages/wxt/e2e/tests/user-config.test.ts
+++ b/packages/wxt/e2e/tests/user-config.test.ts
@@ -1,6 +1,5 @@
import { describe, it, expect } from 'vitest';
import { TestProject } from '../utils';
-import { InlineConfig } from '../../src/types';
describe('User Config', () => {
// Root directory is tested with all tests.
@@ -88,24 +87,6 @@ describe('User Config', () => {
`);
});
- it('should exclude the polyfill when extensionApi="chrome"', async () => {
- const buildBackground = async (config?: InlineConfig) => {
- const background = `export default defineBackground(() => console.log(browser.runtime.id));`;
- const projectWithPolyfill = new TestProject();
- projectWithPolyfill.addFile('entrypoints/background.ts', background);
- await projectWithPolyfill.build(config);
- return await projectWithPolyfill.serializeFile(
- '.output/chrome-mv3/background.js',
- );
- };
-
- const withPolyfill = await buildBackground();
- const withoutPolyfill = await buildBackground({
- extensionApi: 'chrome',
- });
- expect(withoutPolyfill).not.toBe(withPolyfill);
- });
-
it('should respect changing config files', async () => {
const project = new TestProject();
project.addFile(
diff --git a/packages/wxt/package.json b/packages/wxt/package.json
index eb44a03c3..ab9b4f5c0 100644
--- a/packages/wxt/package.json
+++ b/packages/wxt/package.json
@@ -46,12 +46,8 @@
"default": "./dist/sandbox/index.mjs"
},
"./browser": {
- "types": "./dist/browser/index.d.ts",
- "default": "./dist/browser/index.mjs"
- },
- "./browser/chrome": {
- "types": "./dist/browser/chrome.d.ts",
- "import": "./dist/browser/chrome.mjs"
+ "types": "./dist/browser.d.ts",
+ "default": "./dist/browser.mjs"
},
"./testing": {
"types": "./dist/testing/index.d.ts",
@@ -83,7 +79,6 @@
"dependencies": {
"@aklinker1/rollup-plugin-visualizer": "5.12.0",
"@types/chrome": "^0.0.269",
- "@types/webextension-polyfill": "^0.10.7",
"@webext-core/fake-browser": "^1.3.1",
"@webext-core/isolated-element": "^1.1.2",
"@webext-core/match-patterns": "^1.0.3",
@@ -124,8 +119,7 @@
"unimport": "^3.13.1",
"vite": "^5.4.8",
"vite-node": "^2.1.2",
- "web-ext-run": "^0.2.1",
- "webextension-polyfill": "^0.12.0"
+ "web-ext-run": "^0.2.1"
},
"devDependencies": {
"@aklinker1/check": "^1.4.5",
diff --git a/packages/wxt/src/browser/chrome.ts b/packages/wxt/src/browser.ts
similarity index 56%
rename from packages/wxt/src/browser/chrome.ts
rename to packages/wxt/src/browser.ts
index d1dad85db..10cd6e8b9 100644
--- a/packages/wxt/src/browser/chrome.ts
+++ b/packages/wxt/src/browser.ts
@@ -1,12 +1,19 @@
///
/**
- * EXPERIMENTAL
- *
- * Includes the `chrome` API and types when using `extensionApi: 'chrome'`.
- *
- * @module wxt/browser/chrome
+ * @module wxt/browser
*/
-import type { WxtRuntime, WxtI18n } from './index';
+
+/**
+ * This interface is empty because it is generated per-project when running `wxt prepare`. See:
+ * - `.wxt/types/paths.d.ts`
+ */
+export interface WxtRuntime {}
+
+/**
+ * This interface is empty because it is generated per-project when running `wxt prepare`. See:
+ * - `.wxt/types/i18n.d.ts`
+ */
+export interface WxtI18n {}
export type WxtBrowser = Omit & {
runtime: WxtRuntime & Omit<(typeof chrome)['runtime'], 'getURL'>;
diff --git a/packages/wxt/src/browser/index.ts b/packages/wxt/src/browser/index.ts
deleted file mode 100644
index 3eb44e110..000000000
--- a/packages/wxt/src/browser/index.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Includes the `browser` API and types when using `extensionApi: 'webextension-polyfill'` (the default).
- *
- * @module wxt/browser
- */
-
-import originalBrowser, { Browser } from 'webextension-polyfill';
-
-export type AugmentedBrowser = Omit & {
- runtime: WxtRuntime & Omit;
- i18n: WxtI18n & Omit;
-};
-
-/**
- * This interface is empty because it is generated per-project when running `wxt prepare`. See:
- * - `.wxt/types/paths.d.ts`
- */
-export interface WxtRuntime {}
-
-/**
- * This interface is empty because it is generated per-project when running `wxt prepare`. See:
- * - `.wxt/types/i18n.d.ts`
- */
-export interface WxtI18n {}
-
-export const browser: AugmentedBrowser = originalBrowser;
-
-// re-export all the types from webextension-polyfill
-// Because webextension-polyfill uses a weird namespace with "import export", there isn't a good way
-// to get these types without re-listing them.
-/** @ignore */
-export type {
- ActivityLog,
- Alarms,
- Bookmarks,
- Action,
- BrowserAction,
- BrowserSettings,
- BrowsingData,
- CaptivePortal,
- Clipboard,
- Commands,
- ContentScripts,
- ContextualIdentities,
- Cookies,
- DeclarativeNetRequest,
- Devtools,
- Dns,
- Downloads,
- Events,
- Experiments,
- Extension,
- ExtensionTypes,
- Find,
- GeckoProfiler,
- History,
- I18n,
- Identity,
- Idle,
- Management,
- Manifest, // TODO: Export custom manifest types that are valid for both Chrome and Firefox.
- ContextMenus,
- Menus,
- NetworkStatus,
- NormandyAddonStudy,
- Notifications,
- Omnibox,
- PageAction,
- Permissions,
- Pkcs11,
- Privacy,
- Proxy,
- Runtime,
- Scripting,
- Search,
- Sessions,
- SidebarAction,
- Storage,
- Tabs,
- Theme,
- TopSites,
- Types,
- Urlbar,
- UserScripts,
- WebNavigation,
- WebRequest,
- Windows,
-} from 'webextension-polyfill';
diff --git a/packages/wxt/src/client/content-scripts/__tests__/content-script-context.test.ts b/packages/wxt/src/client/content-scripts/__tests__/content-script-context.test.ts
index 6f7d14c18..099c9453f 100644
--- a/packages/wxt/src/client/content-scripts/__tests__/content-script-context.test.ts
+++ b/packages/wxt/src/client/content-scripts/__tests__/content-script-context.test.ts
@@ -16,7 +16,7 @@ describe('Content Script Context', () => {
const onInvalidated = vi.fn();
ctx.onInvalidated(onInvalidated);
- // @ts-expect-error
+ // @ts-ignore
delete fakeBrowser.runtime.id;
const isValid = ctx.isValid;
diff --git a/packages/wxt/src/core/builders/vite/index.ts b/packages/wxt/src/core/builders/vite/index.ts
index 6ab15ab4a..5fa87581c 100644
--- a/packages/wxt/src/core/builders/vite/index.ts
+++ b/packages/wxt/src/core/builders/vite/index.ts
@@ -74,7 +74,6 @@ export async function createViteBuilder(
wxtPlugins.tsconfigPaths(wxtConfig),
wxtPlugins.noopBackground(),
wxtPlugins.globals(wxtConfig),
- wxtPlugins.resolveExtensionApi(wxtConfig),
wxtPlugins.defineImportMeta(),
wxtPlugins.wxtPluginLoader(wxtConfig),
wxtPlugins.resolveAppConfig(wxtConfig),
diff --git a/packages/wxt/src/core/builders/vite/plugins/extensionApiMock.ts b/packages/wxt/src/core/builders/vite/plugins/extensionApiMock.ts
index 7724219ec..0e2b18f3a 100644
--- a/packages/wxt/src/core/builders/vite/plugins/extensionApiMock.ts
+++ b/packages/wxt/src/core/builders/vite/plugins/extensionApiMock.ts
@@ -3,12 +3,7 @@ import type * as vite from 'vite';
import { ResolvedConfig } from '../../../../types';
/**
- * Mock `webextension-polyfill`, `wxt/browser`, and `wxt/browser/*` by inlining
- * all dependencies that import them and adding a custom alias so that Vite
- * resolves to a mocked version of the module.
- *
- * TODO: Detect non-wxt dependencies (like `@webext-core/*`) that import `webextension-polyfill` via
- * `npm list` and inline them automatically.
+ * Mock `wxt/browser` and stub the global `browser`/`chrome` types with a fake version of the extension APIs
*/
export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
const virtualSetupModule = 'virtual:wxt-setup';
@@ -27,14 +22,12 @@ export function extensionApiMock(config: ResolvedConfig): vite.PluginOption {
},
resolve: {
alias: [
- { find: 'webextension-polyfill', replacement },
// wxt/browser, wxt/browser/...
- { find: /^wxt\/browser.*/, replacement },
+ { find: 'wxt/browser', replacement },
],
},
ssr: {
- // Inline all WXT modules so vite processes them so the aliases can
- // be resolved
+ // Inline all WXT modules subdependencies can be mocked
noExternal: ['wxt'],
},
};
diff --git a/packages/wxt/src/core/builders/vite/plugins/index.ts b/packages/wxt/src/core/builders/vite/plugins/index.ts
index f70dde240..5ed13ff81 100644
--- a/packages/wxt/src/core/builders/vite/plugins/index.ts
+++ b/packages/wxt/src/core/builders/vite/plugins/index.ts
@@ -9,7 +9,6 @@ export * from './cssEntrypoints';
export * from './bundleAnalysis';
export * from './globals';
export * from './extensionApiMock';
-export * from './resolveExtensionApi';
export * from './entrypointGroupGlobals';
export * from './defineImportMeta';
export * from './removeEntrypointMainFunction';
diff --git a/packages/wxt/src/core/builders/vite/plugins/resolveExtensionApi.ts b/packages/wxt/src/core/builders/vite/plugins/resolveExtensionApi.ts
deleted file mode 100644
index 17ec02064..000000000
--- a/packages/wxt/src/core/builders/vite/plugins/resolveExtensionApi.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import { ResolvedConfig } from '../../../../types';
-import type * as vite from 'vite';
-
-/**
- * Apply the experimental config for which extension API is used. This only
- * effects the extension API included at RUNTIME - during development, types
- * depend on the import.
- *
- * NOTE: this only works if we import `wxt/browser` instead of using the relative path.
- */
-export function resolveExtensionApi(config: ResolvedConfig): vite.Plugin {
- return {
- name: 'wxt:resolve-extension-api',
- config() {
- // Only apply the config if we're disabling the polyfill
- if (config.extensionApi === 'webextension-polyfill') return;
-
- return {
- resolve: {
- alias: [
- { find: /^wxt\/browser$/, replacement: 'wxt/browser/chrome' },
- ],
- },
- };
- },
- };
-}
diff --git a/packages/wxt/src/core/generate-wxt-dir.ts b/packages/wxt/src/core/generate-wxt-dir.ts
index cf9980c7f..dfa3149b9 100644
--- a/packages/wxt/src/core/generate-wxt-dir.ts
+++ b/packages/wxt/src/core/generate-wxt-dir.ts
@@ -37,10 +37,8 @@ export async function generateWxtDir(entrypoints: Entrypoint[]): Promise {
// import.meta.env.*
entries.push(await getGlobalsDeclarationEntry());
- // @types/chrome
- if (wxt.config.extensionApi === 'chrome') {
- entries.push({ module: '@types/chrome' });
- }
+ // wxt/browser types
+ entries.push({ module: '@types/chrome' });
// tsconfig.json
entries.push(await getTsConfigEntry());
diff --git a/packages/wxt/src/core/resolve-config.ts b/packages/wxt/src/core/resolve-config.ts
index e99dbb10b..4209cb823 100644
--- a/packages/wxt/src/core/resolve-config.ts
+++ b/packages/wxt/src/core/resolve-config.ts
@@ -162,8 +162,6 @@ export async function resolveConfig(
{},
);
- const extensionApi = mergedConfig.extensionApi ?? 'webextension-polyfill';
-
return {
browser,
command,
@@ -173,13 +171,7 @@ export async function resolveConfig(
filterEntrypoints,
env,
fsCache: createFsCache(wxtDir),
- imports: await getUnimportOptions(
- wxtDir,
- srcDir,
- logger,
- extensionApi,
- mergedConfig,
- ),
+ imports: await getUnimportOptions(wxtDir, srcDir, logger, mergedConfig),
logger,
manifest: await resolveManifestConfig(env, mergedConfig.manifest),
manifestVersion,
@@ -198,7 +190,6 @@ export async function resolveConfig(
analysis: resolveAnalysisConfig(root, mergedConfig),
userConfigMetadata: userConfigMetadata ?? {},
alias,
- extensionApi,
entrypointLoader: mergedConfig.entrypointLoader ?? 'vite-node',
experimental: defu(mergedConfig.experimental, {}),
dev: {
@@ -333,7 +324,6 @@ async function getUnimportOptions(
wxtDir: string,
srcDir: string,
logger: Logger,
- extensionApi: ResolvedConfig['extensionApi'],
config: InlineConfig,
): Promise {
if (config.imports === false) return false;
@@ -352,10 +342,7 @@ async function getUnimportOptions(
// ignored.
ignore: ['options'],
},
- {
- package:
- extensionApi === 'chrome' ? 'wxt/browser/chrome' : 'wxt/browser',
- },
+ { package: 'wxt/browser' },
{ package: 'wxt/sandbox' },
{ package: 'wxt/storage' },
],
diff --git a/packages/wxt/src/core/utils/__tests__/manifest.test.ts b/packages/wxt/src/core/utils/__tests__/manifest.test.ts
index 1af508dc5..56fdd1efe 100644
--- a/packages/wxt/src/core/utils/__tests__/manifest.test.ts
+++ b/packages/wxt/src/core/utils/__tests__/manifest.test.ts
@@ -13,7 +13,6 @@ import {
fakeWxtDevServer,
setFakeWxt,
} from '../testing/fake-objects';
-import { Manifest } from 'webextension-polyfill';
import {
BuildOutput,
ContentScriptEntrypoint,
@@ -56,7 +55,7 @@ describe('Manifest Utils', () => {
outDir,
},
});
- const expected: Partial = {
+ const expected: Partial = {
action: {
default_icon: popup.options.defaultIcon,
default_title: popup.options.defaultTitle,
diff --git a/packages/wxt/src/core/utils/building/rebuild.ts b/packages/wxt/src/core/utils/building/rebuild.ts
index 7a17e3ff1..4e7a6c7a5 100644
--- a/packages/wxt/src/core/utils/building/rebuild.ts
+++ b/packages/wxt/src/core/utils/building/rebuild.ts
@@ -1,4 +1,3 @@
-import type { Manifest } from 'wxt/browser';
import { BuildOutput, Entrypoint, EntrypointGroup } from '../../../types';
import { generateWxtDir } from '../../generate-wxt-dir';
import { buildEntrypoints } from './build-entrypoints';
@@ -30,7 +29,7 @@ export async function rebuild(
},
): Promise<{
output: BuildOutput;
- manifest: Manifest.WebExtensionManifest;
+ manifest: chrome.runtime.Manifest;
warnings: any[][];
}> {
const { default: ora } = await import('ora');
diff --git a/packages/wxt/src/core/utils/content-scripts.ts b/packages/wxt/src/core/utils/content-scripts.ts
index d9b1425dd..cfb6db3e6 100644
--- a/packages/wxt/src/core/utils/content-scripts.ts
+++ b/packages/wxt/src/core/utils/content-scripts.ts
@@ -1,6 +1,6 @@
-import type { Manifest, Scripting } from 'wxt/browser';
import { ContentScriptEntrypoint, ResolvedConfig } from '../../types';
import { getEntrypointBundlePath } from './entrypoints';
+import { ManifestContentScript } from './types';
/**
* Returns a unique and consistent string hash based on a content scripts options.
@@ -22,7 +22,7 @@ export function hashContentScriptOptions(
if (simplifiedOptions[key] == null) delete simplifiedOptions[key];
});
- const withDefaults: Manifest.ContentScript = {
+ const withDefaults: ManifestContentScript = {
exclude_globs: [],
exclude_matches: [],
include_globs: [],
@@ -50,7 +50,7 @@ export function mapWxtOptionsToContentScript(
options: ContentScriptEntrypoint['options'],
js: string[] | undefined,
css: string[] | undefined,
-): Manifest.ContentScript {
+): ManifestContentScript {
return {
matches: options.matches,
all_frames: options.allFrames,
@@ -72,7 +72,7 @@ export function mapWxtOptionsToRegisteredContentScript(
options: ContentScriptEntrypoint['options'],
js: string[] | undefined,
css: string[] | undefined,
-): Omit {
+): Omit {
return {
allFrames: options.allFrames,
excludeMatches: options.excludeMatches,
@@ -80,7 +80,6 @@ export function mapWxtOptionsToRegisteredContentScript(
runAt: options.runAt,
js,
css,
- // @ts-expect-error: Chrome accepts this, not typed in webextension-polyfill (https://developer.chrome.com/docs/extensions/reference/scripting/#type-RegisteredContentScript)
world: options.world,
};
}
diff --git a/packages/wxt/src/core/utils/manifest.ts b/packages/wxt/src/core/utils/manifest.ts
index 17a9feb1f..e04efedd3 100644
--- a/packages/wxt/src/core/utils/manifest.ts
+++ b/packages/wxt/src/core/utils/manifest.ts
@@ -1,4 +1,3 @@
-import type { Manifest } from 'wxt/browser';
import {
Entrypoint,
BackgroundEntrypoint,
@@ -21,12 +20,13 @@ import { normalizePath } from './paths';
import { writeFileIfDifferent } from './fs';
import defu from 'defu';
import { wxt } from '../wxt';
+import { ManifestV3WebAccessibleResource } from './types';
/**
* Writes the manifest to the output directory and the build output.
*/
export async function writeManifest(
- manifest: Manifest.WebExtensionManifest,
+ manifest: chrome.runtime.Manifest,
output: BuildOutput,
): Promise {
const str =
@@ -49,7 +49,7 @@ export async function writeManifest(
export async function generateManifest(
entrypoints: Entrypoint[],
buildOutput: Omit,
-): Promise<{ manifest: Manifest.WebExtensionManifest; warnings: any[][] }> {
+): Promise<{ manifest: chrome.runtime.Manifest; warnings: any[][] }> {
const warnings: any[][] = [];
const pkg = await getPackageJson();
@@ -65,7 +65,7 @@ export async function generateManifest(
}
const version = wxt.config.manifest.version ?? simplifyVersion(versionName);
- const baseManifest: Manifest.WebExtensionManifest = {
+ const baseManifest: chrome.runtime.Manifest = {
manifest_version: wxt.config.manifestVersion,
name: pkg?.name,
description: pkg?.description,
@@ -75,10 +75,7 @@ export async function generateManifest(
};
const userManifest = wxt.config.manifest;
- let manifest = defu(
- userManifest,
- baseManifest,
- ) as Manifest.WebExtensionManifest;
+ let manifest = defu(userManifest, baseManifest) as chrome.runtime.Manifest;
// Add reload command in dev mode
if (wxt.config.command === 'serve' && wxt.config.dev.reloadCommand) {
@@ -121,7 +118,7 @@ export async function generateManifest(
}
if (wxt.config.manifestVersion === 3) {
- validateMv3WebAccessbileResources(manifest);
+ validateMv3WebAccessibleResources(manifest);
}
stripKeys(manifest);
@@ -143,7 +140,7 @@ export async function generateManifest(
}
/**
- * Removes suffixes from the version, like X.Y.Z-alpha1 (which brosers don't allow), so it's a
+ * Removes suffixes from the version, like X.Y.Z-alpha1 (which browsers don't allow), so it's a
* simple version number, like X or X.Y or X.Y.Z, which browsers allow.
*/
function simplifyVersion(versionName: string): string {
@@ -161,7 +158,7 @@ function simplifyVersion(versionName: string): string {
}
function addEntrypoints(
- manifest: Manifest.WebExtensionManifest,
+ manifest: chrome.runtime.Manifest,
entrypoints: Entrypoint[],
buildOutput: Omit,
): void {
@@ -223,7 +220,6 @@ function addEntrypoints(
);
} else {
manifest.chrome_url_overrides ??= {};
- // @ts-expect-error: bookmarks is untyped in webextension-polyfill, but supported by chrome
manifest.chrome_url_overrides.bookmarks = getEntrypointBundlePath(
bookmarks,
wxt.config.outDir,
@@ -239,7 +235,6 @@ function addEntrypoints(
);
} else {
manifest.chrome_url_overrides ??= {};
- // @ts-expect-error: history is untyped in webextension-polyfill, but supported by chrome
manifest.chrome_url_overrides.history = getEntrypointBundlePath(
history,
wxt.config.outDir,
@@ -263,12 +258,13 @@ function addEntrypoints(
wxt.config.outDir,
'.html',
);
- const options: Manifest.ActionManifest = {};
+ const options: chrome.runtime.ManifestAction = {};
if (popup.options.defaultIcon)
options.default_icon = popup.options.defaultIcon;
if (popup.options.defaultTitle)
options.default_title = popup.options.defaultTitle;
if (popup.options.browserStyle)
+ // @ts-expect-error: Not typed by @types/chrome, but supported by Firefox
options.browser_style = popup.options.browserStyle;
if (manifest.manifest_version === 3) {
manifest.action = {
@@ -298,6 +294,7 @@ function addEntrypoints(
const page = getEntrypointBundlePath(options, wxt.config.outDir, '.html');
manifest.options_ui = {
open_in_tab: options.options.openInTab,
+ // @ts-expect-error: Not typed by @types/chrome, but supported by Firefox
browser_style:
wxt.config.browser === 'firefox'
? options.options.browserStyle
@@ -316,7 +313,6 @@ function addEntrypoints(
'Sandboxed pages not supported by Firefox. sandbox.pages was not added to the manifest',
);
} else {
- // @ts-expect-error: sandbox not typed
manifest.sandbox = {
pages: sandboxes.map((entry) =>
getEntrypointBundlePath(entry, wxt.config.outDir, '.html'),
@@ -343,7 +339,6 @@ function addEntrypoints(
open_at_install: defaultSidepanel.options.openAtInstall,
};
} else if (wxt.config.manifestVersion === 3) {
- // @ts-expect-error: Untyped
manifest.side_panel = {
default_path: page,
};
@@ -424,7 +419,7 @@ function addEntrypoints(
function discoverIcons(
buildOutput: Omit,
-): Manifest.WebExtensionManifest['icons'] {
+): chrome.runtime.Manifest['icons'] {
const icons: [string, string][] = [];
// prettier-ignore
// #region snippet
@@ -456,7 +451,7 @@ function discoverIcons(
return icons.length > 0 ? Object.fromEntries(icons) : undefined;
}
-function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
+function addDevModeCsp(manifest: chrome.runtime.Manifest): void {
const permission = `http://${wxt.server?.hostname ?? ''}/*`;
const allowedCsp = wxt.server?.origin ?? 'http://localhost:*';
@@ -468,8 +463,7 @@ function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
const extensionPagesCsp = new ContentSecurityPolicy(
manifest.manifest_version === 3
- ? // @ts-expect-error: extension_pages is not typed
- (manifest.content_security_policy?.extension_pages ??
+ ? (manifest.content_security_policy?.extension_pages ??
"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';") // default extension_pages CSP for MV3
: (manifest.content_security_policy ??
"script-src 'self'; object-src 'self';"), // default CSP for MV2
@@ -487,17 +481,15 @@ function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
if (manifest.manifest_version === 3) {
manifest.content_security_policy ??= {};
- // @ts-expect-error: extension_pages is not typed
manifest.content_security_policy.extension_pages =
extensionPagesCsp.toString();
- // @ts-expect-error: sandbox is not typed
manifest.content_security_policy.sandbox = sandboxCsp.toString();
} else {
manifest.content_security_policy = extensionPagesCsp.toString();
}
}
-function addDevModePermissions(manifest: Manifest.WebExtensionManifest) {
+function addDevModePermissions(manifest: chrome.runtime.Manifest) {
// For reloading the page
addPermission(manifest, 'tabs');
@@ -541,8 +533,7 @@ export function getContentScriptCssWebAccessibleResources(
contentScripts: ContentScriptEntrypoint[],
contentScriptCssMap: Record,
): any[] {
- const resources: Manifest.WebExtensionManifestWebAccessibleResourcesC2ItemType[] =
- [];
+ const resources: ManifestV3WebAccessibleResource[] = [];
contentScripts.forEach((script) => {
if (script.options.cssInjectionMode !== 'ui') return;
@@ -581,16 +572,18 @@ export function getContentScriptsCssMap(
}
function addPermission(
- manifest: Manifest.WebExtensionManifest,
+ manifest: chrome.runtime.Manifest,
permission: string,
): void {
manifest.permissions ??= [];
+ // @ts-expect-error: Allow using strings for permissions for MV2 support
if (manifest.permissions.includes(permission)) return;
+ // @ts-expect-error: Allow using strings for permissions for MV2 support
manifest.permissions.push(permission);
}
function addHostPermission(
- manifest: Manifest.WebExtensionManifest,
+ manifest: chrome.runtime.Manifest,
hostPermission: string,
): void {
manifest.host_permissions ??= [];
@@ -613,10 +606,10 @@ export function stripPathFromMatchPattern(pattern: string) {
/**
* Converts all MV3 web accessible resources to their MV2 forms. MV3 web accessible resources are
* generated in this file, and may be defined by the user in their manifest. In both cases, when
- * targetting MV2, automatically convert their definitions down to the basic MV2 array.
+ * targeting MV2, automatically convert their definitions down to the basic MV2 array.
*/
export function convertWebAccessibleResourcesToMv2(
- manifest: Manifest.WebExtensionManifest,
+ manifest: chrome.runtime.Manifest,
): void {
if (manifest.web_accessible_resources == null) return;
@@ -631,17 +624,17 @@ export function convertWebAccessibleResourcesToMv2(
}
function moveHostPermissionsToPermissions(
- manifest: Manifest.WebExtensionManifest,
+ manifest: chrome.runtime.Manifest,
): void {
if (!manifest.host_permissions?.length) return;
- manifest.host_permissions.forEach((permission) =>
+ manifest.host_permissions.forEach((permission: string) =>
addPermission(manifest, permission),
);
delete manifest.host_permissions;
}
-function convertActionToMv2(manifest: Manifest.WebExtensionManifest): void {
+function convertActionToMv2(manifest: chrome.runtime.Manifest): void {
if (
manifest.action == null ||
manifest.browser_action != null ||
@@ -655,8 +648,8 @@ function convertActionToMv2(manifest: Manifest.WebExtensionManifest): void {
/**
* Make sure all resources are in MV3 format. If not, add a wanring
*/
-export function validateMv3WebAccessbileResources(
- manifest: Manifest.WebExtensionManifest,
+function validateMv3WebAccessibleResources(
+ manifest: chrome.runtime.Manifest,
): void {
if (manifest.web_accessible_resources == null) return;
@@ -675,7 +668,7 @@ export function validateMv3WebAccessbileResources(
/**
* Remove keys from the manifest based on the build target.
*/
-function stripKeys(manifest: Manifest.WebExtensionManifest): void {
+function stripKeys(manifest: chrome.runtime.Manifest): void {
let keysToRemove: string[] = [];
if (wxt.config.manifestVersion === 2) {
keysToRemove.push(...mv3OnlyKeys);
@@ -686,7 +679,7 @@ function stripKeys(manifest: Manifest.WebExtensionManifest): void {
}
keysToRemove.forEach((key) => {
- delete manifest[key as keyof Manifest.WebExtensionManifest];
+ delete manifest[key as keyof chrome.runtime.Manifest];
});
}
diff --git a/packages/wxt/src/core/utils/testing/fake-objects.ts b/packages/wxt/src/core/utils/testing/fake-objects.ts
index c097aeab7..db48364d2 100644
--- a/packages/wxt/src/core/utils/testing/fake-objects.ts
+++ b/packages/wxt/src/core/utils/testing/fake-objects.ts
@@ -4,7 +4,6 @@
import { resolve } from 'path';
import { faker } from '@faker-js/faker';
import merge from 'lodash.merge';
-import { Commands, type Manifest } from 'wxt/browser';
import {
FsCache,
ResolvedConfig,
@@ -207,13 +206,11 @@ export function fakeOutputFile(): OutputFile {
return faker.helpers.arrayElement([fakeOutputAsset(), fakeOutputChunk()]);
}
-export const fakeManifest = fakeObjectCreator(
- () => ({
- manifest_version: faker.helpers.arrayElement([2, 3]),
- name: faker.string.alphanumeric(),
- version: `${faker.number.int()}.${faker.number.int()}.${faker.number.int()}`,
- }),
-);
+export const fakeManifest = fakeObjectCreator(() => ({
+ manifest_version: faker.helpers.arrayElement([2, 3]),
+ name: faker.string.alphanumeric(),
+ version: `${faker.number.int()}.${faker.number.int()}.${faker.number.int()}`,
+}));
export const fakeUserManifest = fakeObjectCreator(() => ({
name: faker.string.alphanumeric(),
@@ -298,7 +295,6 @@ export const fakeResolvedConfig = fakeObjectCreator(() => {
transformManifest: () => {},
userConfigMetadata: {},
alias: {},
- extensionApi: 'webextension-polyfill',
entrypointLoader: 'vite-node',
experimental: {},
dev: {
@@ -355,13 +351,17 @@ export const fakeBuildStepOutput = fakeObjectCreator(() => ({
entrypoints: fakeArray(fakeEntrypoint),
}));
-export const fakeManifestCommand = fakeObjectCreator(() => ({
- description: faker.string.sample(),
- shortcut: `${faker.helpers.arrayElement(['ctrl', 'alt'])}+${faker.number.int({
- min: 0,
- max: 9,
- })}`,
-}));
+export const fakeManifestCommand = fakeObjectCreator(
+ () => ({
+ description: faker.string.sample(),
+ shortcut: `${faker.helpers.arrayElement(['ctrl', 'alt'])}+${faker.number.int(
+ {
+ min: 0,
+ max: 9,
+ },
+ )}`,
+ }),
+);
export const fakeDevServer = fakeObjectCreator(() => ({
hostname: 'localhost',
diff --git a/packages/wxt/src/core/utils/transform.ts b/packages/wxt/src/core/utils/transform.ts
index f6951c614..857fdcff6 100644
--- a/packages/wxt/src/core/utils/transform.ts
+++ b/packages/wxt/src/core/utils/transform.ts
@@ -5,7 +5,7 @@ import { ProxifiedModule, parseModule } from 'magicast';
* 1. Removes or clears out `main` function from returned object
* 2. Removes any unused functions/variables outside the definition that aren't being called/used
* 3. Removes unused imports
- * 3. Removes value-less, side-effect only imports (like `import "./styles.css"` or `import "webextension-polyfill"`)
+ * 3. Removes value-less, side-effect only imports (like `import "./styles.css"` or `import "polyfill"`)
*/
export function removeMainFunctionCode(code: string): {
code: string;
diff --git a/packages/wxt/src/core/utils/types.ts b/packages/wxt/src/core/utils/types.ts
index ed6ff2000..45d68dda9 100644
--- a/packages/wxt/src/core/utils/types.ts
+++ b/packages/wxt/src/core/utils/types.ts
@@ -6,3 +6,11 @@
* // type Test = {a: string | undefined, b: number}
*/
export type NullablyRequired = { [K in keyof Required]: T[K] };
+
+export type ManifestContentScript = NonNullable<
+ chrome.runtime.Manifest['content_scripts']
+>[number];
+
+export type ManifestV3WebAccessibleResource = NonNullable<
+ chrome.runtime.ManifestV3['web_accessible_resources']
+>[number];
diff --git a/packages/wxt/src/storage.ts b/packages/wxt/src/storage.ts
index 55795d4a7..94c774b21 100644
--- a/packages/wxt/src/storage.ts
+++ b/packages/wxt/src/storage.ts
@@ -5,7 +5,7 @@
*
* @module wxt/storage
*/
-import { Storage, browser } from 'wxt/browser';
+import { browser } from 'wxt/browser';
import { dequal } from 'dequal/lite';
import { logger } from './sandbox/utils/logger';
import { toArray } from './core/utils/arrays';
@@ -391,7 +391,7 @@ function createDriver(storageArea: StorageArea): WxtStorageDriver {
return area;
};
const watchListeners = new Set<
- (changes: Storage.StorageAreaOnChangedChangesType) => void
+ (changes: Record) => void
>();
return {
getItem: async (key) => {
@@ -432,7 +432,9 @@ function createDriver(storageArea: StorageArea): WxtStorageDriver {
await getStorageArea().set(data);
},
watch(key, cb) {
- const listener = (changes: Storage.StorageAreaOnChangedChangesType) => {
+ const listener = (
+ changes: Record,
+ ) => {
const change = changes[key];
if (change == null) return;
if (dequal(change.newValue, change.oldValue)) return;
@@ -646,7 +648,7 @@ export interface WxtStorageItem<
migrate(): Promise;
}
-export type StorageArea = 'local' | 'session' | 'sync' | 'managed';
+export type StorageArea = chrome.storage.AreaName;
export type StorageItemKey = `${StorageArea}:${string}`;
export interface GetItemOptions {
diff --git a/packages/wxt/src/types.ts b/packages/wxt/src/types.ts
index 3ad48acfe..8a258f0f5 100644
--- a/packages/wxt/src/types.ts
+++ b/packages/wxt/src/types.ts
@@ -1,5 +1,4 @@
import type * as vite from 'vite';
-import type { Manifest, Scripting } from 'wxt/browser';
import { UnimportOptions, Import } from 'unimport';
import { LogLevel } from 'consola';
import type { ContentScriptContext } from './client/content-scripts/content-script-context';
@@ -8,6 +7,7 @@ import type { FSWatcher } from 'chokidar';
import { ResolvedConfig as C12ResolvedConfig } from 'c12';
import { Hookable, NestedHooks } from 'hookable';
import type * as Nypm from 'nypm';
+import { ManifestContentScript } from './core/utils/types';
export interface InlineConfig {
/**
@@ -267,7 +267,7 @@ export interface InlineConfig {
* }
* })
*/
- transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
+ transformManifest?: (manifest: chrome.runtime.Manifest) => void;
analysis?: {
/**
* Explicitly include bundle analysis when running `wxt build`. This can be overridden by the
@@ -325,16 +325,6 @@ export interface InlineConfig {
* }
*/
alias?: Record;
- /**
- * Which extension API to use.
- *
- * - `"webextension-polyfill"`: Use `browser` and types from [`webextension-polyfill`](https://www.npmjs.com/package/webextension-polyfill).
- * - `"chrome"`: Use the regular `chrome` (or `browser` for Firefox/Safari) globals provided by the browser. Types provided by [`@types/chrome`](https://www.npmjs.com/package/@types/chrome).
- *
- * @default "webextension-polyfill"
- * @since 0.19.0
- */
- extensionApi?: 'webextension-polyfill' | 'chrome';
/**
* @deprecated Will be removed in v0.20.0, please migrate to using `vite-node`, the new default.
*
@@ -444,7 +434,7 @@ export interface WxtHooks {
}
export interface BuildOutput {
- manifest: Manifest.WebExtensionManifest;
+ manifest: chrome.runtime.Manifest;
publicAssets: OutputAsset[];
steps: BuildStepOutput[];
}
@@ -537,7 +527,7 @@ export interface WxtDevServer
export interface ReloadContentScriptPayload {
registration?: BaseContentScriptEntrypointOptions['registration'];
- contentScript: Omit;
+ contentScript: Omit;
}
export type TargetBrowser = string;
@@ -588,39 +578,39 @@ export interface BackgroundEntrypointOptions extends BaseEntrypointOptions {
export interface BaseContentScriptEntrypointOptions
extends BaseEntrypointOptions {
- matches: PerBrowserOption;
+ matches: PerBrowserOption>;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default "documentIdle"
*/
- runAt?: PerBrowserOption;
+ runAt?: PerBrowserOption;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default false
*/
matchAboutBlank?: PerBrowserOption<
- Manifest.ContentScript['match_about_blank']
+ ManifestContentScript['match_about_blank']
>;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default []
*/
- excludeMatches?: PerBrowserOption;
+ excludeMatches?: PerBrowserOption;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default []
*/
- includeGlobs?: PerBrowserOption;
+ includeGlobs?: PerBrowserOption;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default []
*/
- excludeGlobs?: PerBrowserOption;
+ excludeGlobs?: PerBrowserOption;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default false
*/
- allFrames?: PerBrowserOption;
+ allFrames?: PerBrowserOption;
/**
* See https://developer.chrome.com/docs/extensions/mv3/content_scripts/
* @default false
@@ -1163,7 +1153,7 @@ export interface WxtHooks {
*/
'build:manifestGenerated': (
wxt: Wxt,
- manifest: Manifest.WebExtensionManifest,
+ manifest: chrome.runtime.Manifest,
) => HookResult;
/**
* Called once all entrypoints have been loaded from the `entrypointsDir`.
@@ -1316,7 +1306,7 @@ export interface ResolvedConfig {
/**
* @deprecated Use `build:manifestGenerated` hook instead.
*/
- transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
+ transformManifest?: (manifest: chrome.runtime.Manifest) => void;
analysis: {
enabled: boolean;
open: boolean;
@@ -1334,7 +1324,6 @@ export interface ResolvedConfig {
* Import aliases to absolute paths.
*/
alias: Record;
- extensionApi: 'webextension-polyfill' | 'chrome';
entrypointLoader: 'vite-node' | 'jiti';
experimental: {};
dev: {
diff --git a/packages/wxt/src/virtual/tsconfig.json b/packages/wxt/src/virtual/tsconfig.json
index 6f74c3f88..0820153ad 100644
--- a/packages/wxt/src/virtual/tsconfig.json
+++ b/packages/wxt/src/virtual/tsconfig.json
@@ -1,7 +1,7 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
- "types": ["vite/client", "../@types/globals.d.ts"]
+ "types": ["vite/client", "../@types/globals.d.ts", "chrome"]
},
"include": ["./*"]
}
diff --git a/packages/wxt/src/virtual/utils/reload-content-scripts.ts b/packages/wxt/src/virtual/utils/reload-content-scripts.ts
index 11b5e0c87..3b82417ae 100644
--- a/packages/wxt/src/virtual/utils/reload-content-scripts.ts
+++ b/packages/wxt/src/virtual/utils/reload-content-scripts.ts
@@ -84,7 +84,7 @@ async function reloadTabsForContentScript(contentScript: ContentScript) {
await Promise.all(
matchingTabs.map(async (tab) => {
try {
- await browser.tabs.reload(tab.id);
+ await browser.tabs.reload(tab.id!);
} catch (err) {
logger.warn('Failed to reload tab:', err);
}
diff --git a/packages/wxt/src/virtual/virtual-module-globals.d.ts b/packages/wxt/src/virtual/virtual-module-globals.d.ts
index 5199a83a9..fa95ef866 100644
--- a/packages/wxt/src/virtual/virtual-module-globals.d.ts
+++ b/packages/wxt/src/virtual/virtual-module-globals.d.ts
@@ -21,7 +21,7 @@ declare module 'virtual:user-unlisted-script-entrypoint' {
}
declare module 'wxt/browser' {
- export const browser: import('webextension-polyfill').Browser;
+ export { chrome as browser };
}
declare module 'virtual:wxt-plugins' {
diff --git a/packages/wxt/typedoc.json b/packages/wxt/typedoc.json
index 312472814..b5472db17 100644
--- a/packages/wxt/typedoc.json
+++ b/packages/wxt/typedoc.json
@@ -3,8 +3,7 @@
"src/client/index.ts",
"src/testing/index.ts",
"src/sandbox/index.ts",
- "src/browser/index.ts",
- "src/browser/chrome.ts",
+ "src/browser.ts",
"src/index.ts",
"src/storage.ts",
"src/modules.ts"
diff --git a/packages/wxt/vitest.config.ts b/packages/wxt/vitest.config.ts
index 8bb1d0dab..0c25b9629 100644
--- a/packages/wxt/vitest.config.ts
+++ b/packages/wxt/vitest.config.ts
@@ -11,6 +11,7 @@ export default defineConfig({
include: ['src/**'],
exclude: ['**/dist', '**/__tests__', 'src/utils/testing'],
},
+ setupFiles: ['./vitest.setup.ts'],
globalSetup: ['./vitest.globalSetup.ts'],
},
server: {
@@ -22,7 +23,6 @@ export default defineConfig({
resolve: {
alias: {
'wxt/testing': path.resolve('src/testing'),
- 'webextension-polyfill': path.resolve('src/virtual/mock-browser'),
},
},
});
diff --git a/packages/wxt/vitest.setup.ts b/packages/wxt/vitest.setup.ts
new file mode 100644
index 000000000..a828762f2
--- /dev/null
+++ b/packages/wxt/vitest.setup.ts
@@ -0,0 +1,5 @@
+import { fakeBrowser } from '@webext-core/fake-browser';
+import { vi } from 'vitest';
+
+vi.stubGlobal('chrome', fakeBrowser);
+vi.stubGlobal('browser', fakeBrowser);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d94a395f8..a6d891145 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -257,9 +257,6 @@ importers:
'@types/chrome':
specifier: ^0.0.269
version: 0.0.269
- '@types/webextension-polyfill':
- specifier: ^0.10.7
- version: 0.10.7
'@webext-core/fake-browser':
specifier: ^1.3.1
version: 1.3.1
@@ -383,9 +380,6 @@ importers:
web-ext-run:
specifier: ^0.2.1
version: 0.2.1
- webextension-polyfill:
- specifier: ^0.12.0
- version: 0.12.0
devDependencies:
'@aklinker1/check':
specifier: ^1.4.5
@@ -1731,9 +1725,6 @@ packages:
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
- '@types/webextension-polyfill@0.10.7':
- resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==}
-
'@types/yauzl@2.10.3':
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
@@ -4541,9 +4532,6 @@ packages:
resolution: {integrity: sha512-5D11VcjdGkA1/xax5UWL0YeAbDySKHzWFe6EpsoPNUMw5Uk9tKk9p6GUOfcaI5N7sINKfBMZYNsTBiu5dzJB9A==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
- webextension-polyfill@0.12.0:
- resolution: {integrity: sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==}
-
webidl-conversions@7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
@@ -5780,8 +5768,6 @@ snapshots:
'@types/web-bluetooth@0.0.20': {}
- '@types/webextension-polyfill@0.10.7': {}
-
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 20.16.10
@@ -8879,8 +8865,6 @@ snapshots:
- supports-color
- utf-8-validate
- webextension-polyfill@0.12.0: {}
-
webidl-conversions@7.0.0: {}
webpack-sources@3.2.3:
diff --git a/templates/react/wxt.config.ts b/templates/react/wxt.config.ts
index d1e353878..429f2b90d 100644
--- a/templates/react/wxt.config.ts
+++ b/templates/react/wxt.config.ts
@@ -2,6 +2,5 @@ import { defineConfig } from 'wxt';
// See https://wxt.dev/api/config.html
export default defineConfig({
- extensionApi: 'chrome',
modules: ['@wxt-dev/module-react'],
});
diff --git a/templates/solid/wxt.config.ts b/templates/solid/wxt.config.ts
index 0a5a994ff..1cc7596d8 100644
--- a/templates/solid/wxt.config.ts
+++ b/templates/solid/wxt.config.ts
@@ -2,6 +2,5 @@ import { defineConfig } from 'wxt';
// See https://wxt.dev/api/config.html
export default defineConfig({
- extensionApi: 'chrome',
modules: ['@wxt-dev/module-solid'],
});
diff --git a/templates/svelte/wxt.config.ts b/templates/svelte/wxt.config.ts
index f0e4f9aa1..5749b4e62 100644
--- a/templates/svelte/wxt.config.ts
+++ b/templates/svelte/wxt.config.ts
@@ -3,6 +3,5 @@ import { defineConfig } from 'wxt';
// See https://wxt.dev/api/config.html
export default defineConfig({
srcDir: 'src',
- extensionApi: 'chrome',
modules: ['@wxt-dev/module-svelte'],
});
diff --git a/templates/vanilla/wxt.config.ts b/templates/vanilla/wxt.config.ts
index 35c7ade7f..1e2f53d37 100644
--- a/templates/vanilla/wxt.config.ts
+++ b/templates/vanilla/wxt.config.ts
@@ -1,6 +1,4 @@
import { defineConfig } from 'wxt';
// See https://wxt.dev/api/config.html
-export default defineConfig({
- extensionApi: 'chrome',
-});
+export default defineConfig({});
diff --git a/templates/vue/wxt.config.ts b/templates/vue/wxt.config.ts
index 2ab714b1c..55fbc4af6 100644
--- a/templates/vue/wxt.config.ts
+++ b/templates/vue/wxt.config.ts
@@ -2,6 +2,5 @@ import { defineConfig } from 'wxt';
// See https://wxt.dev/api/config.html
export default defineConfig({
- extensionApi: 'chrome',
modules: ['@wxt-dev/module-vue'],
});