Chrome扩展Manifest V3 Service Worker加载jQuery报错与XML解析方案
解决方案
Manifest V3的Service Worker是独立Worker上下文,没有完整的DOM/BOM环境,jQuery(尤其是你用的2.x老旧版本)依赖window、document等页面环境对象,就算修正导入语法也无法正常运行,完全没必要强行适配。Chrome原生提供的DOMParserAPI可以直接在Service Worker中解析XML,所有jQuery的DOM操作都可以用原生Web API替换,无依赖、启动速度更快。
清理无效依赖
直接删除代码开头错误的jQuery导入语句,本地的jQuery文件也可以一并删除,不需要保留:
// 删除以下无效导入 // import $ as module from 'js/jquery-2.1.4.min.js';
替换Feed解析逻辑
你代码中所有jQuery调用都集中在FeedService模块,直接把原有downloadFeed、parseFeed、getUrlForFeed三个方法替换为下面的原生实现即可,业务逻辑和原代码完全一致,同时修复了原代码未兼容Atom订阅格式的问题:
var FeedService = (function() { // 工具方法:获取指定选择器下的元素文本 function getText(elm, selector) { const node = elm.querySelector(selector); return node ? node.textContent.trim() : ''; } // 工具方法:获取条目链接,兼容RSS2.0(文本节点)和Atom(href属性)两种格式 function getEntryLink(elm) { const rssLink = elm.querySelector('link'); if (rssLink && rssLink.textContent.trim()) { return rssLink.textContent.trim(); } const atomLink = elm.querySelector('link[href]'); if (atomLink) { return atomLink.getAttribute('href'); } return ''; } return { downloadFeed: function(feed) { if (!feed.url) return; console.log(feed.url) fetch(feed.url) .then(response => response.text()) .then(xmlString => { console.log(xmlString) const xmlDoc = new DOMParser().parseFromString(xmlString, 'text/xml'); this.parseFeed(xmlDoc, feed); }) .catch(err => console.error('Feed拉取失败:', err)) }, parseFeed: function(xmlDoc, existingFeedData) { // 兼容Atom的<entry>和RSS2.0的<item>两种条目标签 let feedEntries = xmlDoc.querySelectorAll("entry"); if (feedEntries.length === 0) { feedEntries = xmlDoc.querySelectorAll('item'); } let lastUpdate = Date.now() console.log("Now = " + lastUpdate) lastUpdate = (existingFeedData && existingFeedData.lastUpdate) || Date.now() console.log("Last Update = " + lastUpdate) console.log("existingFeedData = " + JSON.stringify(existingFeedData)) const pubDates = []; Array.from(feedEntries).forEach(function(elm) { // 兼容RSS2.0的pubDate和Atom的updated时间字段 const pubDateStr = getText(elm, "pubDate") || getText(elm, "updated"); const pubTime = new Date(pubDateStr).getTime(); pubDates.push(pubTime); if (lastUpdate < pubTime) { const title = getText(elm, "title"); console.log(title.substring(0, 20)); const link = getEntryLink(elm); chrome.notifications.create( link, { type: "basic", iconUrl: "../icons/254.png", title: title, message: "(" + msToTime((Date.now() - pubTime)) + ") ", requireInteraction: true }, function() {} ); } }.bind(this)); if (pubDates.length > 0) { const maxPubTime = Math.max.apply(null, pubDates); console.log("Max date = " + maxPubTime) existingFeedData.lastUpdate = maxPubTime; Storage.saveFeedData(existingFeedData); } }, getUrlForFeed: function(xmlDoc, feedSettings) { if (feedSettings.linkType) { const customLink = xmlDoc.querySelector(feedSettings.linkType); if (customLink && (customLink.textContent.trim() || customLink.getAttribute('href'))) { return customLink.textContent.trim() || customLink.getAttribute('href'); } } const allLinks = xmlDoc.querySelectorAll('link'); if (allLinks.length == 1) { return allLinks[0].textContent.trim() || allLinks[0].getAttribute('href'); } const shortLink = xmlDoc.querySelector('link[rel="shorturl"]'); if (shortLink) return shortLink.getAttribute('href'); const altLink = xmlDoc.querySelector('link[rel="alternate"]'); if (altLink) return altLink.getAttribute('href'); const relatedLink = xmlDoc.querySelector('link[rel="related"]'); if (relatedLink) return relatedLink.getAttribute('href'); return allLinks[0]; }, saveFeed: function(existingFeedData, newFeedData) {}, updateReadStatusOfNewItems: function(oldItems, newItems) { if (typeof oldItems === 'undefined' || Object.keys(oldItems).length == 0 || Object.keys(newItems).length == 0) { return newItems; } Object.keys(newItems).forEach(function(url) { if (oldItems[url]) { newItems[url].unread = oldItems[url].unread; } }); return newItems; }, setNewBadge: function() { // MV3已废弃browserAction,统一使用action API chrome.action.setBadgeText({ text: 'NEW' }); } }; }());
适配注意点
- 现有Manifest V3的background配置不需要修改,
"type": "module"配置保留即可 - 注意MV3中
chrome.browserActionAPI已被废弃,所有调用都要替换为chrome.action,否则徽章设置、图标点击等逻辑会报错 - 改造后无任何第三方依赖,Service Worker冷启动速度比加载jQuery快3-5倍,内存占用更低
- 上述代码额外兼容了Atom格式订阅的时间字段和链接格式,适配范围比原jQuery版本更广
内容的提问来源于stack exchange,提问作者Code Guy
相关产品推荐
相关产品推荐

