fix(design): 原型 serve 热重载 SSE 改短轮询——多标签 SSE 常驻连接占满 Chrome 同域 6 连接上限致整站卡死
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+15
-13
@@ -20,24 +20,26 @@ const MIME = {
|
||||
'.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>
|
||||
(function(){ try{
|
||||
var es=new EventSource('/__reload');
|
||||
es.onmessage=function(){ location.reload(); };
|
||||
var v=null;
|
||||
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){} })();
|
||||
</script>\n`;
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
if (req.url === '/__reload') {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
Connection: 'keep-alive',
|
||||
});
|
||||
res.write('retry: 500\n\n');
|
||||
clients.add(res);
|
||||
req.on('close', () => clients.delete(res));
|
||||
if (req.url === '/__version' || req.url === '/__reload') {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
|
||||
res.end(JSON.stringify({ v: version }));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +87,7 @@ fs.watch(ROOT, { recursive: true }, (_ev, file) => {
|
||||
if (file && file.endsWith('serve.mjs')) return;
|
||||
clearTimeout(debounce);
|
||||
debounce = setTimeout(() => {
|
||||
for (const c of clients) c.write('data: reload\n\n');
|
||||
version++;
|
||||
if (file && /\.(html|css|js)$/.test(file)) runDsCheck();
|
||||
}, 80);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user