fix(design): 原型 serve 热重载 SSE 改短轮询——多标签 SSE 常驻连接占满 Chrome 同域 6 连接上限致整站卡死

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-07-10 20:18:48 +08:00
parent 658df690f6
commit adfa0ca34c
+15 -13
View File
@@ -20,24 +20,26 @@ const MIME = {
'.woff2': 'font/woff2', '.woff2': 'font/woff2',
}; };
const clients = new Set(); // 热重载改短轮询(2026-07-10):原 SSE 每个 tab 一条常驻连接,Chrome 同域
// HTTP/1.1 上限 6 条——开到第 7 个原型 tab 连接池耗尽整站卡死。轮询即用即断,无上限。
let version = 0;
const RELOAD_SNIPPET = `\n<script> const RELOAD_SNIPPET = `\n<script>
(function(){ try{ (function(){ try{
var es=new EventSource('/__reload'); var v=null;
es.onmessage=function(){ location.reload(); }; function tick(){
fetch('/__version',{cache:'no-store'}).then(function(r){return r.json();}).then(function(j){
if(v!==null && j.v!==v){ location.reload(); return; }
v=j.v; setTimeout(tick,1500);
}).catch(function(){ setTimeout(tick,3000); });
}
tick();
}catch(e){} })(); }catch(e){} })();
</script>\n`; </script>\n`;
const server = http.createServer((req, res) => { const server = http.createServer((req, res) => {
if (req.url === '/__reload') { if (req.url === '/__version' || req.url === '/__reload') {
res.writeHead(200, { res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
'Content-Type': 'text/event-stream', res.end(JSON.stringify({ v: version }));
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
});
res.write('retry: 500\n\n');
clients.add(res);
req.on('close', () => clients.delete(res));
return; return;
} }
@@ -85,7 +87,7 @@ fs.watch(ROOT, { recursive: true }, (_ev, file) => {
if (file && file.endsWith('serve.mjs')) return; if (file && file.endsWith('serve.mjs')) return;
clearTimeout(debounce); clearTimeout(debounce);
debounce = setTimeout(() => { debounce = setTimeout(() => {
for (const c of clients) c.write('data: reload\n\n'); version++;
if (file && /\.(html|css|js)$/.test(file)) runDsCheck(); if (file && /\.(html|css|js)$/.test(file)) runDsCheck();
}, 80); }, 80);
}); });