ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Quasar BEX 后台脚本(Background Script)实战指南:从 Manifest 注册到事件通信

Quasar BEX 后台脚本(Background Script)实战指南:从 Manifest 注册到事件通信 Quasar BEX 后台脚本Background Script实战指南从 Manifest 注册到事件通信【免费下载链接】quasarQuasar Framework - Build high-performance VueJS user interfaces in record time项目地址: https://gitcode.com/gh_mirrors/qu/quasar本文是 Quasar Framework 的 BEXBrowser Extension浏览器扩展开发系列指南之一聚焦于quasar/app-vite模式下后台脚本Background Script的完整开发流程如何在/src-bex/manifest.json中注册后台脚本、如何用 BEX Bridge 将浏览器事件如新标签页打开推送到 Quasar App 内部以及 Manifest v3 下 Service Worker 生命周期带来的连接管理问题。读完本文你将能够独立编写一个可监听浏览器扩展事件并与 Quasar 应用双向通信的后台脚本。后台脚本的定位BEX 的事件中枢后台脚本运行在 BEX 自身的上下文context中是唯一可以监听所有浏览器扩展事件的地方——包括chrome.tabs、chrome.runtime、chrome.webNavigation、chrome.storage等扩展 API 提供的事件。与注入到网页中的内容脚本Content Script不同后台脚本不受目标页面 DOM 与 CSP 的限制因此适合承担全局状态维护、跨标签页协调、调用高权限 API 等职责。在 Quasar 的 BEX 架构中后台脚本还有一个特殊身份它是 BEX Bridge 通信的中心节点。所有消息都经由后台脚本中的 bridge 转发到正确的接收方详见 BEX Bridge 通信文档。[!WARNING] 在 Chrome 的 Manifest v3 中后台脚本实际上是一个Service Worker这一情况目前撰写本文档时尚不适用于 Firefox 的 Manifest v3。这直接影响后台脚本的生命周期与内存状态后文生命周期一节会专门展开。注册后台脚本以/src-bex/manifest.json为准/src-bex/manifest.json是定义整个 BEX 的中央配置后台脚本也在这里声明。由于 Chrome 与 Firefox 对后台脚本的声明方式不同Quasar 的 BEX manifest 支持按目标浏览器拆分配置chrome: { background: { service_worker: background.js } }, firefox: { background: { scripts: [ background.js ] } }两个关键点需要留意ChromeMV3使用service_worker字段只允许声明一个后台 Service WorkerFirefoxMV2/MV3使用scripts数组允许声明多个后台脚本。TS 开发者请注意你的后台脚本与内容脚本文件扩展名是.ts那么在 manifest.json 中也请写.ts——例如background.ts、my-content-script.ts。虽然浏览器厂商只认.js扩展名但 Quasar CLI 会在构建阶段自动把扩展名转换为.js。源码印证扩展名如何被自动转换manifest.json中声明的脚本并非原样打包。在 bex-utils.js 中createManifest()会解析 manifest 并调用extractBexScripts()提取所有脚本入口对background.service_worker与background.scripts中的每一项先通过正则/\.[jt]sx?$/i去掉.ts/.js/.tsx/.jsx扩展名再统一改写为.js写入最终生成的 manifest对应代码见 bex-utils.js同时按name - distDir/脚本名.js的映射生成编译入口让 Vite 把源文件含 TS真正编译成浏览器可执行的 JS若声明的文件不存在构建时会输出警告并跳过该入口。也就是说你在/src-bex/下书写background.ts最终产物中的manifest.json会自动指向编译后的background.js无需手动维护两份清单。extendBexManifestJson配置钩子见 bex-utils.js还允许你在quasar.config.js或应用扩展中进一步改写 manifest。后台脚本的入口与桥初始化项目模板会在创建 BEX 时生成后台脚本骨架JS 模板 与 TS 模板 内容基本一致。脚本开头的导入是强制要求/** * Importing the file below initializes the extension background. * * Warnings: * 1. Do NOT remove the import statement below. It is required for the extension to work. * If you dont need createBridge(), leave it as import #q-app/bex/background. * 2. Do NOT import this file in multiple background scripts. Only in one! * 3. Import it in your background service worker (if available for your target browser). */ import { createBridge } from #q-app/bex/background const bridge createBridge({ debug: false })#q-app/bex/background是 Quasar CLI 为 BEX 后台脚本注入的虚拟模块其实现在 app-vite/exports/bex/background.js。源码层面的三个实现细节值得了解单例保护模块内部通过scriptHasBridge标志位确保createBridge()在同一个后台脚本中只能调用一次重复调用会输出Background Quasar Bridge has already been created.并直接返回见 background.js。BEX Bridge 文档也明确警告即便 manifest 中声明了多个后台脚本也只能在其中某一个脚本里创建 bridge。开发模式 HMR当QUASAR_DEV且目标为 Chrome 时该模块会自动拦截扩展页面发往 Vite dev server 的 fetch 请求interceptRequests并通过 WebSocket 建立 HMR 通道收到qbex:hmr:reload事件后通知所有内容脚本并调用chrome.runtime.reload()热重载整个扩展见 background.js。这解释了为何后台脚本模板不允许被删除——它同时承担了构建期的桥初始化与开发期的 HMR 基建。双浏览器兼容BexBridge 内部会根据QUASAR_TARGET在browserFirefox与chrome命名空间间自动切换见 bex-bridge.js。实战案例监听新标签页并通知 Quasar App下面完整演示浏览器打开新标签页 → 后台脚本感知 → Quasar App 收到事件的链路。这是后台脚本最常见的用法用浏览器扩展 API 监听事件再通过 bridge 把事件转发给应用。首先在后台脚本中监听标签页更新事件并向 Quasar App 发送自定义事件/** * Importing the file below initializes the extension background. * * Warnings: * 1. Do NOT remove the import statement below. It is required for the extension to work. * If you dont need createBridge(), leave it as import #q-app/bex/background. * 2. Do NOT import this file in multiple background scripts. Only in one! * 3. Import it in your background service worker (if available for your target browser). */ import { createBridge } from #q-app/bex/background const bridge createBridge({ debug: false }) chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) { if (bridge.portList.includes(app)) { bridge.send({ event: bex.tab.updated, to: app, payload: { url: tab.url } }) } })bridge.portList.includes(app)用于确认 Quasar App 的端口当前已连接popup / options / devtools 页面在 bridge 中的端口名统一为app避免向不存在的接收方发送消息。然后在 Quasar App 的组件生命周期钩子中监听该事件import { useQuasar } from quasar import { onBeforeUnmount } from vue export default { setup() { const $q useQuasar() // Our function which receives the URL sent by the background script. function doOnTabOpened({ payload }) { console.log(Browser tab updated:, payload.url) } // Add our listener $q.bex.on(bex.tab.updated, doOnTabOpened) // Dont forget to clean it up onBeforeUnmount(() { $q.bex.off(bex.tab.updated, doOnTabOpened) }) return {} } }注意两个配套动作$q.bex是 Quasar 在应用侧暴露的 bridge 实例由useQuasar()获取其portName固定为app而onBeforeUnmount中的off是必须的清理步骤——后台脚本可能长驻运行应用组件销毁后若不移除监听器会造成事件泄漏与重复回调。浏览器扩展 API 还暴露了大量其他事件chrome.tabs.onCreated、chrome.webNavigation、chrome.runtime.onInstalled等具体以你所面向的浏览器与 manifest 版本的官方文档为准。项目模板中的后台脚本也内置了若干参考实现如storage.get/set/remove、getTime事件可作为后续扩展的起点见 JS 模板 与 TS 模板。深入桥通信send / on / off 与端口模型后台脚本与 App、内容脚本的通信完全建立在 BexBridge 之上。它是一个Promise 化的事件系统实现见 bex-bridge.js每个上下文持有自己的 bridge 实例端口名规则为background、app、content脚本相对路径-实例号。后台脚本侧最常用的 API 组合// 监听来自 App / 内容脚本的消息可同步或异步返回响应 bridge.on(getTime, () Date.now()) // 向指定端口发送消息返回 Promise响应 bridge.send({ event: test, to: app, payload: { banner: Hello from background! } }).then(responsePayload { ... }).catch(err { ... }) // 广播给所有已连接的 App 与内容脚本 bridge.portList.forEach(portName { bridge.send({ event: test, to: portName, payload: Hello from background! }) }) // 找到任意已连接的内容脚本并发送 const contentPort bridge.portList.find(name name.startsWith(content)) if (contentPort) { bridge.send({ event: test, to: contentPort, payload: Hello from background! }) } // 监听端口连接 / 断开quasar:ports 为桥自动注册的内部事件 bridge.on(quasar:ports, ({ portList, added, removed }) { console.log(Ports:, portList) })关于消息体积有两个重要约束详见 BEX Bridge 文档大消息需分块浏览器对扩展消息有硬性大小限制。当payload为数组时bridge 会自动把每个元素作为独立消息分块发送若你本意是发送一个数组请把它包进对象里payload: { myArray: [...] }否则性能会很差。计算大小时还要算上 bridge 消息外壳本身的字节数。异步响应bridge.on的回调可以返回普通值同步响应、async函数或Promise异步响应send()一侧通过 Promise 等待结果。Manifest v3 下的后台脚本生命周期与自动重连这是后台脚本开发最容易踩坑的地方。在 Manifest v3 中Chrome 将后台脚本作为Service Worker运行浏览器会在其空闲约 30 秒后将其终止Firefox 在 MV3 下目前使用事件页机制行为类似所有桥连接会随之一同断开后台脚本内存中的状态也会全部丢失。扩展商店不允许通过keep-alive手段阻止终止因此 Quasar 的 bridge 选择透明地处理这一情况对应文档标注quasar/app-vite v3.8.1其源码与测试均验证了以下行为重启唤醒后台脚本每次重新启动时会广播一条一次性消息源码中的reviveSignature quasar:bex:revive见 bex-bridge.js要求之前连接过的 App 与内容脚本桥重新建立端口连接见 bex-bridge.js。自动重连若已连接的 App/内容脚本桥断线其下一次bridge.send()会先自动重连重连会唤醒后台脚本而不是直接 reject见 bex-bridge.js。端口等待send()目标端口尚未注册时会等待最多1 秒源码常量waitForPortTimeout 1000再失败覆盖后台重启后端口重新注册的窗口期。显式断开即退出自动重连通过bridge.disconnectFromBackground()主动断开的桥不再参与上述恢复机制。这些行为都有对应的单元测试覆盖例如background restart revives previously connected clients、send() transparently reconnects after the background is gone等用例见 bex-bridge.test.js。[!TIP] 后台脚本每次终止都会清空内存状态。任何需要跨重启存活的数据如登录态、偏好设置请用chrome.storage持久化不要依赖普通变量。调试与安全实践开启调试消息不通时可为相关桥开启 debug 模式通信过程会输出到浏览器控制台// Dynamically set debug mode bridge.setDebug(true) // boolean // Log a message on the console (if debug is enabled) bridge.log(Hello world!) // Log a warning on the console (regardless of the debug setting) bridge.warn(Hello world!, { some: data })log仅在 debug 开启时输出warn无条件输出二者都支持多参数。安全提示桥的每条消息都应视为不可信输入——尤其是来自内容脚本它可接触任意网页的消息。在使用扩展权限或读取存储数据之前务必校验事件名、发送方message.from、payload 结构、URL 与标识符暴露窄化的操作接口而非通用的高权限命令并按最小权限原则申请 manifest 权限与主机访问权。小结后台脚本是 Quasar BEX 的事件中枢与桥通信中心。回顾全文的关键结论在/src-bex/manifest.json中用chrome.background.service_workerMV3 单脚本与firefox.background.scripts多脚本注册后台脚本TS 扩展名由 Quasar CLI 在构建期自动转换bex-utils.js。通过import { createBridge } from #q-app/bex/background初始化桥注意只能在一个后台脚本中创建单例保护见 background.js。用chrome.*事件监听 bridge.send()把浏览器事件推给to: app在 Quasar App 中用$q.bex.on()/off()接收并清理。MV3 下后台脚本约 30 秒空闲即被终止bridge 已内置重启唤醒 自动重连 1 秒端口等待机制但内存状态仍需chrome.storage持久化。继续阅读系列文档可深入 内容脚本Content Scripts、BEX 配置项 与 TypeScript 支持。【免费下载链接】quasarQuasar Framework - Build high-performance VueJS user interfaces in record time项目地址: https://gitcode.com/gh_mirrors/qu/quasar创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表