當我們使用vuex的時候,時不時能看到“更改Vuex中的store中的狀態唯一辦法就是提交mutations”,但是有沒有試想過,我們不提交mutations其實也能修改state的值?答案是可以的 我們可以直接使用如下方式; this.$store.state.num=666; 其中,這樣修改的話 ...
出錯
配置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.
大意就是在後臺訪問dom API不好,用chrome插件API好
另附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.
可見官方明確了禁止直接訪問dom,只能通過一些方式間接實現了
解決
放棄在後臺頁直接調用dom API
chrome官方態度還是比較明確的,所以最好不要花太大力氣去搞。能用chrome API的全都用chrome API實現,特別是標簽和視窗的操作。另外chrome也提供了一些mv2到mv3遷移的建議migrating_to_service_workers
使用undom模擬
undom是比jsdom輕量的Document介面實現,基本滿足dom操作的需求,簡單易用。
安裝
pnpm install --save undom
簡單使用
import undom from 'undom';
let document = undom();
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])));