diff --git a/docs/guide/essentials/extension-apis.md b/docs/guide/essentials/extension-apis.md
index 898857e0..5d0187b9 100644
--- a/docs/guide/essentials/extension-apis.md
+++ b/docs/guide/essentials/extension-apis.md
@@ -4,61 +4,41 @@
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`.
+:::tip
+With auto-imports enabled, you don't even need to import this variable from `wxt/browser`!
+:::
-## 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.
-
-You can disable it with a single line:
-
-```ts [wxt.config.ts]
-export default defineConfig({
- extensionApi: 'chrome',
-});
-```
-
-This will change `wxt/browser` to simply export the `browser` or `chrome` globals based on browser at runtime:
+The `browser` variable WXT provides is a simple export of the `browser` or `chrome` globals provided by the browser at runtime:
<<< @/../packages/browser/src/index.mjs#snippet
-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:
+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).
+
+## Accessing Types
+
+All types can be accessed via WXT's `Browser` namespace:
```ts
-function handleMessage(message: any, sender: browser.runtime.Sender) {
+import { Browser } from 'wxt/browser';
+
+function handleMessage(message: any, sender: Browser.runtime.MessageSender) {
// ...
}
```
## 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/browser/src/__tests__/index.test.ts b/packages/browser/src/__tests__/index.test.ts
index 1fb8330c..07b40f51 100644
--- a/packages/browser/src/__tests__/index.test.ts
+++ b/packages/browser/src/__tests__/index.test.ts
@@ -1,6 +1,6 @@
///
import { describe, expectTypeOf, it } from 'vitest';
-import { browser, Browser } from '../index';
+import { browser, type Browser } from '../index';
describe('browser', () => {
describe('types', () => {
diff --git a/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts b/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts
index 62f79bed..c46f84d2 100644
--- a/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts
+++ b/packages/wxt-demo/src/entrypoints/__tests__/background.test.ts
@@ -1,7 +1,7 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import background from '../background';
-chrome.i18n.getMessage = () => 'fake-message';
+browser.i18n.getMessage = () => 'fake-message';
const logMock = vi.fn();
console.log = logMock;
@@ -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 6961eea2..eee9f5d3 100644
--- a/packages/wxt-demo/wxt.config.ts
+++ b/packages/wxt-demo/wxt.config.ts
@@ -3,7 +3,6 @@ import { presetUno } from 'unocss';
export default defineConfig({
srcDir: 'src',
- extensionApi: 'chrome',
manifest: {
permissions: ['storage'],
default_locale: 'en',
diff --git a/packages/wxt/e2e/tests/modules.test.ts b/packages/wxt/e2e/tests/modules.test.ts
index 11d86688..dcbe6c90 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 260157ae..4145eaab 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
@@ -289,11 +286,7 @@ describe('Output Directory Structure', () => {
logHello("background");
}
});
- // @ts-expect-error
- ((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) == null ? globalThis.chrome : (
- // @ts-expect-error
- globalThis.browser
- );
+ ((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) ? globalThis.browser : globalThis.chrome;
function print(method, ...args) {
return;
}
@@ -347,9 +340,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
@@ -381,11 +371,7 @@ describe('Output Directory Structure', () => {
background;
function initPlugins() {
}
- // @ts-expect-error
- ((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) == null ? globalThis.chrome : (
- // @ts-expect-error
- globalThis.browser
- );
+ ((_b = (_a = globalThis.browser) == null ? void 0 : _a.runtime) == null ? void 0 : _b.id) ? globalThis.browser : globalThis.chrome;
function print(method, ...args) {
return;
}
diff --git a/packages/wxt/e2e/tests/user-config.test.ts b/packages/wxt/e2e/tests/user-config.test.ts
index b120bf87..0ee4a969 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 39ca18ad..03583adb 100644
--- a/packages/wxt/package.json
+++ b/packages/wxt/package.json
@@ -47,12 +47,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",
@@ -84,11 +80,10 @@
"dependencies": {
"@1natsu/wait-element": "catalog:",
"@aklinker1/rollup-plugin-visualizer": "catalog:",
- "@types/chrome": "catalog:",
- "@types/webextension-polyfill": "catalog:",
"@webext-core/fake-browser": "catalog:",
"@webext-core/isolated-element": "catalog:",
"@webext-core/match-patterns": "catalog:",
+ "@wxt-dev/browser": "workspace:*",
"@wxt-dev/storage": "workspace:^1.0.0",
"async-mutex": "catalog:",
"c12": "catalog:",
@@ -128,8 +123,7 @@
"unimport": "catalog:",
"vite": "catalog:",
"vite-node": "catalog:",
- "web-ext-run": "catalog:",
- "webextension-polyfill": "catalog:"
+ "web-ext-run": "catalog:"
},
"devDependencies": {
"@aklinker1/check": "catalog:",
@@ -149,9 +143,5 @@
"vitest": "catalog:",
"vitest-plugin-random-seed": "catalog:"
},
- "peerDependenciesMeta": {
- "@types/chrome": {
- "optional": true
- }
- }
+ "peerDependenciesMeta": {}
}
diff --git a/packages/wxt/src/browser.ts b/packages/wxt/src/browser.ts
new file mode 100644
index 00000000..9f0b96fd
--- /dev/null
+++ b/packages/wxt/src/browser.ts
@@ -0,0 +1,25 @@
+/**
+ * @module wxt/browser
+ */
+import { browser as _browser, type Browser } from '@wxt-dev/browser';
+
+/**
+ * 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 _browser)['runtime'], 'getURL'>;
+ i18n: WxtI18n & Omit<(typeof _browser)['i18n'], 'getMessage'>;
+};
+
+export const browser: WxtBrowser = _browser;
+
+export { Browser };
diff --git a/packages/wxt/src/browser/chrome.ts b/packages/wxt/src/browser/chrome.ts
deleted file mode 100644
index d1dad85d..00000000
--- a/packages/wxt/src/browser/chrome.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-///
-/**
- * EXPERIMENTAL
- *
- * Includes the `chrome` API and types when using `extensionApi: 'chrome'`.
- *
- * @module wxt/browser/chrome
- */
-import type { WxtRuntime, WxtI18n } from './index';
-
-export type WxtBrowser = Omit & {
- runtime: WxtRuntime & Omit<(typeof chrome)['runtime'], 'getURL'>;
- i18n: WxtI18n & Omit<(typeof chrome)['i18n'], 'getMessage'>;
-};
-
-// #region snippet
-export const browser: WxtBrowser =
- // @ts-expect-error
- globalThis.browser?.runtime?.id == null
- ? globalThis.chrome
- : // @ts-expect-error
- globalThis.browser;
-// #endregion snippet
diff --git a/packages/wxt/src/browser/index.ts b/packages/wxt/src/browser/index.ts
deleted file mode 100644
index 8e21e1fb..00000000
--- a/packages/wxt/src/browser/index.ts
+++ /dev/null
@@ -1,87 +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,
- 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 23ff12e8..548beb3d 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
@@ -24,7 +24,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 545c6339..24bbe5d9 100644
--- a/packages/wxt/src/core/builders/vite/index.ts
+++ b/packages/wxt/src/core/builders/vite/index.ts
@@ -83,7 +83,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 7724219e..0e2b18f3 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 f70dde24..5ed13ff8 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 17ec0206..00000000
--- 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 e7d35949..3e58d778 100644
--- a/packages/wxt/src/core/generate-wxt-dir.ts
+++ b/packages/wxt/src/core/generate-wxt-dir.ts
@@ -37,11 +37,6 @@ 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' });
- }
-
// 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 01c38ca2..d5a9b15a 100644
--- a/packages/wxt/src/core/resolve-config.ts
+++ b/packages/wxt/src/core/resolve-config.ts
@@ -171,8 +171,6 @@ export async function resolveConfig(
{},
);
- const extensionApi = mergedConfig.extensionApi ?? 'webextension-polyfill';
-
return {
browser,
command,
@@ -182,13 +180,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,
@@ -207,7 +199,6 @@ export async function resolveConfig(
analysis: resolveAnalysisConfig(root, mergedConfig),
userConfigMetadata: userConfigMetadata ?? {},
alias,
- extensionApi,
entrypointLoader: mergedConfig.entrypointLoader ?? 'vite-node',
experimental: defu(mergedConfig.experimental, {}),
dev: {
@@ -342,7 +333,6 @@ async function getUnimportOptions(
wxtDir: string,
srcDir: string,
logger: Logger,
- extensionApi: ResolvedConfig['extensionApi'],
config: InlineConfig,
): Promise {
if (config.imports === false) return false;
@@ -361,10 +351,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 230f1470..1a767d10 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,
@@ -22,6 +21,7 @@ import {
} from '../../../types';
import { wxt } from '../../wxt';
import { mock } from 'vitest-mock-extended';
+import type { Browser } from '@wxt-dev/browser';
const outDir = '/output';
const contentScriptOutDir = '/output/content-scripts';
@@ -58,7 +58,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 7a17e3ff..b0902f5c 100644
--- a/packages/wxt/src/core/utils/building/rebuild.ts
+++ b/packages/wxt/src/core/utils/building/rebuild.ts
@@ -1,9 +1,9 @@
-import type { Manifest } from 'wxt/browser';
import { BuildOutput, Entrypoint, EntrypointGroup } from '../../../types';
import { generateWxtDir } from '../../generate-wxt-dir';
import { buildEntrypoints } from './build-entrypoints';
import { generateManifest, writeManifest } from '../../utils/manifest';
import { wxt } from '../../wxt';
+import type { Browser } from '@wxt-dev/browser';
/**
* Given a configuration, list of entrypoints, and an existing, partial output, build the
@@ -30,7 +30,7 @@ export async function rebuild(
},
): Promise<{
output: BuildOutput;
- manifest: Manifest.WebExtensionManifest;
+ manifest: Browser.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 3ba1eb18..93f00d8a 100644
--- a/packages/wxt/src/core/utils/content-scripts.ts
+++ b/packages/wxt/src/core/utils/content-scripts.ts
@@ -1,6 +1,7 @@
-import type { Manifest, Scripting } from 'wxt/browser';
+import type { Browser } from '@wxt-dev/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,13 +23,14 @@ export function hashContentScriptOptions(
if (simplifiedOptions[key] == null) delete simplifiedOptions[key];
});
- const withDefaults: Manifest.ContentScript = {
+ const withDefaults: ManifestContentScript = {
exclude_globs: [],
exclude_matches: [],
include_globs: [],
match_about_blank: false,
run_at: 'document_idle',
all_frames: false,
+ // @ts-expect-error: Untyped
match_origin_as_fallback: false,
world: 'ISOLATED',
...simplifiedOptions,
@@ -49,7 +51,7 @@ export function mapWxtOptionsToContentScript(
options: ContentScriptEntrypoint['options'],
js: string[] | undefined,
css: string[] | undefined,
-): Manifest.ContentScript {
+): ManifestContentScript {
return {
matches: options.matches ?? [],
all_frames: options.allFrames,
@@ -61,6 +63,7 @@ export function mapWxtOptionsToContentScript(
css,
js,
+ // @ts-expect-error: Untyped
match_origin_as_fallback: options.matchOriginAsFallback,
world: options.world,
};
@@ -70,7 +73,7 @@ export function mapWxtOptionsToRegisteredContentScript(
options: ContentScriptEntrypoint['options'],
js: string[] | undefined,
css: string[] | undefined,
-): Omit {
+): Omit {
return {
allFrames: options.allFrames,
excludeMatches: options.excludeMatches,
diff --git a/packages/wxt/src/core/utils/manifest.ts b/packages/wxt/src/core/utils/manifest.ts
index 364f749f..7b0d3388 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,14 @@ import { normalizePath } from './paths';
import { writeFileIfDifferent } from './fs';
import defu from 'defu';
import { wxt } from '../wxt';
+import { ManifestV3WebAccessibleResource } from './types';
+import type { Browser } from '@wxt-dev/browser';
/**
* Writes the manifest to the output directory and the build output.
*/
export async function writeManifest(
- manifest: Manifest.WebExtensionManifest,
+ manifest: Browser.runtime.Manifest,
output: BuildOutput,
): Promise {
const str =
@@ -49,7 +50,7 @@ export async function writeManifest(
export async function generateManifest(
allEntrypoints: Entrypoint[],
buildOutput: Omit,
-): Promise<{ manifest: Manifest.WebExtensionManifest; warnings: any[][] }> {
+): Promise<{ manifest: Browser.runtime.Manifest; warnings: any[][] }> {
const entrypoints = allEntrypoints.filter((entry) => !entry.skipped);
const warnings: any[][] = [];
@@ -67,7 +68,7 @@ export async function generateManifest(
}
const version = wxt.config.manifest.version ?? simplifyVersion(versionName);
- const baseManifest: Manifest.WebExtensionManifest = {
+ const baseManifest: Browser.runtime.Manifest = {
manifest_version: wxt.config.manifestVersion,
name: pkg?.name,
description: pkg?.description,
@@ -83,10 +84,7 @@ export async function generateManifest(
);
}
- let manifest = defu(
- userManifest,
- baseManifest,
- ) as Manifest.WebExtensionManifest;
+ let manifest = defu(userManifest, baseManifest) as Browser.runtime.Manifest;
// Add reload command in dev mode
if (wxt.config.command === 'serve' && wxt.config.dev.reloadCommand) {
@@ -177,7 +175,7 @@ function simplifyVersion(versionName: string): string {
}
function addEntrypoints(
- manifest: Manifest.WebExtensionManifest,
+ manifest: Browser.runtime.Manifest,
entrypoints: Entrypoint[],
buildOutput: Omit,
): void {
@@ -239,7 +237,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,
@@ -255,7 +252,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,
@@ -279,12 +275,13 @@ function addEntrypoints(
wxt.config.outDir,
'.html',
);
- const options: Manifest.ActionManifest = {};
+ const options: Browser.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 @wxt-dev/browser, but supported by Firefox
options.browser_style = popup.options.browserStyle;
if (manifest.manifest_version === 3) {
manifest.action = {
@@ -314,6 +311,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 @wxt-dev/browser, but supported by Firefox
browser_style:
wxt.config.browser === 'firefox'
? options.options.browserStyle
@@ -332,7 +330,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'),
@@ -359,7 +356,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,
};
@@ -432,7 +428,7 @@ function addEntrypoints(
function discoverIcons(
buildOutput: Omit,
-): Manifest.WebExtensionManifest['icons'] {
+): Browser.runtime.Manifest['icons'] {
const icons: [string, string][] = [];
// prettier-ignore
// #region snippet
@@ -464,7 +460,7 @@ function discoverIcons(
return icons.length > 0 ? Object.fromEntries(icons) : undefined;
}
-function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
+function addDevModeCsp(manifest: Browser.runtime.Manifest): void {
const permission = `http://${wxt.server?.hostname ?? ''}/*`;
const allowedCsp = wxt.server?.origin ?? 'http://localhost:*';
@@ -499,7 +495,7 @@ function addDevModeCsp(manifest: Manifest.WebExtensionManifest): void {
manifest.content_security_policy.sandbox = sandboxCsp.toString();
}
-function addDevModePermissions(manifest: Manifest.WebExtensionManifest) {
+function addDevModePermissions(manifest: Browser.runtime.Manifest) {
// For reloading the page
addPermission(manifest, 'tabs');
@@ -543,8 +539,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;
@@ -554,9 +549,10 @@ export function getContentScriptCssWebAccessibleResources(
resources.push({
resources: [cssFile],
- matches: script.options.matches?.map((matchPattern) =>
- stripPathFromMatchPattern(matchPattern),
- ),
+ matches:
+ script.options.matches?.map((matchPattern) =>
+ stripPathFromMatchPattern(matchPattern),
+ ) ?? [],
});
});
@@ -583,16 +579,18 @@ export function getContentScriptsCssMap(
}
function addPermission(
- manifest: Manifest.WebExtensionManifest,
+ manifest: Browser.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: Browser.runtime.Manifest,
hostPermission: string,
): void {
manifest.host_permissions ??= [];
@@ -618,7 +616,7 @@ export function stripPathFromMatchPattern(pattern: string) {
* targeting MV2, automatically convert their definitions down to the basic MV2 array.
*/
export function convertWebAccessibleResourcesToMv2(
- manifest: Manifest.WebExtensionManifest,
+ manifest: Browser.runtime.Manifest,
): void {
if (manifest.web_accessible_resources == null) return;
@@ -633,17 +631,17 @@ export function convertWebAccessibleResourcesToMv2(
}
function moveHostPermissionsToPermissions(
- manifest: Manifest.WebExtensionManifest,
+ manifest: Browser.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: Browser.runtime.Manifest): void {
if (
manifest.action == null ||
manifest.browser_action != null ||
@@ -654,7 +652,7 @@ function convertActionToMv2(manifest: Manifest.WebExtensionManifest): void {
manifest.browser_action = manifest.action;
}
-function convertCspToMv2(manifest: Manifest.WebExtensionManifest): void {
+function convertCspToMv2(manifest: Browser.runtime.Manifest): void {
if (
typeof manifest.content_security_policy === 'string' ||
manifest.content_security_policy?.extension_pages == null
@@ -668,8 +666,8 @@ function convertCspToMv2(manifest: Manifest.WebExtensionManifest): void {
/**
* Make sure all resources are in MV3 format. If not, add a wanring
*/
-export function validateMv3WebAccessibleResources(
- manifest: Manifest.WebExtensionManifest,
+function validateMv3WebAccessibleResources(
+ manifest: Browser.runtime.Manifest,
): void {
if (manifest.web_accessible_resources == null) return;
@@ -688,7 +686,7 @@ export function validateMv3WebAccessibleResources(
/**
* Remove keys from the manifest based on the build target.
*/
-function stripKeys(manifest: Manifest.WebExtensionManifest): void {
+function stripKeys(manifest: Browser.runtime.Manifest): void {
let keysToRemove: string[] = [];
if (wxt.config.manifestVersion === 2) {
keysToRemove.push(...mv3OnlyKeys);
@@ -699,7 +697,7 @@ function stripKeys(manifest: Manifest.WebExtensionManifest): void {
}
keysToRemove.forEach((key) => {
- delete manifest[key as keyof Manifest.WebExtensionManifest];
+ delete manifest[key as keyof Browser.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 0586d7fb..eeef953b 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 type { Manifest } from 'wxt/browser';
import {
FsCache,
ResolvedConfig,
@@ -27,6 +26,7 @@ import {
import { mock } from 'vitest-mock-extended';
import { vi } from 'vitest';
import { setWxtForTesting } from '../../../core/wxt';
+import type { Browser } from '@wxt-dev/browser';
faker.seed(import.meta.test.SEED);
@@ -208,13 +208,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(),
@@ -299,7 +297,6 @@ export const fakeResolvedConfig = fakeObjectCreator(() => {
transformManifest: () => {},
userConfigMetadata: {},
alias: {},
- extensionApi: 'webextension-polyfill',
entrypointLoader: 'vite-node',
experimental: {},
dev: {
@@ -356,8 +353,8 @@ export const fakeBuildStepOutput = fakeObjectCreator(() => ({
entrypoints: fakeArray(fakeEntrypoint),
}));
-export const fakeManifestCommand =
- fakeObjectCreator(() => ({
+export const fakeManifestCommand = fakeObjectCreator(
+ () => ({
description: faker.string.sample(),
suggested_key: {
default: `${faker.helpers.arrayElement(['ctrl', 'alt'])}+${faker.number.int(
@@ -367,7 +364,8 @@ export const fakeManifestCommand =
},
)}`,
},
- }));
+ }),
+);
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 f6951c61..857fdcff 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 ed6ff200..9755088a 100644
--- a/packages/wxt/src/core/utils/types.ts
+++ b/packages/wxt/src/core/utils/types.ts
@@ -1,3 +1,5 @@
+import type { Browser } from '@wxt-dev/browser';
+
/**
* Remove optional from key, but keep undefined if present
*
@@ -6,3 +8,11 @@
* // type Test = {a: string | undefined, b: number}
*/
export type NullablyRequired = { [K in keyof Required]: T[K] };
+
+export type ManifestContentScript = NonNullable<
+ Browser.runtime.Manifest['content_scripts']
+>[number];
+
+export type ManifestV3WebAccessibleResource = NonNullable<
+ Browser.runtime.ManifestV3['web_accessible_resources']
+>[number];
diff --git a/packages/wxt/src/types.ts b/packages/wxt/src/types.ts
index 187ecb1f..1d6f29bf 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';
@@ -7,6 +6,8 @@ import type { PluginVisualizerOptions } from '@aklinker1/rollup-plugin-visualize
import { ResolvedConfig as C12ResolvedConfig } from 'c12';
import { Hookable, NestedHooks } from 'hookable';
import type * as Nypm from 'nypm';
+import { ManifestContentScript } from './core/utils/types';
+import type { Browser } from '@wxt-dev/browser';
export interface InlineConfig {
/**
@@ -267,7 +268,7 @@ export interface InlineConfig {
* }
* })
*/
- transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
+ transformManifest?: (manifest: Browser.runtime.Manifest) => void;
analysis?: {
/**
* Explicitly include bundle analysis when running `wxt build`. This can be overridden by the
@@ -325,16 +326,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 +435,7 @@ export interface WxtHooks {
}
export interface BuildOutput {
- manifest: Manifest.WebExtensionManifest;
+ manifest: Browser.runtime.Manifest;
publicAssets: OutputAsset[];
steps: BuildStepOutput[];
}
@@ -537,7 +528,7 @@ export interface WxtDevServer
export interface ReloadContentScriptPayload {
registration?: BaseContentScriptEntrypointOptions['registration'];
- contentScript: Omit;
+ contentScript: Omit;
}
export type TargetBrowser = string;
@@ -588,39 +579,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
@@ -868,7 +859,7 @@ export type ResolvedPerBrowserOptions = {
* here, they are configured inline.
*/
export type UserManifest = {
- [key in keyof chrome.runtime.ManifestV3 as key extends
+ [key in keyof Browser.runtime.ManifestV3 as key extends
| 'action'
| 'background'
| 'chrome_url_overrides'
@@ -880,16 +871,16 @@ export type UserManifest = {
| 'sandbox'
| 'web_accessible_resources'
? never
- : key]?: chrome.runtime.ManifestV3[key];
+ : key]?: Browser.runtime.ManifestV3[key];
} & {
// Add any Browser-specific or MV2 properties that WXT supports here
- action?: chrome.runtime.ManifestV3['action'] & {
+ action?: Browser.runtime.ManifestV3['action'] & {
browser_style?: boolean;
};
- browser_action?: chrome.runtime.ManifestV2['browser_action'] & {
+ browser_action?: Browser.runtime.ManifestV2['browser_action'] & {
browser_style?: boolean;
};
- page_action?: chrome.runtime.ManifestV2['page_action'] & {
+ page_action?: Browser.runtime.ManifestV2['page_action'] & {
browser_style?: boolean;
};
browser_specific_settings?: {
@@ -909,12 +900,12 @@ export type UserManifest = {
};
};
permissions?: (
- | chrome.runtime.ManifestPermissions
+ | Browser.runtime.ManifestPermissions
| (string & Record)
)[];
web_accessible_resources?:
| string[]
- | chrome.runtime.ManifestV3['web_accessible_resources'];
+ | Browser.runtime.ManifestV3['web_accessible_resources'];
};
export type UserManifestFn = (
@@ -1187,7 +1178,7 @@ export interface WxtHooks {
*/
'build:manifestGenerated': (
wxt: Wxt,
- manifest: Manifest.WebExtensionManifest,
+ manifest: Browser.runtime.Manifest,
) => HookResult;
/**
* Called once the names and paths of all entrypoints have been resolved.
@@ -1359,7 +1350,7 @@ export interface ResolvedConfig {
/**
* @deprecated Use `build:manifestGenerated` hook instead.
*/
- transformManifest?: (manifest: Manifest.WebExtensionManifest) => void;
+ transformManifest?: (manifest: Browser.runtime.Manifest) => void;
analysis: {
enabled: boolean;
open: boolean;
@@ -1377,7 +1368,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/utils/reload-content-scripts.ts b/packages/wxt/src/virtual/utils/reload-content-scripts.ts
index 11b5e0c8..3b82417a 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 5199a83a..0b70bcf1 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 { browser, Browser } from '@wxt-dev/browser';
}
declare module 'virtual:wxt-plugins' {
diff --git a/packages/wxt/typedoc.json b/packages/wxt/typedoc.json
index d9edaddf..fa919313 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/modules.ts",
"src/storage.ts"
diff --git a/packages/wxt/vitest.config.ts b/packages/wxt/vitest.config.ts
index 8bb1d0da..0c25b962 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 00000000..a828762f
--- /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 d461ccb5..ce82ef83 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -57,9 +57,6 @@ catalogs:
'@types/ua-parser-js':
specifier: ^0.7.39
version: 0.7.39
- '@types/webextension-polyfill':
- specifier: ^0.12.1
- version: 0.12.1
'@vitejs/plugin-react':
specifier: ^4.3.4
version: 4.3.4
@@ -297,9 +294,6 @@ catalogs:
web-ext-run:
specifier: ^0.2.1
version: 0.2.1
- webextension-polyfill:
- specifier: ^0.12.0
- version: 0.12.0
patchedDependencies:
markdown-it-footnote:
@@ -698,12 +692,6 @@ importers:
'@aklinker1/rollup-plugin-visualizer':
specifier: 'catalog:'
version: 5.12.0(rollup@4.34.9)
- '@types/chrome':
- specifier: 'catalog:'
- version: 0.0.280
- '@types/webextension-polyfill':
- specifier: 'catalog:'
- version: 0.12.1
'@webext-core/fake-browser':
specifier: 'catalog:'
version: 1.3.1
@@ -713,6 +701,9 @@ importers:
'@webext-core/match-patterns':
specifier: 'catalog:'
version: 1.0.3
+ '@wxt-dev/browser':
+ specifier: workspace:*
+ version: link:../browser
'@wxt-dev/storage':
specifier: workspace:^1.0.0
version: link:../storage
@@ -833,9 +824,6 @@ importers:
web-ext-run:
specifier: 'catalog:'
version: 0.2.1
- webextension-polyfill:
- specifier: 'catalog:'
- version: 0.12.0
devDependencies:
'@aklinker1/check':
specifier: 'catalog:'
@@ -2324,9 +2312,6 @@ packages:
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
- '@types/webextension-polyfill@0.12.1':
- resolution: {integrity: sha512-xPTFWwQ8BxPevPF2IKsf4hpZNss4LxaOLZXypQH4E63BDLmcwX/RMGdI4tB4VO4Nb6xDBH3F/p4gz4wvof1o9w==}
-
'@types/yauzl@2.10.3':
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
@@ -5365,9 +5350,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'}
@@ -6664,8 +6646,6 @@ snapshots:
'@types/web-bluetooth@0.0.20': {}
- '@types/webextension-polyfill@0.12.1': {}
-
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 20.17.6
@@ -10092,8 +10072,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 d1e35387..429f2b90 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 0a5a994f..1cc7596d 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 f0e4f9aa..5749b4e6 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 35c7ade7..1e2f53d3 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 2ab714b1..55fbc4af 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'],
});