diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 2e971e4f..c4fb5680 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -16,6 +16,7 @@ on:
- module-vue
- storage
- unocss
+ - webextension-polyfill
- wxt
permissions:
diff --git a/.github/workflows/sync-releases.yml b/.github/workflows/sync-releases.yml
index 3d0663fa..7e6ddca0 100644
--- a/.github/workflows/sync-releases.yml
+++ b/.github/workflows/sync-releases.yml
@@ -15,6 +15,7 @@ on:
- module-svelte
- module-vue
- storage
+ - webextension-polyfill
- wxt
permissions:
diff --git a/docs/guide/essentials/extension-apis.md b/docs/guide/essentials/extension-apis.md
index 5d0187b9..89b58115 100644
--- a/docs/guide/essentials/extension-apis.md
+++ b/docs/guide/essentials/extension-apis.md
@@ -36,6 +36,12 @@ function handleMessage(message: any, sender: Browser.runtime.MessageSender) {
}
```
+## Using `webextension-polyfill`
+
+If you want to use the `webextension-polyfill` when importing `browser`, you can do so by installing the `@wxt-dev/webextension-polyfill` package.
+
+See it's [Installation Guide](https://github.com/wxt-dev/wxt/blob/main/packages/webextension-polyfill/README.md) to get started.
+
## Feature Detection
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`.
diff --git a/docs/guide/resources/upgrading.md b/docs/guide/resources/upgrading.md
index e7ed8d1d..44b40d55 100644
--- a/docs/guide/resources/upgrading.md
+++ b/docs/guide/resources/upgrading.md
@@ -31,12 +31,11 @@ WXT no longer uses the `webextension-polyfill` internally and `wxt/browser` uses
To upgrade, you have two options:
1. **Stop using the polyfill**
- - No changes required, this is the default behavior of v0.20. Your extension will likely continue to work, but do some manual testing to confirm.
+ - Replace any manual imports from `wxt/browser/chrome` with `wxt/browser`
2. **Continue using the polyfill**
- - Install the polyfill, types (if you use typescript), and WXT's [new polyfill module](https://www.npmjs.com/package/@wxt-dev/webextension-polyfill):
+ - Install the polyfill and WXT's [new polyfill module](https://www.npmjs.com/package/@wxt-dev/webextension-polyfill):
```sh
- pnpm i webextension-polyfill
- pnpm i -D @types/webextension-polyfill @wxt-dev/webextension-polyfill
+ pnpm i webextension-polyfill @wxt-dev/webextension-polyfill
```
- Add the WXT module to your config:
```ts
@@ -46,7 +45,7 @@ To upgrade, you have two options:
});
```
-Additionally, the `extensionApi` config has been removed. Remove it from your `wxt.config.ts` file if present:
+Regardless of your choice, the `extensionApi` config has been removed. Remove it from your `wxt.config.ts` file if present:
```ts
// wxt.config.ts
@@ -55,6 +54,21 @@ export default defineConfig({
});
```
+Additionally, extension API types have changed. `wxt/browser` now uses types from `@types/chrome` instead of `@types/webextension-polyfill`. You will have to migrate any type imports to use `@types/chrome`'s namespace approach:
+
+
+```ts
+import type { Runtime } from 'wxt/browser'; // [!code --]
+import { browser } from 'wxt/browser'; // [!code ++]
+
+function getMessageSenderUrl(sender: Runtime.MessageSender): string { // [!code --]
+function getMessageSenderUrl(sender: browser.runtime.MessageSender): string { // [!code ++]
+ // ...
+}
+```
+
+`@types/chrome` are more up-to-date, contain less bugs, and don't have any auto-generated names. So even if you continue to use the polyfill, you will need to update your types to use these types.
+
### `public/` and `modules/` Directories Moved
The default location for the `public/` and `modules/` directories have changed to better align with standards set by other frameworks (Nuxt, Next, Astro, etc). Now, each path is relative to the project's root directory.
diff --git a/packages/webextension-polyfill/README.md b/packages/webextension-polyfill/README.md
new file mode 100644
index 00000000..8dffa772
--- /dev/null
+++ b/packages/webextension-polyfill/README.md
@@ -0,0 +1,18 @@
+# `@wxt-dev/webextension-polyfill`
+
+Configures `wxt/browser` to import `browser` from [`webextension-polyfill`](https://github.com/mozilla/webextension-polyfill) instead of using the regular `chrome`/`browser` globals WXT normally provides.
+
+## Usage
+
+```sh
+pnpm i @wxt-dev/webextension-polyfill webextension-polyfill
+```
+
+Then add the module to your config:
+
+```ts
+// wxt.config.ts
+export default defineConfig({
+ modules: ['@wxt-dev/webextension-polyfill'],
+});
+```
diff --git a/packages/webextension-polyfill/build.config.ts b/packages/webextension-polyfill/build.config.ts
new file mode 100644
index 00000000..64a6c1bf
--- /dev/null
+++ b/packages/webextension-polyfill/build.config.ts
@@ -0,0 +1,15 @@
+import { defineBuildConfig } from 'unbuild';
+import { resolve } from 'node:path';
+
+export default defineBuildConfig({
+ rootDir: resolve(__dirname, 'modules/webextension-polyfill'),
+ outDir: resolve(__dirname, 'dist'),
+ entries: [
+ { input: 'index.ts', name: 'index' },
+ { input: 'browser.ts', name: 'browser' },
+ ],
+ replace: {
+ 'process.env.NPM': 'true',
+ },
+ declaration: true,
+});
diff --git a/packages/webextension-polyfill/entrypoints/content/index.ts b/packages/webextension-polyfill/entrypoints/content/index.ts
new file mode 100644
index 00000000..87ad9f39
--- /dev/null
+++ b/packages/webextension-polyfill/entrypoints/content/index.ts
@@ -0,0 +1,6 @@
+export default defineContentScript({
+ matches: ['*://*/*'],
+ async main() {
+ console.log(browser.runtime.id);
+ },
+});
diff --git a/packages/webextension-polyfill/entrypoints/popup/index.html b/packages/webextension-polyfill/entrypoints/popup/index.html
new file mode 100644
index 00000000..a6d6644f
--- /dev/null
+++ b/packages/webextension-polyfill/entrypoints/popup/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
diff --git a/packages/webextension-polyfill/entrypoints/popup/main.ts b/packages/webextension-polyfill/entrypoints/popup/main.ts
new file mode 100644
index 00000000..3677c7ed
--- /dev/null
+++ b/packages/webextension-polyfill/entrypoints/popup/main.ts
@@ -0,0 +1,3 @@
+const root = document.getElementById('app')!;
+
+root.textContent = browser.runtime.id;
diff --git a/packages/webextension-polyfill/modules/webextension-polyfill/browser.ts b/packages/webextension-polyfill/modules/webextension-polyfill/browser.ts
new file mode 100644
index 00000000..c86e9ce3
--- /dev/null
+++ b/packages/webextension-polyfill/modules/webextension-polyfill/browser.ts
@@ -0,0 +1 @@
+export { default as browser } from 'webextension-polyfill';
diff --git a/packages/webextension-polyfill/modules/webextension-polyfill/index.ts b/packages/webextension-polyfill/modules/webextension-polyfill/index.ts
new file mode 100644
index 00000000..6114cad1
--- /dev/null
+++ b/packages/webextension-polyfill/modules/webextension-polyfill/index.ts
@@ -0,0 +1,18 @@
+import 'wxt';
+import { addViteConfig, defineWxtModule } from 'wxt/modules';
+import { resolve } from 'node:path';
+
+export default defineWxtModule({
+ name: '@wxt-dev/webextension-polyfill',
+ setup(wxt) {
+ addViteConfig(wxt, () => ({
+ resolve: {
+ alias: {
+ 'wxt/browser': process.env.NPM
+ ? '@wxt-dev/webextension-polyfill/browser'
+ : resolve(__dirname, 'browser.ts'),
+ },
+ },
+ }));
+ },
+});
diff --git a/packages/webextension-polyfill/package.json b/packages/webextension-polyfill/package.json
new file mode 100644
index 00000000..fb7c8d5a
--- /dev/null
+++ b/packages/webextension-polyfill/package.json
@@ -0,0 +1,56 @@
+{
+ "name": "@wxt-dev/webextension-polyfill",
+ "description": "Use webextension-polyfill with WXT",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/wxt-dev/wxt.git",
+ "directory": "packages/webextension-polyfill"
+ },
+ "homepage": "https://github.com/wxt-dev/wxt/blob/main/packages/webextension-polyfill/README.md",
+ "keywords": [
+ "wxt",
+ "module",
+ "webextension-polyfill"
+ ],
+ "author": {
+ "name": "Aaron Klinker",
+ "email": "aaronklinker1+wxt@gmail.com"
+ },
+ "license": "MIT",
+ "version": "1.0.0",
+ "type": "module",
+ "main": "./dist/index.mjs",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.mts",
+ "default": "./dist/index.mjs"
+ },
+ "./browser": {
+ "types": "./dist/browser.d.mts",
+ "default": "./dist/browser.mjs"
+ }
+ },
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "dev": "wxt",
+ "check": "pnpm build && check",
+ "build": "buildc -- unbuild",
+ "prepare": "buildc --deps-only -- wxt prepare"
+ },
+ "peerDependencies": {
+ "webextension-polyfill": "*",
+ "wxt": ">=0.20.0"
+ },
+ "devDependencies": {
+ "@aklinker1/check": "catalog:",
+ "@types/webextension-polyfill": "catalog:",
+ "publint": "catalog:",
+ "typescript": "catalog:",
+ "unbuild": "catalog:",
+ "webextension-polyfill": "catalog:",
+ "wxt": "workspace:*"
+ }
+}
diff --git a/packages/webextension-polyfill/public/.keep b/packages/webextension-polyfill/public/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/webextension-polyfill/tsconfig.json b/packages/webextension-polyfill/tsconfig.json
new file mode 100644
index 00000000..cde6e0a8
--- /dev/null
+++ b/packages/webextension-polyfill/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ "extends": ["../../tsconfig.base.json", "./.wxt/tsconfig.json"],
+ "exclude": ["node_modules/**", "dist/**"]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9dcf32f0..dbbc7c73 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -57,6 +57,9 @@ catalogs:
'@types/ua-parser-js':
specifier: ^0.7.39
version: 0.7.39
+ '@types/webextension-polyfill':
+ specifier: ^0.12.1
+ version: 0.12.3
'@vitejs/plugin-react':
specifier: ^4.3.4
version: 4.3.4
@@ -294,6 +297,9 @@ 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:
@@ -687,6 +693,30 @@ importers:
specifier: workspace:*
version: link:../wxt
+ packages/webextension-polyfill:
+ devDependencies:
+ '@aklinker1/check':
+ specifier: 'catalog:'
+ version: 1.4.5(typescript@5.6.3)
+ '@types/webextension-polyfill':
+ specifier: 'catalog:'
+ version: 0.12.3
+ publint:
+ specifier: 'catalog:'
+ version: 0.2.12
+ typescript:
+ specifier: 'catalog:'
+ version: 5.6.3
+ unbuild:
+ specifier: 'catalog:'
+ version: 3.5.0(sass@1.80.7)(typescript@5.6.3)(vue@3.5.13(typescript@5.6.3))
+ webextension-polyfill:
+ specifier: 'catalog:'
+ version: 0.12.0
+ wxt:
+ specifier: workspace:*
+ version: link:../wxt
+
packages/wxt:
dependencies:
'@1natsu/wait-element':
@@ -2312,6 +2342,9 @@ packages:
'@types/web-bluetooth@0.0.20':
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
+ '@types/webextension-polyfill@0.12.3':
+ resolution: {integrity: sha512-F58aDVSeN/MjUGazXo/cPsmR76EvqQhQ1v4x23hFjUX0cfAJYE+JBWwiOGW36/VJGGxoH74sVlRIF3z7SJCKyg==}
+
'@types/yauzl@2.10.3':
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
@@ -5354,6 +5387,9 @@ 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'}
@@ -6654,6 +6690,8 @@ snapshots:
'@types/web-bluetooth@0.0.20': {}
+ '@types/webextension-polyfill@0.12.3': {}
+
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 20.17.6
@@ -10084,6 +10122,8 @@ snapshots:
- supports-color
- utf-8-validate
+ webextension-polyfill@0.12.0: {}
+
webidl-conversions@7.0.0: {}
webpack-sources@3.2.3: