
在第一章 Browser Extension Dev - 1. 介绍基本概念 里面,我使用了原始的 JavaScript 实现了一个简单的 Chrome 扩展。现在,我将使用 WXT 重写扩展。那么问题是:什么是 WXT?
简单来说,WXT 是用于浏览器扩展的开发框架,就像 Vite 是用于 Web 开发的流行框架一样。实际上,WXT 是基于 Vite 实现的,所以它也可以使用 Vite 插件的生态系统。在我看来,这是个非常棒的决定。
那么,它能解决什么问题呢?
如果想了解更详细的功能对比,可以参考官方文档:https://wxt.dev/guide/resources/compare.html
首先,让我们初始化一个项目,由于不涉及 UI 部分,所以只需要使用 vanilla 模版就好了。
1 | |
现在我们得到一系列的目录和文件,让我们依次了解
1 | |
使用以下命令开发和构建
使用 pnpm dev 启动开发模式,输出目录在 .output/chrome-mv3-dev,在 Chrome 中需要加载这个目录作为扩展目录,而不是项目根目录。不过 WXT 会自动启动一个 Chrome 进程并自动加载扩展,所以可以不需要手动加载扩展。


但如果你不希望自动打开 Chrome 窗口,也可以配置 wxt.config.ts 来禁用这个行为。对于调试需要登录的网站而言,这也是必要的。
1 | |
对于不熟悉现代前端工具链的人而言,开发和构建代码是分离的,不像早期那样编写的 JavaScript 就是运行在用户设备上的 JavaScript,使用 WXT 开发扩展也是一样的。
使用 pnpm build 启动构建模式,输出目录在 .output/chrome-mv3,通常只有在需要调试 Firefox 或 Safari 版本时才需要使用构建后的扩展。

使用 pnpm zip 可以打包扩展的 zip 文件,对于 Firefox 还会有一个额外的 source 文件(Firefox AMO 要求提交扩展必须包含源码),这在提交到 Chrome Web Store 时才需要,这里先提一下。

在使用 WXT 之后,manifest 有许多部分都不再需要,它们通常都变成“约定配置”,不再需要手动处理。例如下面是之前实现扩展的 manifest.json
1 | |
manifest_version 会自动推导,Chrome/Safari 使用 v3,而 Firefox 默认使用 v2,不过我仍然建议统一使用 v3,以避免一些边缘情况需要兼容name/version/description 可以在 package.json 中配置,它会自动合并到输出目录中的 manifest.json。由于 package.json 的 name 字段有大小写限制,而且可能包含包名,所以我仍然建议在 wxt.config.ts 中配置 name/description 字段content_scripts/icons 字段完全不需要,它们会从 entrypoints 和 public/icon 目录自动推导出来所以更新后的 wxt.config.ts 是
1 | |
首先,还是让我们先清理一下无关文件。
1 | |
接下来打开 entryponits/content.ts 文件,可以看到初始内容如下
1 | |
而这里就是有趣的部分,defineContentScript 实际上定义了 manifest 和对应实际执行的脚本,这就是为什么上面在 wxt.config.ts 中省略 content_scripts 字段的原因,不过这也合理,将相关的代码和配置放在一起。将之前扩展的代码和配置修改过来之后变成:
1 | |
作为对比,之前的 content script 是放在 manifest.json 和 content-scripts/content.js 两个文件中完成。
1 | |
1 | |
可以看到 WXT 的 content script 仍然是非常直观的,只是将下划线字段重命名为驼峰字段了(run_at => runAt)。在我们更新 content script 之后,直接打开 google.com 可以看到扩展已经热更新为了我们修改后的代码。扩展效果

注意:你可能注意到闪烁问题又出现了,这是因为 wxt 为了实现热更新加载机制,content script 是动态注入的,这导致
run_at: document_start设置在开发模式下不太有用,但无需担心,在构建后它的工作正常。参考:https://github.com/wxt-dev/wxt/issues/357
提示:在开发过程中,如果需要查看 content script 的 console.log 输出,需要在网页 google.com(而不是扩展页面)打开 Devtools > Console 查看。
接下来,我们来添加扩展 icon。在 WXT 中,只需要将图标放到 ./public/icon/ 目录就好了,创建项目后可以看到自动创建了一些不同尺寸的图标,这是用于在显示时自动选择合适的图标,你可以选择使用任何工具来生成合适尺寸的图标,这里使用 ImageMagick 作为演示。
1 | |
如果更喜欢可视化工具,也可以使用 https://squoosh.app/ 来调整图片尺寸。或者使用 WXT 官方的 icon 模块 https://wxt.dev/auto-icons 来自动生成。
回到浏览器扩展管理页面,可以看到 icon 已经被正确识别了。

现在,我们完成了第一个使用 WXT 实现的扩展就完成了,你觉得怎么样?在下一章中,我们将使用现代 Web 框架和 npm 包,为网页注入 UI 并实现更复杂的功能。
如果有任何问题,欢迎加入 Discord 群组讨论。
https://discord.gg/VxbAqE7gj2
完整代码:https://github.com/rxliuli/browser-extension-dev-examples/tree/main/packages/02-use-wxt
WXT 官网 https://wxt.dev/

