一、技术选型维度最终选择核心理由扩展框架WXT基于 Vite热更新快对 Vue 3 中立友好维护活跃不像 Plasmo 已进入维护模式Manifest 版本V3Chrome 强制推行V2 已彻底淘汰没有选择余地前端框架Vue 3你的技术栈偏好WXT 官方支持UI 组件库Element Plus静态 CSS 分发Shadow DOM 适配成本比 Ant Design Vue 低维护状态更健康抓取方式Content Script 读 DOM Main World Hook如需MV3 下阻塞式 webRequest 已不可用页面内 Hook 是主流替代方案测试Vitest单元 PlaywrightE2EWXT 官方对两者均有一等支持二、整体架构博客页面你的网站 │ │ 派发 Custom DOM Event 或 window.postMessage ▼ Content Script注入到博客页面 │ │ runtime.sendMessage ▼ Background Service WorkerWXT 后台 │ ├──► CSDN API发布 ├──► 掘金 API发布 └──► chrome.storage凭证/状态核心思路博客页面负责“选中文章”WXT 插件负责“同步到其他平台”。网页不直接调用各平台 API所有发布逻辑收敛在扩展后台凭证不暴露给网页。三、网页与扩展通信的两种方案方案一externally_connectableWXT 配置// wxt.config.ts import { defineConfig } from wxt; export default defineConfig({ modules: [wxt-dev/module-vue], manifest: { externally_connectable: { matches: [ http://localhost:5173/*, http://127.0.0.1:5173/*, ], }, permissions: [storage], }, });扩展后台监听// entrypoints/background.ts export default defineBackground(() { browser.runtime.onMessageExternal.addListener( (message, sender, sendResponse) { const allowedOrigins [ http://localhost:5173, http://127.0.0.1:5173, ]; if (!sender.origin || !allowedOrigins.includes(sender.origin)) { sendResponse({ success: false, error: 未授权的来源 }); return true; } if (message.action sync-article) { console.log(收到文章:, message.article.title); browser.storage.local.set({ lastSyncedArticle: message.article, }); sendResponse({ success: true, message: 已接收 }); } return true; } ); });博客页面发送// 你的博客网站代码 const EXTENSION_ID 你的扩展ID; // 从 chrome://extensions 获取 function syncArticle(article) { if (!window.chrome?.runtime?.sendMessage) { alert(请先安装同步插件); return; } chrome.runtime.sendMessage( EXTENSION_ID, { action: sync-article, article }, (response) { if (chrome.runtime.lastError) { console.error(通信失败:, chrome.runtime.lastError.message); return; } console.log(同步结果:, response); } ); } // 用户点击“同步”按钮时调用 syncArticle({ title: 我的文章标题, content: # 正文内容..., tags: [技术, 前端], });特点网页直接调用扩展 API代码简洁但需要知道扩展 ID且Firefox 不支持。方案二桥接方式DOM 事件WXT 配置// wxt.config.ts import { defineConfig } from wxt; export default defineConfig({ modules: [wxt-dev/module-vue], manifest: { host_permissions: [ http://localhost:5173/*, http://127.0.0.1:5173/*, ], permissions: [storage], }, });内容脚本注入博客页面// entrypoints/content/index.ts export default defineContentScript({ matches: [ http://localhost:5173/*, http://127.0.0.1:5173/*, ], main() { document.addEventListener(BLOG_SYNC_ARTICLE, (event: Event) { const customEvent event as CustomEvent; const article customEvent.detail; if (!article?.title || !article?.content) { console.warn(文章数据格式不正确); return; } browser.runtime.sendMessage({ action: sync-article, article, }); }); }, });扩展后台接收// entrypoints/background.ts export default defineBackground(() { browser.runtime.onMessage.addListener((message, sender, sendResponse) { if (message.action sync-article) { console.log(收到文章:, message.article.title); browser.storage.local.set({ lastSyncedArticle: message.article, }); sendResponse({ success: true, message: 已接收 }); } return true; }); });博客页面派发事件// 你的博客网站代码 —— 不依赖任何 chrome.* API function syncArticle(article) { const event new CustomEvent(BLOG_SYNC_ARTICLE, { detail: article, }); document.dispatchEvent(event); } // 用户点击“同步”按钮时调用 syncArticle({ title: 我的文章标题, content: # 正文内容..., tags: [技术, 前端], });特点网页代码完全不依赖chrome.*APIFirefox 也能用但需要扩展注入内容脚本到你的博客页面。两种方案对比externally_connectable桥接方式DOM 事件Firefox 支持❌ 不支持✅ 支持需要扩展 ID需要不需要网页代码依赖chrome.runtime.sendMessage纯 DOM 事件无扩展 API前提条件扩展已安装且域名在matches中扩展的内容脚本已注入博客页面安全性由matches限制域名内容脚本需自行校验数据格式响应机制支持回调可拿到扩展返回值单向事件如需响应可再派发反向事件建议如果你的博客希望覆盖 Firefox 用户或者不想在网页代码里硬编码扩展 ID桥接方式是更稳妥的选择。它把“扩展相关”的逻辑完全收敛在内容脚本里网页端只负责派发一个标准 DOM 事件耦合度最低。四、关键避坑点扩展 ID 不是项目名它是 Chrome 基于密钥生成的独立字符串。开发时路径一变 ID 就变建议尽早用manifest.key固定。Shadow DOM 样式隔离Element Plus 的:rootCSS 变量不会自动进入 Shadow DOM需要替换为:host或使用cssInjectionMode: ui。MV3 网络拦截限制无法实时修改请求爬虫/同步逻辑要转向“页面内 Hook”或“声明式规则”思路。凭证安全CSDN/掘金的登录凭证应存在扩展的storage中由后台 Service Worker 调用 API不要暴露给网页。测试策略纯函数提取逻辑用 Vitest 快速验证完整流程用 Playwright 的持久化上下文跑通。五、项目结构参考blog-sync-extension/ ├── entrypoints/ │ ├── content/ # 注入博客页面监听事件并转发 │ ├── background.ts # 接收文章调用各平台 API │ └── popup/ # 配置凭证、查看同步状态 ├── components/ # Vue 组件自动导入 ├── composables/ # 组合式函数 ├── utils/ # 消息/存储封装 ├── wxt.config.ts # manifest、权限、externally_connectable └── package.json