Skip to content

Commit f575b5b

Browse files
committed
fix: review
1 parent f0ecc7b commit f575b5b

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

src/hmr-sse-bridge.ts

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import type { Buffer } from 'node:buffer'
12
import type { IncomingMessage, ServerResponse } from 'node:http'
23
import type { ViteDevServer } from 'vite'
34

45
const SSE_PATH = '/__hmr_sse'
56
const SEND_PATH = '/__hmr_send'
7+
const MAX_POST_BODY = 64 * 1024 // 64KB limit for client messages
68

79
export function setupHmrSseBridge(server: ViteDevServer): void {
810
const sseClients = new Set<ServerResponse>()
@@ -24,9 +26,14 @@ export function setupHmrSseBridge(server: ViteDevServer): void {
2426
payload = JSON.stringify(args[0])
2527
}
2628

27-
// Push to all SSE clients
29+
// Push to all SSE clients (skip errored ones)
2830
for (const res of sseClients) {
29-
res.write(`data: ${payload}\n\n`)
31+
try {
32+
res.write(`data: ${payload}\n\n`)
33+
}
34+
catch {
35+
sseClients.delete(res)
36+
}
3037
}
3138
}
3239

@@ -57,7 +64,6 @@ function handleSseConnection(
5764
'Content-Type': 'text/event-stream',
5865
'Cache-Control': 'no-cache',
5966
'Connection': 'keep-alive',
60-
'Access-Control-Allow-Origin': '*',
6167
})
6268

6369
// Send initial connected message (same as Vite's WebSocket)
@@ -67,13 +73,19 @@ function handleSseConnection(
6773

6874
// Keep-alive ping every 30s
6975
const keepAlive = setInterval(() => {
70-
res.write(': ping\n\n')
76+
try {
77+
res.write(': ping\n\n')
78+
}
79+
catch { cleanup() }
7180
}, 30000)
7281

73-
res.on('close', () => {
82+
function cleanup(): void {
7483
clearInterval(keepAlive)
7584
sseClients.delete(res)
76-
})
85+
}
86+
87+
res.on('close', cleanup)
88+
res.on('error', cleanup)
7789
}
7890

7991
function handleClientMessage(
@@ -82,10 +94,20 @@ function handleClientMessage(
8294
server: ViteDevServer,
8395
): void {
8496
let body = ''
97+
let overflow = false
8598
req.on('data', (chunk: Buffer) => {
8699
body += chunk.toString()
100+
if (body.length > MAX_POST_BODY) {
101+
overflow = true
102+
req.destroy()
103+
}
87104
})
88105
req.on('end', () => {
106+
if (overflow) {
107+
res.writeHead(413)
108+
res.end('{"ok":false}')
109+
return
110+
}
89111
try {
90112
const data = JSON.parse(body)
91113
// Forward custom events to Vite's HMR server
@@ -102,7 +124,6 @@ function handleClientMessage(
102124
}
103125
res.writeHead(200, {
104126
'Content-Type': 'application/json',
105-
'Access-Control-Allow-Origin': '*',
106127
})
107128
res.end('{"ok":true}')
108129
}
@@ -237,7 +258,8 @@ export const hmrSseBridgeClientScript = `
237258
PatchedWebSocket.OPEN = 1;
238259
PatchedWebSocket.CLOSING = 2;
239260
PatchedWebSocket.CLOSED = 3;
240-
PatchedWebSocket.prototype = OriginalWebSocket.prototype;
261+
PatchedWebSocket.prototype = Object.create(OriginalWebSocket.prototype);
262+
PatchedWebSocket.prototype.constructor = PatchedWebSocket;
241263
242264
window.WebSocket = PatchedWebSocket;
243265
})();

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ let config: ResolvedConfig
1313

1414
let caddy: CaddyInstant
1515

16+
let hmrSseBridgeActive = false
17+
1618
const cwd = process.cwd()
1719

1820
function colorUrl(url: string): string {
@@ -124,11 +126,12 @@ export const unpluginFactory: UnpluginFactory<Options> = options => ({
124126
// Setup SSE bridge for iOS Safari WSS workaround
125127
if (options.https) {
126128
setupHmrSseBridge(server)
129+
hmrSseBridgeActive = true
127130
consola.info('HMR SSE bridge enabled for iOS Safari WSS workaround')
128131
}
129132
},
130133
transformIndexHtml() {
131-
if (config.command !== 'serve' || !options.https)
134+
if (!hmrSseBridgeActive)
132135
return []
133136
// Inject client-side script to patch WebSocket on iOS Safari
134137
return [{

0 commit comments

Comments
 (0)