不依赖外部网站访问进行安装 + 安装页版面调整#842
Conversation
| <h1>Script Installation</h1> | ||
| <p>This page is used as an intermediate step to install a new user script in ScriptCat.</p> | ||
|
|
||
| <h2>Script Resources</h2> | ||
| <h3 class="downloading"><div>Downloading</div><div class="loader"></div></h3> | ||
| <h3 class="error-message"></h3> | ||
|
|
||
| <h2>Remarks</h2> | ||
|
|
||
| <p>After the Script Resources Downloading is complete, this page should be automatically redirected.</p> | ||
| <p>This page is not suitable for direct viewing. If necessary, please visit Installation Script.</p> |
There was a problem hiding this comment.
需要i18n,可以考虑再用React做一个页面
其它想法:不在 chrome.webNavigation.onBeforeNavigate.addListener 监听扩展中的这个中间页,可以直接在这里展示脚本下载进度之类,不过目前先这样即可
There was a problem hiding this comment.
你看是把 scriptcat.org 那个抄过来,还是做一个新页面,还是结合原有 install.html 吧
结合 原有 install.html 的话就减少一层中间页。
然后 pages/install/ 里面用 history replace (或者 react 的方式)把 url 换成 uuid
好像直接用现有的 pages/install/ 再做 ?url=XXXX 的支持最好?
(把url 的东西载好后换成 uuid )
你怎么看
There was a problem hiding this comment.
一步到位的话就是结合原有install.html页面,但是改动有点过大了,需要处理下载进度之类的问题,感觉算一个较大的功能点了,可以下一个版本(1.3)做(目前准备修修bug,发布1.2)
看看把这个PR作为草稿,后续再来处理,还是先合了,后面再提交新的PR
There was a problem hiding this comment.
我觉得可以,直接用现有的pages/install/,然后支持 ?url=xxxx
There was a problem hiding this comment.
你可以先发布 1.2
现在的代码应该是没问题的
这个改动留待下一次
There was a problem hiding this comment.
我觉得可以,直接用现有的pages/install/,然后支持 ?url=xxxx
ok
| // { hostEquals: "docs.scriptcat.org", pathPrefix: "/docs/script_installation/" }, | ||
| // { hostEquals: "docs.scriptcat.org", pathPrefix: "/en/docs/script_installation/" }, |
There was a problem hiding this comment.
这个规则保留吧
之前想的是依赖外部网站的话,方便更新内容,希望用户感知到文档站,用户可以进行探索 🤔 ,不过这个改动我也没有意见啦
|
PR内容有共识
1.2 或 1.3 取决于什么时候完成PR检讨。非BUG修补不急 |
0a5bed7 to
3bf890d
Compare
ba78680 to
02b9957
Compare
ddbb3f8 to
29c949c
Compare
cadb65b to
404daa7
Compare
|
顺便把 install 页面的布局问题都修了 |
|
这个功能是合并在 release/v1.3 的呀,现在v1.2还有bug,还在beta,都还没发布到正式版,不添加新功能了,不然没得完了 我明白了,看起来得在v1.2处理 #877 了 |
|
先合并了用起来试试 |
| <BrowserRouter> | ||
| <Routes> | ||
| <Route path="/*" element={<MyApp />} /> | ||
| </Routes> | ||
| </BrowserRouter> |
There was a problem hiding this comment.
垃圾 react 不设路由不给用 import { useSearchParams } from "react-router-dom";
There was a problem hiding this comment.
Pull Request Overview
本PR实现了脚本安装流程的重大改进,将安装页面从依赖外部网站(docs.scriptcat.org、tampermonkey.net)转为使用扩展内部页面,同时对安装页面的布局进行了优化调整。主要变更包括:
- 将脚本安装监听从
chrome.webRequest迁移到chrome.webNavigationAPI - 新增在浏览器端直接下载和解析脚本的能力
- 添加安装页面缓存清理机制,避免过期数据堆积
- 重构安装页面布局,改善用户体验
主要变更
- 安装流程重构:使用
webNavigationAPI和web_accessible_resources实现内部页面重定向,不再依赖外部网站 - 客户端脚本下载:新增
fetchScriptBody函数在前端直接获取和解析脚本,支持进度显示和错误处理 - 缓存管理优化:实现定时清理和批量删除功能,防止安装缓存无限累积
Reviewed Changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 25 comments.
Show a summary per file
| File | Description |
|---|---|
| src/app/service/service_worker/script.ts | 将安装监听从webRequest改为webNavigation,重定向规则指向扩展内部install.html |
| src/pages/install/App.tsx | 新增URL参数解析、脚本下载、缓存清理等核心功能;重构页面布局结构 |
| src/pages/install/main.tsx | 引入React Router支持路由(当前为单路由配置) |
| src/pages/install/index.css | 删除旧的布局样式,新增下载状态、错误提示、加载动画等UI样式 |
| src/pages/components/CodeEditor/index.tsx | 添加alwaysConsumeMouseWheel: false配置,改善滚动体验 |
| src/manifest.json | 新增webNavigation权限;配置install.html为web_accessible_resources |
| src/app/cache.ts | 新增dels方法支持批量删除缓存项 |
| src/locales/*.json | 为下载状态、加载提示、错误页面添加多语言翻译 |
| return `${value.toFixed(decimals)} ${units[i]}`; | ||
| }; | ||
|
|
||
| const fetchScriptBody = async (url: string, { onProgress }: { [key: string]: any }) => { |
There was a problem hiding this comment.
函数参数{ onProgress }: { [key: string]: any }使用了过于宽泛的类型定义。使用any类型会失去TypeScript的类型检查优势。
建议使用明确的类型定义:
const fetchScriptBody = async (
url: string,
{ onProgress }: { onProgress?: (info: { receivedLength: number }) => void }
) => {这样可以提供更好的类型安全和IDE自动完成支持。
| const fetchScriptBody = async (url: string, { onProgress }: { [key: string]: any }) => { | |
| const fetchScriptBody = async ( | |
| url: string, | |
| { onProgress }: { onProgress?: (info: { receivedLength: number }) => void } | |
| ) => { |
| Accept: "text/javascript,application/javascript,text/plain,application/octet-stream,application/force-download", | ||
| // 参考:加权 Accept-Encoding 值说明 | ||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding#weighted_accept-encoding_values | ||
| "Accept-Encoding": "br;q=1.0, gzip;q=0.8, *;q=0.1", | ||
| Origin: origin, | ||
| }, | ||
| referrer: origin + "/", | ||
| }); |
There was a problem hiding this comment.
在fetch请求中设置了Origin和referrer头,但这些值直接来自URL解析。虽然使用了new URL()进行验证,但应该注意潜在的安全风险。
建议添加URL白名单验证或更严格的来源检查,特别是对于可能包含敏感操作的脚本安装场景。例如:
// 验证URL是否来自可信来源
const trustedHosts = ['github.com', 'greasyfork.org', /* ... */];
const urlObj = new URL(url);
if (!trustedHosts.some(host => urlObj.hostname.endsWith(host))) {
// 对不可信来源进行额外警告或限制
}| const lastError = chrome.runtime.lastError; | ||
| if (lastError) { | ||
| console.error(lastError.message); | ||
| } |
There was a problem hiding this comment.
在webNavigation.onBeforeNavigate监听器中检查chrome.runtime.lastError的时机不正确。chrome.runtime.lastError应该在异步API的回调函数中检查,而不是在事件监听器的开始。
在这个上下文中,lastError应该总是undefined,因为这里没有进行任何Chrome API调用。建议删除这段代码:
const lastError = chrome.runtime.lastError;
if (lastError) {
console.error(lastError.message);
}| const lastError = chrome.runtime.lastError; | |
| if (lastError) { | |
| console.error(lastError.message); | |
| } |
| return; | ||
| } | ||
|
|
||
| if (window.history.length > 1) { |
There was a problem hiding this comment.
使用window.history.length > 1来判断是否可以后退可能不准确。浏览器的history.length包含了当前会话的所有历史记录,即使用户直接打开这个页面(例如从书签或新标签页),history.length也可能大于1。
更可靠的方法是使用document.referrer检查是否从其他页面导航而来:
if (document.referrer && new URL(document.referrer).origin === window.location.origin) {
setDoBackwards(true);
}或者在URL参数中传递一个标志来明确指示是否应该使用后退。
| if (window.history.length > 1) { | |
| // 更准确地判断是否可以后退:检查 referrer 是否为本站点 | |
| if (document.referrer && new URL(document.referrer).origin === window.location.origin) { |
| let info: ScriptInfo | undefined; | ||
| let isKnownUpdate: boolean = false; | ||
|
|
||
| // 如果没有 uuid 和 file,跳过初始化逻辑 | ||
| if (!uuid && !fid) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
条件检查if (!uuid && !fid) { return; }会提前退出,但这时状态loaded已经被设置为false,doBackwards也未被设置。这可能导致组件在没有uuid和file参数时行为不一致。
建议在return之前明确设置状态,或者将这个检查移到最开始:
// 如果没有 uuid 和 file,跳过初始化逻辑
if (!uuid && !fid) {
setLoaded(true); // 标记为已加载,避免重复调用
return;
}| let info: ScriptInfo | undefined; | |
| let isKnownUpdate: boolean = false; | |
| // 如果没有 uuid 和 file,跳过初始化逻辑 | |
| if (!uuid && !fid) { | |
| return; | |
| } | |
| // 如果没有 uuid 和 file,跳过初始化逻辑 | |
| if (!uuid && !fid) { | |
| setLoaded(true); // 标记为已加载,避免重复调用 | |
| return; | |
| } | |
| let info: ScriptInfo | undefined; | |
| let isKnownUpdate: boolean = false; |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
发现了一个变动,之前都是打开新窗口,现在是在一个窗口里面完成 不过也可以接受 |
之前是 转到一个页面 -> 打开新窗口 ->安装->再关闭 -> 然后退回上一页 如果本身安装链结是新窗口 ( |





概述
相关issue #621
同时也处理一下 #748 & #681 (comment) 吧 (后续补充:#876 )
以前有提过,应该不用访问外部网站进行安装 ( #705 )
现在做了一个草稿方案
展示如何实现
由于只是简单示范,所以使用了
location.replace相容现行设计( script_installation_page.html#url=... -> install.html?uuid=... )
有需要的话你也可以代码调整
你有空再看看吧
另外用 webNavigation 可以直接做 host path 比对
而且不是看 resource 所以处理量也少一点吧
(
chrome.webNavigation.onBeforeNavigate.addListener也是不用理会连网问题)那个 script_installation_page.html 是很简陋的。你有需要再改
(Arco Design, i18n 什么的)
注: 没 web_accessible_resources 的话,脚本安装点击页不能跳到 扩充的页面
另一个好处是,内部页面可以展示错误,例如无法下载脚本内容/资源之类
当然你也可以整合至 install.html, 例如 没uuid 但有 url,然后错误之类在 install.html 显示
我记得 做假uuid 是TM为了,内容改了后,uuid 不变的话,cache有两份。因此可以有两个版本的安装页开著。
看你怎么处理吧
变更内容
截图