升级 WXT
概述
要将 WXT 升级到最新的主版本:
安装时跳过脚本,这样
wxt prepare就不会运行——在主版本变更后它可能会抛出错误(我们稍后再运行)。shpnpm i wxt@latest --ignore-scripts按照下面的升级步骤修复所有破坏性变更。
运行
wxt prepare。它应该能成功执行,之后类型错误将会消失。shpnpm wxt prepare手动测试确保开发模式和生产构建都能正常工作。
对于次版本或补丁版本更新,没有特殊步骤。只需使用包管理器更新即可:
pnpm i wxt@latest以下列出了升级到新版本 WXT 时需要处理的所有破坏性变更。
目前,WXT 处于预发布阶段。这意味着第二位数字的变更(v0.X)被视为主版本变更,包含破坏性变更。一旦 v1 发布,只有主版本号的变更才会包含破坏性变更。
v0.19.0 → v0.20.0
v0.20 是一个重大版本!有许多破坏性变更,因为这个版本旨在作为 v1.0 的候选发布版本。如果一切顺利,v1.0 将不会有额外的破坏性变更。
TIP
在更新代码之前,请先通读所有变更。
webextension-polyfill 已移除
WXT 的 browser 不再使用 webextension-polyfill!
要升级,你有两个选择:
停止使用 polyfill
如果你已经在使用
extensionApi: "chrome",那么你没有在使用 polyfill,无需任何更改!否则只有一个变更:
browser.runtime.onMessage不再支持使用 Promise 来返回响应:tsbrowser.runtime.onMessage.addListener(async () => { const res = await someAsyncWork(); return res; browser.runtime.onMessage.addListener(async (_message, _sender, sendResponse) => { someAsyncWork().then((res) => { sendResponse(res); }); return true; });
继续使用 polyfill - 如果你想继续使用 polyfill,完全可以!在本次升级中可以少操心一件事。
安装
webextension-polyfill和 WXT 的新 polyfill 模块:shpnpm i webextension-polyfill @wxt-dev/webextension-polyfill将 WXT 模块添加到你的配置中:
tsexport default defineConfig({ modules: ['@wxt-dev/webextension-polyfill'], });
新的 browser 对象(及类型)由 WXT 的新包 @wxt-dev/browser 提供支持。这个包延续了 WXT 为整个社区提供实用包的使命。就像 @wxt-dev/storage、@wxt-dev/i18n、@wxt-dev/analytics 一样,它被设计为可以在任何 Web 扩展项目中轻松使用,而不仅仅是使用 WXT 的项目,并在所有浏览器和 Manifest 版本之间提供一致的 API。
extensionApi 配置已移除
extensionApi 配置已被移除。之前,此配置提供了一种在 v0.20.0 之前选择使用新 browser 对象的方式。
如果存在的话,请从你的 wxt.config.ts 文件中移除它:
export default defineConfig({
extensionApi: 'chrome',
});Extension API 类型变更
随着 v0.20 引入的新 browser,访问类型的方式发生了变化。WXT 现在基于 @types/chrome 而非 @types/webextension-polyfill 提供类型。
这些类型对 MV3 API 更加新,包含更少的 bug,组织更好,并且没有任何自动生成的名称。
要访问类型,请使用来自 wxt/browser 的新 Browser 命名空间:
import type { Runtime } from 'wxt/browser';
import type { Browser } from 'wxt/browser';
function getMessageSenderUrl(sender: Runtime.MessageSender): string {
function getMessageSenderUrl(sender: Browser.runtime.MessageSender): string {
// ...
}如果你使用自动导入,
Browser将无需手动导入即可使用。
并非所有类型名称都与 @types/webextension-polyfill 提供的相同。你需要通过查看所使用的 browser.* API 的类型来找到新的类型名称。
public/ 和 modules/ 目录已移动
public/ 和 modules/ 目录的默认位置已更改,以更好地与其他框架(Nuxt、Next、Astro 等)设定的标准保持一致。现在,每个路径都相对于项目的根目录,而非 src 目录。
- 如果你遵循默认的文件夹结构,则无需做任何更改。
- 如果你设置了自定义的
srcDir,你有两个选择:将你的
public/和modules/目录移到项目根目录:html📂 {rootDir}/ 📁 modules/ 📁 public/ 📂 src/ 📁 components/ 📁 entrypoints/ 📁 modules/ 📁 public/ 📁 utils/ 📄 app.config.ts 📄 wxt.config.ts保持文件夹在原位并更新项目配置:
tsexport default defineConfig({ srcDir: 'src', publicDir: 'src/public', modulesDir: 'src/modules', });
导入路径变更和 #imports
wxt/sandbox、wxt/client 或 wxt/storage 导出的 API 已移至 wxt/utils/* 路径下的各个独立导出。
为什么?
随着 WXT 的增长和更多工具的添加,任何带有副作用的辅助工具都不会从最终包中被 tree-shaking 掉。
这可能会导致问题,因为并非每种类型的入口点都可以使用这些副作用所用的所有 API。某些 API 只能在后台使用,沙盒页面不能使用任何扩展 API,等等。这导致 JS 在顶层作用域中抛出错误,阻止你的代码运行。
将每个工具拆分为独立的模块可以解决这个问题,确保你只将 API 和副作用导入到它们可以运行的入口点中。
请参阅更新后的 API 参考 查看新导入路径的列表。
不过,你不需要记忆或学习新的导入路径!v0.20 引入了一个新的虚拟模块 #imports,它将所有这些从开发者那里抽象出来。有关此模块如何工作的更多详细信息,请参阅博客文章。
因此,要升级,只需将从 wxt/storage、wxt/client 和 wxt/sandbox 的任何导入替换为新的 #imports 模块:
import { storage } from 'wxt/storage';
import { defineContentScript } from 'wxt/sandbox';
import { ContentScriptContext, useAppConfig } from 'wxt/client';
import { storage } from '#imports';
import { defineContentScript } from '#imports';
import { ContentScriptContext, getAppConfig } from '#imports'; 你可以将导入合并为单个导入语句,但直接查找/替换每个语句更简单。
import { storage } from 'wxt/storage';
import { defineContentScript } from 'wxt/sandbox';
import { ContentScriptContext, useAppConfig } from 'wxt/client';
import {
storage,
defineContentScript,
ContentScriptContext,
getAppConfig,
} from '#imports'; TIP
在类型生效之前,你需要在安装 v0.20 后运行 wxt prepare 来生成新的 TypeScript 声明。
createShadowRootUi CSS 变更
WXT 现在通过在 Shadow Root 内设置 all: initial 来重置从网页继承的样式(visibility、color、font-size 等)。
WARNING
这不影响 rem 单位。如果网页设置了 HTML 元素的 font-size,你应该继续使用 postcss-rem-to-px 或等效的库。
如果你使用 createShadowRootUi:
移除任何手动重置特定网站样式的 CSS 覆盖。例如:
cssbody { /* 覆盖 Reddit 对元素默认的 "hidden" visibility */ visibility: visible !important; }仔细检查你的 UI 是否与之前看起来一样。
如果你遇到新行为的问题,可以禁用它并继续使用当前的 CSS:
const ui = await createShadowRootUi({
inheritStyles: true,
// ...
});默认输出目录变更
outDirTemplate 配置的默认值已更改。现在,不同的构建模式会输出到不同的目录:
--mode production→.output/chrome-mv3:生产构建不变--mode development→.output/chrome-mv3-dev:开发模式现在有-dev后缀,这样就不会覆盖生产构建--mode custom→.output/chrome-mv3-custom:其他自定义模式以-[mode]后缀结尾
要使用旧行为(将所有输出写入同一目录),请设置 outDirTemplate 选项:
export default defineConfig({
outDirTemplate: '{{browser}}-mv{{manifestVersion}}',
});WARNING
如果你之前在开发时手动将扩展加载到浏览器中,你需要从新的开发输出目录卸载并重新安装。
已弃用的 API 已移除
entrypointLoader选项:WXT 现在使用vite-node在构建过程中导入入口点。这在 v0.19.0 中已弃用,请参阅 v0.19 章节 了解迁移步骤。
transformManifest选项:请改用build:manifestGenerated钩子来转换 manifest:tsexport default defineConfig({ transformManifest(manifest) { hooks: { 'build:manifestGenerated': (_, manifest) => { // ... }, }, });
新的弃用项
runner API 已重命名
为了与 web-ext.config.ts 文件名保持一致性,"runner" API 和配置选项已被重命名。你可以继续使用旧名称,但它们已被弃用,将在未来版本中移除:
runner选项已重命名为webExt:tsexport default defineConfig({ runner: { webExt: { startUrls: ["https://wxt.dev"], }, });defineRunnerConfig已重命名为defineWebExtConfig:tsimport { defineRunnerConfig } from 'wxt'; import { defineWebExtConfig } from 'wxt';ExtensionRunnerConfig类型已重命名为WebExtConfigtsimport type { ExtensionRunnerConfig } from 'wxt'; import type { WebExtConfig } from 'wxt';
v0.18.5 → v0.19.0
vite-node 入口点加载器
默认的入口点加载器已更改为 vite-node。如果你使用了依赖 webextension-polyfill 的 NPM 包,你需要将它们添加到 Vite 的 ssr.noExternal 选项中:
export default defineConfig({
vite: () => ({
ssr: {
noExternal: ['@webext-core/messaging', '@webext-core/proxy-service'],
},
}),
});阅读完整文档 了解更多信息。
此变更启用了以下功能:
导入变量并在入口点选项中使用它们:
import { GOOGLE_MATCHES } from '~/utils/constants'
export default defineContentScript({
matches: [GOOGLE_MATCHES],
main: () => ...,
})使用 Vite 特定的 API(如 import.meta.glob)来定义入口点选项:
const providers: Record<string, any> = import.meta.glob('../providers/*', {
eager: true,
});
export default defineContentScript({
matches: Object.values(providers).flatMap(
(provider) => provider.default.paths,
),
async main() {
console.log('Hello content.');
},
});基本上,你现在可以在入口点的 main 函数之外导入和执行操作了——以前不能这样做。不过要小心,仍然建议避免在 main 函数之外运行代码,以保持构建速度。
要继续使用旧方式,请在 wxt.config.ts 文件中添加以下内容:
export default defineConfig({
entrypointLoader: 'jiti',
});WARNING
entrypointLoader: "jiti" 已弃用,将在下一个主版本中移除。
取消 CJS 支持
WXT 不再附带 Common JS 支持。如果你在使用 CJS,以下是迁移步骤:
- 在你的
package.json中添加"type": "module"。 - 将使用 CJS 语法的
.js文件扩展名更改为.cjs,或更新它们以使用 ESM 语法。
Vite 也提供了迁移到 ESM 的步骤。查看更多详情:https://vitejs.dev/guide/migration#deprecate-cjs-node-api
v0.18.0 → v0.18.5
当此版本发布时,它并未被视为破坏性变更……但实际上应该是。
新的 modules/ 目录
WXT 现在将 modules/ 目录识别为包含 WXT 模块 的文件夹。
如果你已经有 <srcDir>/modules 或 <srcDir>/Modules 目录,wxt prepare 和其他命令将会失败。
你有两个选择:
[推荐] 保持文件在原位,让 WXT 在不同的文件夹中查找:
tsexport default defineConfig({ modulesDir: 'wxt-modules', // 默认为 "modules" });将你的
modules目录重命名为其他名称。
v0.17.0 → v0.18.0
自动将 MV3 host_permissions 转换为 MV2 permissions
出于谨慎考虑,此变更被标记为破坏性变更,因为权限生成方式不同。
如果你在 wxt.config.ts 的 manifest 中列出了 host_permissions 并且已发布你的扩展,请仔细检查你在 .output/*/manifest.json 文件中针对所有目标浏览器的 permissions 和 host_permissions 是否有变化。权限变更可能导致扩展在更新时被禁用,并可能导致用户流失,因此请务必与之前的 manifest 版本进行对比检查。
v0.16.0 → v0.17.0
Storage - defineItem 需要 defaultValue 选项
如果你之前使用了带版本控制但没有默认值的 defineItem,你需要在选项中添加 defaultValue: null 并更新第一个类型参数:
const item = storage.defineItem<number>("local:count", {
const item = storage.defineItem<number | null>("local:count", {
defaultValue: null,
version: ...,
migrations: ...,
})如果传入第二个选项参数,defaultValue 属性现在是必需的。
如果你省略第二个选项参数,它将默认为可空的,与之前一样。
const item: WxtStorageItem<number | null> =
storage.defineItem<number>('local:count');
const value: number | null = await item.getValue();Storage - 修复 watch 回调中的类型
如果你不使用 TypeScript,这不是破坏性变更,这只是类型变更。
const item = storage.defineItem<number>('local:count', { defaultValue: 0 });
item.watch((newValue: number | null, oldValue: number | null) => {
item.watch((newValue: number, oldValue: number) => {
// ...
});v0.15.0 → v0.16.0
输出目录结构变更
输出目录中的 JS 入口点已被移动。除非你在做某种引用文件的构建后工作,否则不需要做任何更改。
.output/
<target>/
chunks/
some-shared-chunk-<hash>.js
popup-<hash>.js // [!code --]
popup.html
popup.html
popup.js // [!code ++]v0.14.0 → v0.15.0
zip.ignoredSources 重命名为 zip.excludeSources
export default defineConfig({
zip: {
ignoredSources: [
/*...*/
],
excludeSources: [
/*...*/
],
},
});未文档化的常量已重命名
在 #380 中重命名了用于在运行时检测构建配置的未文档化常量。现在已记录在此:https://wxt.dev/guide/multiple-browsers.html#runtime
__BROWSER__→import.meta.env.BROWSER__COMMAND__→import.meta.env.COMMAND__MANIFEST_VERSION__→import.meta.env.MANIFEST_VERSION__IS_CHROME__→import.meta.env.CHROME__IS_FIREFOX__→import.meta.env.FIREFOX__IS_SAFARI__→import.meta.env.SAFARI__IS_EDGE__→import.meta.env.EDGE__IS_OPERA__→import.meta.env.OPERA
v0.13.0 → v0.14.0
Content Script UI API 变更
createContentScriptUi 和 createContentScriptIframe 及其部分选项已被重命名:
createContentScriptUi({ ... })→createShadowRootUi({ ... })createContentScriptIframe({ ... })→createIframeUi({ ... })type: "inline" | "overlay" | "modal"已更改为position: "inline" | "overlay" | "modal"onRemove现在在 UI 从 DOM 中移除之前调用,之前是在 UI 移除之后调用mount选项已重命名为onMount,以更好地与相关选项onRemove匹配。
v0.12.0 → v0.13.0
新的 wxt/storage API
wxt/storage 不再依赖 unstorage。一些 unstorage API(如 prefixStorage)已被移除,而其他的(如 snapshot)是新 storage 对象上的方法。大部分标准用法保持不变。详情请参阅 https://wxt.dev/guide/storage 和 https://wxt.dev/api/reference/wxt/storage/(#300)
v0.11.0 → v0.12.0
API 导出变更
defineContentScript 和 defineBackground 现在从 wxt/sandbox 而非 wxt/client 导出。(#284)
如果你使用自动导入,则无需更改。
如果你禁用了自动导入,你需要手动更新导入语句:
tsimport { defineBackground, defineContentScript } from 'wxt/client'; import { defineBackground, defineContentScript } from 'wxt/sandbox';
v0.10.0 → v0.11.0
Vite 5
你需要将其他 Vite 插件更新到支持 Vite 5 的版本。
v0.9.0 → v0.10.0
扩展图标发现
WXT 不再发现 .png 以外的图标文件。如果你之前使用了 .jpg、.jpeg、.bmp 或 .svg,你需要将图标转换为 .png 文件,或在 wxt.config.ts 文件中手动将它们添加到 manifest 中。
v0.8.0 → v0.9.0
默认移除 WebWorker 类型
从 .wxt/tsconfig.json 中移除了 "WebWorker" 类型。这些类型对使用 Service Worker 的 MV3 项目很有用。
要将它们添加回你的项目,请在项目的 TSConfig 中添加以下内容:
{
"extends": "./.wxt/tsconfig.json",
"compilerOptions": {
"lib": ["ESNext", "DOM", "WebWorker"]
}
}v0.7.0 → v0.8.0
defineUnlistedScript
未列出的脚本现在必须 export default defineUnlistedScript(...)。
BackgroundDefinition 类型
将 BackgroundScriptDefintition 重命名为 BackgroundDefinition。
v0.6.0 → v0.7.0
Content Script CSS 输出位置变更
Content Script CSS 之前输出到 assets/<name>.css,现在输出到 content-scripts/<name>.css 以与文档一致。
v0.5.0 → v0.6.0
vite 配置需要使用函数
vite 配置选项现在必须是一个函数。如果你之前使用的是对象,请将 vite: { ... } 更改为 vite: () => ({ ... })。
v0.4.0 → v0.5.0
恢复公共目录移动
将默认的 publicDir 从 <rootDir>/public 改回 <srcDir>/public。
v0.3.0 → v0.4.0
更新默认路径别名
在 .wxt/tsconfig.json 中使用相对路径别名。
v0.2.0 → v0.3.0
移动公共目录
将默认的 publicDir 从 <srcDir>/public 更改为 <rootDir>/public。
改进类型安全
为 browser.runtime.getURL 添加类型安全。
v0.1.0 → v0.2.0
重命名 defineBackground
将 defineBackgroundScript 重命名为 defineBackground。