Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Remove webextension-polyfill #1084

Merged
merged 12 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 12 additions & 35 deletions docs/guide/essentials/extension-apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 0 additions & 1 deletion packages/wxt-demo/wxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { defineConfig } from 'wxt';

export default defineConfig({
srcDir: 'src',
extensionApi: 'chrome',
manifest: {
permissions: ['storage'],
default_locale: 'en',
Expand Down
2 changes: 2 additions & 0 deletions packages/wxt/e2e/tests/auto-imports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ describe('Auto Imports', () => {
/// <reference types="./types/paths.d.ts" />
/// <reference types="./types/i18n.d.ts" />
/// <reference types="./types/globals.d.ts" />
/// <reference types="@types/chrome" />
/// <reference types="./types/imports.d.ts" />
"
`);
Expand Down Expand Up @@ -93,6 +94,7 @@ describe('Auto Imports', () => {
/// <reference types="./types/paths.d.ts" />
/// <reference types="./types/i18n.d.ts" />
/// <reference types="./types/globals.d.ts" />
/// <reference types="@types/chrome" />
"
`,
);
Expand Down
20 changes: 4 additions & 16 deletions packages/wxt/e2e/tests/modules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Expand All @@ -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);
});
Expand All @@ -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);
});
Expand All @@ -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);
});
Expand Down
6 changes: 0 additions & 6 deletions packages/wxt/e2e/tests/output-structure.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions packages/wxt/e2e/tests/typescript-project.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ describe('TypeScript Project', () => {
/// <reference types="./types/paths.d.ts" />
/// <reference types="./types/i18n.d.ts" />
/// <reference types="./types/globals.d.ts" />
/// <reference types="@types/chrome" />
/// <reference types="./types/imports.d.ts" />
"
`);
Expand Down
19 changes: 0 additions & 19 deletions packages/wxt/e2e/tests/user-config.test.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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(
Expand Down
12 changes: 3 additions & 9 deletions packages/wxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
19 changes: 13 additions & 6 deletions packages/wxt/src/browser/chrome.ts → packages/wxt/src/browser.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
/// <reference types="chrome" />
/**
* 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<typeof chrome, 'runtime' | 'i18n'> & {
runtime: WxtRuntime & Omit<(typeof chrome)['runtime'], 'getURL'>;
Expand Down
88 changes: 0 additions & 88 deletions packages/wxt/src/browser/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 0 additions & 1 deletion packages/wxt/src/core/builders/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Loading