Conversation
好像不用额外做 "scriptcat-content-flag" 这个像 |
There was a problem hiding this comment.
sc{messageFlag} - checkEarlyStartScript 接收
{ct/fd}ld{messageFlag} - 环境 加载完成, 脚本接收
-
脚本先执行 ->
{ct/fd}ld{messageFlag}设置好 ->sc{messageFlag}没有listener. -> 环境 加载完成 执行 ->{ct/fd}ld{messageFlag}触发 ->sc{messageFlag}发送 -> execEarlyScript -
环境 加载完成 先执行 ->
sc{messageFlag}设置好 ->{ct/fd}ld{messageFlag}没有listener. -> 脚本执行 ->sc{messageFlag}触发 -> this. execEarlyScript
然后你看看这个 demo 了解一下 dispatchEvent 回传值
MDN说明: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent#return_value
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>dispatchEvent() Example</title>
</head>
<body>
<p id="result"></p>
<script>
const result = document.getElementById("result");
// Add a cancelable custom event listener
window.addEventListener("myCustomEvent", function (e) {
console.log("Listener 1: Event received");
// Uncomment this line to see how it changes dispatchEvent's return value:
// e.preventDefault();
});
// Dispatch the event
const event = new CustomEvent("myCustomEvent", {
cancelable: true // <-- Key part
});
const returnValue = window.dispatchEvent(event);
result.textContent = `dispatchEvent() returned: ${returnValue}`;
console.log("dispatchEvent() returned:", returnValue);
</script>
</body>
</html>同时避免 callback 在不同环境间传来传去
有可能传不了 (content/page 分离设计)
没文档支援的写法,即使单一浏览器能执行,其他浏览器不一定有一样行为
|
|
打算重构一下messageFlag这个,全使用随机的
确实可以和 inject 一样的方式 |
我有一个更简单的想法 ( script_executor.ts 跟 exec_script.ts ) 要修改 |
不止 GM_info 呀,还有GM API之类的沙盒环境 |
|
好像是同一环境所以可以直接取window的东西? 既然如此, window['${script.flag}'] = {
scriptInfo: ${JSON.stringify(script)},
func: function(){${autoDeleteMountCode}${scriptCode}}
};了 直接把 scriptInfo 跟 func 放在 (() => {
const func = function(){${autoDeleteMountCode}${scriptCode}};
const scriptInfo = ${JSON.stringify(script)};
const f = () => {
const event = new CustomEvent('sc${messageFlag}',
{ cancelable: true, detail: { scriptFlag: '${script.flag}', scriptInfo, func } });
return window.dispatchEvent(event); // checkEarlyStartScript 先执行的话,这里回传 false
};
const noCheckEarlyStartScript = f(); // checkEarlyStartScript 先执行的话,这里的 f() 会直接触发execEarlyScript; dispatchEvent 会回传 false
if (noCheckEarlyStartScript) { // checkEarlyStartScript 未执行
// 使用 dispatchEvent 回传值判断避免注册一堆不会呼叫的 eventHandler
window.addEventListener('${eventName}ld${messageFlag}', f, { once: true }); // 如checkEarlyStartScript 先执行,这个较后的event不会被呼叫。
// once: true 使呼叫后立即移除监听
}
})();但这样。。。 难道没有类似 (() => {
const func = function(){${autoDeleteMountCode}${scriptCode}};
const scriptInfo = ${JSON.stringify(script)};
const f = () => {
const event = new CustomEvent('sc${messageFlag}',
{ cancelable: true, detail: { scriptFlag: '${script.flag}', scriptInfo, func } });
return window.dispatchEvent(event); // checkEarlyStartScript 先执行的话,这里回传 false
};
const noCheckEarlyStartScript = f(); // checkEarlyStartScript 先执行的话,这里的 f() 会直接触发execEarlyScript; dispatchEvent 会回传 false
if (noCheckEarlyStartScript) { // checkEarlyStartScript 未执行
// 使用 dispatchEvent 回传值判断避免注册一堆不会呼叫的 eventHandler
window.addEventListener('${eventName}ld${messageFlag}', f, { once: true }); // 如checkEarlyStartScript 先执行,这个较后的event不会被呼叫。
// once: true 使呼叫后立即移除监听
}
return func(); // 真early-start. 不等待环境加载
})();的做法吗 |
也可以,不过这里也是和普通的方式保持一致,而且 details 传对象的话,不知道有没有一些限制,我觉得现在这样就好
func 不等环境加载,那就需要在这里面做上一些沙盒之类的处理,还有一些同步GM函数的处理(例如:GM_addElement),都是同步操作,其实也没关系吧 |
那先現在這樣。
这个改掉会比较好。不然要等多一个「一行代码」的脚本执行 async getContentJsCode() {
if (!this.contentJsCodePromise) {
this.contentJsCodePromise = fetch("/src/content.js")
.then((res) => res.text())
.catch((e) => {
console.error("Unable to fetch /src/content.js", e);
return undefined;
});
}
return this.contentJsCodePromise;
} // content.js
const contentJs = await this.getContentJsCode();
if (contentJs) {
retScript.push({
id: "scriptcat-content",
js: [{ code: `(function (MessageFlag) {\n${contentJs}\n})('${messageFlag}')` }],
matches: ["<all_urls>"],
allFrames: true,
runAt: "document_start",
world: "USER_SCRIPT",
excludeMatches,
excludeGlobs,
});
} |
Co-authored-by: cyfung1031 <[email protected]>
Co-authored-by: cyfung1031 <[email protected]>
There was a problem hiding this comment.
Pull Request Overview
本 PR 对 EarlyStart(早期启动)脚本机制进行了架构重构,采用事件通知机制替代原有的全局变量监听方案。
主要变更:
- 使用 CustomEvent 事件机制替代
definePropertyListener监听全局变量 - 引入
MessageFlags结构体统一管理多个消息标识符 - 移除动态注册/反注册 inject.js 的复杂逻辑
Reviewed Changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/inject.ts | 更新为使用 MessageFlags 对象替代单一的 MessageFlag |
| src/content.ts | 移除全局变量监听逻辑,直接使用 MessageFlags 初始化 |
| src/app/service/service_worker/utils.ts | compileInjectionCode 接收 MessageFlags 参数 |
| src/app/service/service_worker/utils.test.ts | 注释掉部分测试代码(待补充) |
| src/app/service/service_worker/script.ts | 删除脚本时移除 isEarlyStart 字段传递 |
| src/app/service/service_worker/runtime.ts | 核心重构:移除 earlyScriptFlags 管理,移除 reRegisterInjectScript 方法,使用 MessageFlags 结构 |
| src/app/service/queue.ts | TDeleteScript 类型定义移除 isEarlyStart 字段 |
| src/app/service/content/utils.ts | compilePreInjectScript 生成事件通知代码 |
| src/app/service/content/script_executor.ts | 使用事件监听替代属性监听处理早期脚本 |
| src/app/service/content/content.ts | 简化 pageLoad 方法,直接传递 MessageFlags |
| packages/message/server.test.ts | 测试用例更新为使用 MessageFlags 对象 |
| packages/message/custom_event_message.ts | 支持 MessageFlags 对象参数,向后兼容字符串参数 |
| example/tests/early_inject_content_test.js | 添加对首次 getValue 调用的测试 |
Co-authored-by: Copilot <[email protected]>
* ♻️ 重构 EarlyStart 实现 * 修复loadScriptPromise * 调整flag判断 * Update src/app/service/content/utils.ts Co-authored-by: cyfung1031 <[email protected]> * Update src/app/service/content/script_executor.ts Co-authored-by: cyfung1031 <[email protected]> * 重构messageFlag * 通过单元测试 * 修改代码 * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * 根据copilot修改 * 调整测试 --------- Co-authored-by: cyfung1031 <[email protected]> Co-authored-by: Copilot <[email protected]>
概述 Descriptions
close #870
变更内容 Changes
根据 #871 (comment) 的思路重构 early-start 实现
截图 Screenshots