草庐IT

谷歌浏览器插件MV3报错"Uncaught ReferenceError: window is not defined"

exoo 2023-03-28 原文

出错

配置mv3后,在后台代码background.js使用DOMPurify发现无法访问window,会一直报错
Uncaught ReferenceError: window is not defined
查看后台,globalThis变成了一个叫ServiceWorkerGlobalScope的玩意

原因

mv3使用了一个叫Service workers的东西替代原来的background页面,不提供dom API,所以不管是window还是document、HTMLElement……都会xx is not defined
chrome官方介绍:

Manifest V3 replaces background pages with service workers.
Like their web page counterparts, extension service workers listen for and respond to events in order to enhance the end user's experience. For web service workers this typically means managing cache, preloading resources, and enabling offline web pages. While extension service workers can still do all of this, the extension package already contains a bundle of resources that can be accessed offline. As such, extension service workers tend to focus on reacting to relevant browser events exposed by Chrome's extensions APIs.

另附mv2和mv3后台页区别对比表:

MV2 - Background page MV3 - Service worker
Can use a persistent page. Terminates when not in use.
Has access to the DOM. Doesn't have access to the DOM.
Can use XMLHttpRequest(). Must use fetch() to make requests.

解决

1. 放弃在后台页直接调用dom API

chrome官方态度还是比较明确的,所以最好不要花太大力气去搞。能用chrome API的全都用chrome API实现,特别是标签和窗口的操作。另外chrome也提供了一些mv2到mv3迁移的建议migrating_to_service_workers

2. 使用undom模拟

undom是比jsdom轻量的Document接口实现,基本满足dom操作的需求,简单易用。
安装

pnpm install --save undom

使用

import undom from 'undom';
let document = undom();

// 简单操作dom
let foo = document.createElement('foo');
foo.appendChild(document.createTextNode('Hello, World!'));
document.body.appendChild(foo);

// 驱动第三方库DOMPurify
const purify = DOMPurify(document);
purify.sanitize(html..)

另外undom本身不支持直接输出HTML,因为它只实现了Document的骨架,不能直接用innerHTML、querySelector等,提供了手动解析的方法

function serialize(el) {
	if (el.nodeType===3) return el.textContent;
	var name = String(el.nodeName).toLowerCase(),
		str = '<'+name,
		c, i;
	for (i=0; i<el.attributes.length; i++) {
		str += ' '+el.attributes[i].name+'="'+el.attributes[i].value+'"';
	}
	str += '>';
	for (i=0; i<el.childNodes.length; i++) {
		c = serialize(el.childNodes[i]);
		if (c) str += '\n\t'+c.replace(/\n/g,'\n\t');
	}
	return str + (c?'\n':'') + '</'+name+'>';
}

function enc(s) {
	return s.replace(/[&'"<>]/g, function(a){ return `&#${a};` });
}

// 输出完整html
console.log(serialize(document.childNodes[0]));
// 转义html
console.log(enc(serialize(document.childNodes[0])));

有关谷歌浏览器插件MV3报错"Uncaught ReferenceError: window is not defined"的更多相关文章

  1. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  2. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  3. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  4. ruby-on-rails - 您希望看到哪些 Rails 插件? - 2

    您认为可以作为插件很好地存在于您的Rails应用程序中必须实现的哪些行为?您过去曾搜索过哪些插件功能但找不到?哪些现有的Rails插件可以改进或扩展,如何改进或扩展? 最佳答案 我希望在管理界面中看到一个引擎插件,它提供了应用程序中所有模型的仪表板摘要,以及可配置的事件图表。 关于ruby-on-rails-您希望看到哪些Rails插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questio

  5. ruby - vagrant 从 github 安装插件 - 2

    我们正在使用Vagrant进行部署,我们最终希望将此集群部署在Rackspace上。vagrant-rackspace插件是一个自然的选择,但它有一些错误,这些错误未包含在最新的0.1.1版本中(notablythatvagrantprovisiondoesn'twork)。我已经在我的personalfork中解决了这个问题通过合并其他人的工作来对存储库进行改造。是否可以从github安装vagrant插件?显而易见的事情没有奏效:[unix]$vagrantplugininstallvagrant-rackspace--plugin-sourcehttps://github.com

  6. ruby - 强制浏览器下载文件而不是打开文件 - 2

    我要下载http://foobar.com/song.mp3作为song.mp3,而不是让Chrome在其native中打开它浏览器中的播放器。我怎样才能做到这一点? 最佳答案 您只需要确保发送这些header:Content-Disposition:attachment;filename=song.mp3;Content-Type:application/octet-streamContent-Transfer-Encoding:binarysend_file方法为您完成:get'/:file'do|file|file=File.

  7. ruby-on-rails - 使用 gmaps4rails 动态加载谷歌地图标记 - 2

    如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail

  8. ruby - 404 未找到,但可以从网络浏览器正常访问 - 2

    我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT

  9. ruby - 如何在 watir 测试套件结束时关闭浏览器? - 2

    使用ruby​​的watir测试网络应用程序时,浏览器最后会保持打开状态。网上的一些建议是,要进行真正的单元测试,您应该在每次测试时(在拆卸调用中)打开和关闭浏览器,但这很慢而且毫无意义。或者他们做这样的事情:defself.suites=superdefs.afterClass#Closebrowserenddefs.run(*args)superafterClassendsend但这会导致摘要输出不再显示(诸如“100次测试、100次断言、0次失败、0次错误”之类的内容仍应显示)。我怎样才能让ruby​​或watir在我的测试结束时关闭浏览器? 最佳答案

  10. IDEA使用LeetCode插件 - 2

    前言我们习惯用idea编写、调试代码,在LeetCode上刷题时,如果能够在IDEA编写代码,并且做好代码管理,是一件事半功倍的事情。对于后续复习题目,做笔记也会非常便利。本文目的在于介绍LeetCodeEditor的使用,以及配置工具类,最终目录结构如下:note:放置笔记src:放置代码leetcode.editor.cn:插件LeetCodeEditor自动生成utils:自定义的工具包,可用于自动化输入测试用例,定义题目需要的类(结构体)out:运行测试时自动生成LeetCodeEditorGitHub:https://github.com/shuzijun/leetcode-edit

随机推荐