Files
u-claw/portable/lib/loading.html
hfshfg f715aef9c9 perf(portable): U盘启动加速 — 缓存搬本机 + 启动首屏 + 首轮预热
便携版从 U 盘启动慢,瓶颈在 U 盘随机小写 IO + 首屏无反馈 + 首轮冷启动。
移植 v2 u-clawx 4.0 的 4 个可在纯脚本层复刻的手段(均零依赖、静默失败):

- portable-cache.mjs: 把浏览器 user-data(几百 MB 随机小写)+ V8 编译缓存
  从 U 盘搬到本机 SSD(win junction / mac symlink 重定向 .openclaw/browser,
  NODE_COMPILE_CACHE 落本机)。UUID 隔离让换盘符仍命中同一份缓存。
  业务数据(openclaw.json/memory/账号)仍留 U 盘,便携性不变。
- loading.html: 双击即弹的启动首屏,自轮询 /ready,gateway 真就绪后自动跳
  Dashboard——天然规避"gateway 没起就开 Dashboard 拒连"(issue #46/#48)。
- prewarm.mjs: gateway 首轮预热,后台静默唤醒 config/model 子系统。
- Windows-Start.bat: 等 config-server 改写死 timeout 为动态轮询 18788。
- wait-gateway.bat 退居兜底(首屏页负责主跳转)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:38:05 +08:00

139 lines
4.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>U-Claw 正在启动…</title>
<!--
启动首屏(移植自 v2 u-clawx 4.0 的 splash 思路)。
双击启动脚本后立刻打开本页,给用户即时反馈,消除"黑窗假死"体感。
本页每秒自查 gateway 是否就绪fetch /ready就绪后自动跳转 Dashboard。
端口通过 URL 查询参数传入loading.html?port=18789
(启动脚本打开时拼好。默认 18789。
-->
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; }
body {
font-family: -apple-system, "Microsoft YaHei", "PingFang SC", sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.box {
text-align: center;
max-width: 460px;
padding: 40px;
}
.logo { font-size: 64px; line-height: 1; margin-bottom: 18px; }
h1 { font-size: 1.7em; font-weight: 600; margin-bottom: 8px; }
.tip { opacity: .85; font-size: 1.02em; line-height: 1.6; margin-bottom: 28px; }
.spinner {
width: 46px; height: 46px;
margin: 0 auto 24px;
border: 4px solid rgba(255,255,255,.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin .9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.bar {
height: 6px; width: 100%;
background: rgba(255,255,255,.2);
border-radius: 999px;
overflow: hidden;
margin-bottom: 14px;
}
.bar > i {
display: block; height: 100%; width: 30%;
background: #fff; border-radius: 999px;
animation: slide 1.6s ease-in-out infinite;
}
@keyframes slide {
0% { margin-left: -30%; }
100% { margin-left: 100%; }
}
.status { font-size: .95em; opacity: .9; min-height: 1.4em; }
.elapsed { font-size: .82em; opacity: .6; margin-top: 6px; }
.note {
margin-top: 30px; font-size: .82em; opacity: .65; line-height: 1.6;
}
a.manual { color: #fff; text-decoration: underline; opacity: .9; }
</style>
</head>
<body>
<div class="box">
<div class="logo">🦞</div>
<h1>U-Claw 正在启动</h1>
<div class="tip">首次从 U 盘启动需要展开内置组件,<br>稍等片刻,就绪后会自动打开。</div>
<div class="spinner"></div>
<div class="bar"><i></i></div>
<div class="status" id="status">正在等待 OpenClaw 网关…</div>
<div class="elapsed" id="elapsed"></div>
<div class="note">
慢 U 盘首次启动通常 3090 秒。<br>
如果迟迟没反应,可手动打开
<a class="manual" id="manual" href="#">控制台</a>
</div>
</div>
<script>
(function () {
var params = new URLSearchParams(location.search);
var port = parseInt(params.get('port'), 10) || 18789;
var token = params.get('token') || 'uclaw';
var base = 'http://127.0.0.1:' + port;
var dashboard = base + '/#token=' + encodeURIComponent(token);
var configCenter = 'http://127.0.0.1:18788/';
document.getElementById('manual').href = dashboard;
var startedAt = Date.now();
var redirected = false;
function fmt(ms) {
var s = Math.floor(ms / 1000);
return '已等待 ' + s + ' 秒';
}
function tickElapsed() {
document.getElementById('elapsed').textContent = fmt(Date.now() - startedAt);
}
setInterval(tickElapsed, 1000);
tickElapsed();
function goDashboard() {
if (redirected) return;
redirected = true;
document.getElementById('status').textContent = '网关已就绪,正在打开控制台…';
setTimeout(function () { location.replace(dashboard); }, 400);
}
function poll() {
if (redirected) return;
// /ready 就绪即跳。no-cors 下拿不到 status但 fetch 成功 resolve 就说明端口活了。
fetch(base + '/ready', { mode: 'no-cors', cache: 'no-store' })
.then(function () { goDashboard(); })
.catch(function () {
// 端口还没起,继续等
setTimeout(poll, 1000);
});
}
poll();
// 兜底5 分钟还没起来,提示去控制台
setTimeout(function () {
if (!redirected) {
document.getElementById('status').innerHTML =
'启动较慢,可先打开 <a class="manual" href="' + configCenter + '">配置中心</a> 检查';
}
}, 300000);
})();
</script>
</body>
</html>