在第一章 Browser Extension Dev - 1. 介绍基本概念 里面,我使用了原始的 JavaScript 实现了一个简单的 Chrome 扩展。现在,我将使用 WXT 重写扩展。那么问题是:什么是 WXT?
简单来说,WXT 是用于浏览器扩展的开发框架,就像 Vite 是用于 Web 开发的流行框架一样。实际上,WXT 是基于 Vite 实现的,所以它也可以使用 Vite 插件的生态系统。在我看来,这是个非常棒的决定。
那么,它能解决什么问题呢?
如果想了解更详细的功能对比,可以参考官方文档:https://wxt.dev/guide/resources/compare.html
首先,让我们初始化一个项目,由于不涉及 UI 部分,所以只需要使用 vanilla 模版就好了。
1 | |
现在我们得到一系列的目录和文件,让我们依次了解
1 | |
使用以下命令开发和构建
使用 pnpm dev 启动开发模式,输出目录在 .output/chrome-mv3-dev,在 Chrome 中需要加载这个目录作为扩展目录,而不是项目根目录。不过 WXT 会自动启动一个 Chrome 进程并自动加载扩展,所以可以不需要手动加载扩展。


但如果你不希望自动打开 Chrome 窗口,也可以配置 wxt.config.ts 来禁用这个行为。对于调试需要登录的网站而言,这也是必要的。
1 | |
对于不熟悉现代前端工具链的人而言,开发和构建代码是分离的,不像早期那样编写的 JavaScript 就是运行在用户设备上的 JavaScript,使用 WXT 开发扩展也是一样的。
使用 pnpm build 启动构建模式,输出目录在 .output/chrome-mv3,通常只有在需要调试 Firefox 或 Safari 版本时才需要使用构建后的扩展。

使用 pnpm zip 可以打包扩展的 zip 文件,对于 Firefox 还会有一个额外的 source 文件(Firefox AMO 要求提交扩展必须包含源码),这在提交到 Chrome Web Store 时才需要,这里先提一下。

在使用 WXT 之后,manifest 有许多部分都不再需要,它们通常都变成“约定配置”,不再需要手动处理。例如下面是之前实现扩展的 manifest.json
1 | |
manifest_version 会自动推导,Chrome/Safari 使用 v3,而 Firefox 默认使用 v2,不过我仍然建议统一使用 v3,以避免一些边缘情况需要兼容name/version/description 可以在 package.json 中配置,它会自动合并到输出目录中的 manifest.json。由于 package.json 的 name 字段有大小写限制,而且可能包含包名,所以我仍然建议在 wxt.config.ts 中配置 name/description 字段content_scripts/icons 字段完全不需要,它们会从 entrypoints 和 public/icon 目录自动推导出来所以更新后的 wxt.config.ts 是
1 | |
首先,还是让我们先清理一下无关文件。
1 | |
接下来打开 entryponits/content.ts 文件,可以看到初始内容如下
1 | |
而这里就是有趣的部分,defineContentScript 实际上定义了 manifest 和对应实际执行的脚本,这就是为什么上面在 wxt.config.ts 中省略 content_scripts 字段的原因,不过这也合理,将相关的代码和配置放在一起。将之前扩展的代码和配置修改过来之后变成:
1 | |
作为对比,之前的 content script 是放在 manifest.json 和 content-scripts/content.js 两个文件中完成。
1 | |
1 | |
可以看到 WXT 的 content script 仍然是非常直观的,只是将下划线字段重命名为驼峰字段了(run_at => runAt)。在我们更新 content script 之后,直接打开 google.com 可以看到扩展已经热更新为了我们修改后的代码。扩展效果

注意:你可能注意到闪烁问题又出现了,这是因为 wxt 为了实现热更新加载机制,content script 是动态注入的,这导致
run_at: document_start设置在开发模式下不太有用,但无需担心,在构建后它的工作正常。参考:https://github.com/wxt-dev/wxt/issues/357
提示:在开发过程中,如果需要查看 content script 的 console.log 输出,需要在网页 google.com(而不是扩展页面)打开 Devtools > Console 查看。
接下来,我们来添加扩展 icon。在 WXT 中,只需要将图标放到 ./public/icon/ 目录就好了,创建项目后可以看到自动创建了一些不同尺寸的图标,这是用于在显示时自动选择合适的图标,你可以选择使用任何工具来生成合适尺寸的图标,这里使用 ImageMagick 作为演示。
1 | |
如果更喜欢可视化工具,也可以使用 https://squoosh.app/ 来调整图片尺寸。或者使用 WXT 官方的 icon 模块 https://wxt.dev/auto-icons 来自动生成。
回到浏览器扩展管理页面,可以看到 icon 已经被正确识别了。

现在,我们完成了第一个使用 WXT 实现的扩展就完成了,你觉得怎么样?在下一章中,我们将使用现代 Web 框架和 npm 包,为网页注入 UI 并实现更复杂的功能。
如果有任何问题,欢迎加入 Discord 群组讨论。
https://discord.gg/VxbAqE7gj2
完整代码:https://github.com/rxliuli/browser-extension-dev-examples/tree/main/packages/02-use-wxt
WXT 官网 https://wxt.dev/