@lovrozagar/flare 0.9.4 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/plugins/dev-server.ts +36 -19
package/package.json
CHANGED
|
@@ -12,8 +12,11 @@ interface NodeReq {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
interface NodeRes {
|
|
15
|
+
destroy: () => void;
|
|
15
16
|
end: (data?: unknown) => void;
|
|
17
|
+
headersSent?: boolean;
|
|
16
18
|
on: (event: string, fn: () => void) => void;
|
|
19
|
+
socket?: { off: (event: string, fn: () => void) => void; on: (event: string, fn: () => void) => void } | null;
|
|
17
20
|
writableEnded?: boolean;
|
|
18
21
|
write: (chunk: unknown) => void;
|
|
19
22
|
writeHead: (status: number, headers: Record<string, string | string[]>) => void;
|
|
@@ -71,7 +74,7 @@ function nodeToWebRequest(req: NodeReq, url: URL): Request {
|
|
|
71
74
|
} as RequestInit);
|
|
72
75
|
}
|
|
73
76
|
|
|
74
|
-
async function streamResponse(response: Response, res: NodeRes): Promise<void> {
|
|
77
|
+
export async function streamResponse(response: Response, res: NodeRes): Promise<void> {
|
|
75
78
|
const responseHeaders: Record<string, string | string[]> = {};
|
|
76
79
|
/* Set-Cookie must be sent as separate headers — Node.js writeHead
|
|
77
80
|
* accepts string[] for multi-value headers like Set-Cookie */
|
|
@@ -88,28 +91,42 @@ async function streamResponse(response: Response, res: NodeRes): Promise<void> {
|
|
|
88
91
|
}
|
|
89
92
|
res.writeHead(response.status, responseHeaders);
|
|
90
93
|
|
|
91
|
-
if (response.body) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
if (!response.body) {
|
|
95
|
+
res.end();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const reader = response.body.getReader();
|
|
99
|
+
/* A client that leaves mid-stream (closed tab, aborted navigation): cancel the body so
|
|
100
|
+
rendering stops, and never write to the closed response. Node and Bun 1.4 close `res`;
|
|
101
|
+
Bun 1.3 only closes the socket, so listen to both. */
|
|
102
|
+
let left = false;
|
|
103
|
+
const leave = () => {
|
|
104
|
+
if (left || res.writableEnded) return;
|
|
105
|
+
left = true;
|
|
106
|
+
reader.cancel().catch(() => {});
|
|
107
|
+
};
|
|
108
|
+
const socket = res.socket;
|
|
109
|
+
res.on("close", leave);
|
|
110
|
+
socket?.on("close", leave);
|
|
111
|
+
try {
|
|
112
|
+
while (true) {
|
|
94
113
|
const { done, value } = await reader.read();
|
|
95
|
-
if (done)
|
|
96
|
-
res.end();
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
114
|
+
if (done || left) break;
|
|
99
115
|
res.write(value);
|
|
100
|
-
return pump();
|
|
101
|
-
};
|
|
102
|
-
try {
|
|
103
|
-
await pump();
|
|
104
|
-
} finally {
|
|
105
|
-
reader.cancel().catch(() => {});
|
|
106
|
-
if (!res.writableEnded) res.end();
|
|
107
116
|
}
|
|
108
|
-
}
|
|
109
|
-
|
|
117
|
+
} finally {
|
|
118
|
+
/* Keep-alive sockets outlive this response. */
|
|
119
|
+
socket?.off("close", leave);
|
|
120
|
+
if (!left && !res.writableEnded) res.end();
|
|
110
121
|
}
|
|
111
122
|
}
|
|
112
123
|
|
|
124
|
+
/* Once the status line is out, an error can't become a 500: drop the connection instead. */
|
|
125
|
+
function failResponse(res: NodeRes, next: (err?: unknown) => void, error: unknown): void {
|
|
126
|
+
if (res.headersSent) res.destroy();
|
|
127
|
+
else next(error);
|
|
128
|
+
}
|
|
129
|
+
|
|
113
130
|
const INLINE_PLACEHOLDER = (i: number) => `<!--flare-inline-${i}-->`;
|
|
114
131
|
const INLINE_PLACEHOLDER_RE = /<!--flare-inline-(\d+)-->/g;
|
|
115
132
|
|
|
@@ -238,7 +255,7 @@ export function createDevServerPlugin(entries: ResolvedEntries, _assetsBase: str
|
|
|
238
255
|
if (e instanceof Error) {
|
|
239
256
|
vite.ssrFixStacktrace(e);
|
|
240
257
|
}
|
|
241
|
-
next
|
|
258
|
+
failResponse(res, next, e);
|
|
242
259
|
}
|
|
243
260
|
});
|
|
244
261
|
};
|
|
@@ -325,7 +342,7 @@ export function createPreviewServerPlugin(assetsBase: string = "/assets"): ViteP
|
|
|
325
342
|
const response = await handler.fetch(webReq);
|
|
326
343
|
await streamResponse(response, res);
|
|
327
344
|
} catch (e: unknown) {
|
|
328
|
-
next
|
|
345
|
+
failResponse(res, next, e);
|
|
329
346
|
}
|
|
330
347
|
});
|
|
331
348
|
};
|