Skip to content

Extension APIs

Chrome 文档Firefox 文档

不同的浏览器提供不同的全局变量来访问扩展 API(Chrome 提供 chrome,Firefox 提供 browser,等等)。

WXT 将这些统一合并为一个通过 browser 变量访问的 API。

ts
import { browser } from 'wxt/browser';

browser.action.onClicked.addListener(() => {
  // ...
});

TIP

启用自动导入后,你甚至不需要从 wxt/browser 中导入这个变量!

WXT 提供的 browser 变量是浏览器在运行时提供的 browserchrome 全局变量的简单导出:

mjs
export const browser = globalThis.browser?.runtime?.id
  ? globalThis.browser
  : globalThis.chrome;

这意味着你可以在 MV2 和 MV3 中使用 Promise 风格的 API,并且它可以在所有浏览器(Chromium、Firefox、Safari 等)中正常工作。

访问类型

所有类型都可以通过 WXT 的 Browser 命名空间访问:

ts
import { type Browser } from 'wxt/browser';

function handleMessage(message: any, sender: Browser.runtime.MessageSender) {
  // ...
}

使用 webextension-polyfill

如果你想在导入 browser 时使用 webextension-polyfill,可以通过安装 @wxt-dev/webextension-polyfill 包来实现。

请参阅其安装指南以开始使用。

特性检测

根据 Manifest 版本、浏览器和权限的不同,某些 API 在运行时可能不可用。如果某个 API 不可用,它将是 undefined

WARNING

类型在这里帮不了你。WXT 为 browser 提供的类型假定所有 API 都存在。你需要自行判断某个 API 是否可用。

要检查某个 API 是否可用,请使用特性检测:

ts
if (browser.runtime.onSuspend != null) {
  browser.runtime.onSuspend.addListener(() => {
    // ...
  });
}

在这里,可选链是你最好的帮手:

ts
browser.runtime.onSuspend?.addListener(() => {
  // ...
});

或者,如果你想使用不同名称的类似 API(以同时支持 MV2 和 MV3),可以这样做:

ts
(browser.action ?? browser.browser_action).onClicked.addListener(() => {
  //
});

扩展 Browser 类型

WXT 的 browser 类型基于 @types/chrome 包。这意味着某些 Firefox 特有的 API 可能没有类型定义,例如 browser.sidebarAction。如果你想为这些 API 添加类型,可以通过类型扩展自行添加:

ts
// <srcDir>/browser-types.d.ts
import '@wxt-dev/browser';
import type { SidebarAction } from 'webextension-polyfill';

declare module '@wxt-dev/browser' {
  namespace Browser {
    export const sidebarAction: SidebarAction.Static;
  }
}

为了使其正常工作,你可能需要将 @wxt-dev/browser 作为直接依赖安装。

sh
pnpm add @wxt-dev/browser

入口点限制

由于 WXT 会在 NodeJS 非扩展环境中导入你的入口点文件,浏览器提供给扩展的 chrome/browser 变量将不可用

为了防止一些基本错误,WXT 使用与测试相同的内存中假实现来填充这些全局变量:@webext-core/fake-browser。但是,并非所有 API 都已实现。

因此,非常重要的一点是:永远不要在任何 JS/TS 入口点(Background、Content Script 和 Unlisted Script)的主函数之外使用 browser.* 扩展 API。否则,你会看到如下错误:

plaintext
✖ Command failed after 440 ms

 ERROR  Browser.action.onClicked.addListener not implemented.

修复方法很简单,只需将 API 的使用移到入口点的主函数中:

ts
browser.action.onClicked.addListener(() => {
  /* ... */
}); 

export default defineBackground(() => {
  browser.action.onClicked.addListener(() => {
    /* ... */
  }); 
});
ts
browser.runtime.onMessage.addListener(() => {
  /* ... */
}); 

export default defineContentScript({
  main() {
    browser.runtime.onMessage.addListener(() => {
      /* ... */
    }); 
  },
});
ts
browser.runtime.onMessage.addListener(() => {
  /* ... */
}); 

export default defineUnlistedScript(() => {
  browser.runtime.onMessage.addListener(() => {
    /* ... */
  }); 
});

阅读入口点加载器以了解有关此限制的更多技术细节。