From 052d16a0d5f81163632731dbccd0065ba27c5675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horv=C3=A1th=20D=C3=A1niel?= Date: Wed, 7 Aug 2024 03:28:16 +0200 Subject: [PATCH] fix: fix leaking promise --- .../src/runtime/adapters/connectToWeb.ts | 27 +++++++--------- .../runtime/adapters/createServerResponse.ts | 32 +++++++++---------- .../src/runtime/frameworks/fastify.ts | 7 ++-- packages/vike-node/src/runtime/handler.ts | 13 ++++---- 4 files changed, 37 insertions(+), 42 deletions(-) diff --git a/packages/vike-node/src/runtime/adapters/connectToWeb.ts b/packages/vike-node/src/runtime/adapters/connectToWeb.ts index 944fd19..3e1bb7b 100644 --- a/packages/vike-node/src/runtime/adapters/connectToWeb.ts +++ b/packages/vike-node/src/runtime/adapters/connectToWeb.ts @@ -31,22 +31,17 @@ function connectToWeb(handler: ConnectMiddleware): WebHandler { const { res, onReadable } = createServerResponse(req) return new Promise((resolve, reject) => { - ;(async () => { - try { - const { readable, headers, statusCode } = await onReadable - const responseBody = statusCodesWithoutBody.includes(statusCode) - ? null - : (Readable.toWeb(readable) as ReadableStream) - resolve( - new Response(responseBody, { - status: statusCode, - headers: flattenHeaders(headers) - }) - ) - } catch (error) { - reject(error instanceof Error ? error : new Error('Error creating response')) - } - })() + onReadable(({ readable, headers, statusCode }) => { + const responseBody = statusCodesWithoutBody.includes(statusCode) + ? null + : (Readable.toWeb(readable) as ReadableStream) + resolve( + new Response(responseBody, { + status: statusCode, + headers: flattenHeaders(headers) + }) + ) + }) const next = (error?: unknown) => { if (error) { diff --git a/packages/vike-node/src/runtime/adapters/createServerResponse.ts b/packages/vike-node/src/runtime/adapters/createServerResponse.ts index 94e8c72..579e83e 100644 --- a/packages/vike-node/src/runtime/adapters/createServerResponse.ts +++ b/packages/vike-node/src/runtime/adapters/createServerResponse.ts @@ -7,35 +7,35 @@ import { PassThrough, Readable } from 'stream' * Creates a custom ServerResponse object that allows for intercepting and streaming the response. * * @param {IncomingMessage} incomingMessage - The incoming HTTP request message. - * @returns {{ res: ServerResponse; onReadable: Promise<{ readable: Readable; headers: OutgoingHttpHeaders; statusCode: number }> }} + * @returns {{ + * res: ServerResponse; + * onReadable: (cb: (result: { readable: Readable; headers: OutgoingHttpHeaders; statusCode: number }) => void) => void + * }} * An object containing: * - res: The custom ServerResponse object. - * - onReadable: A promise that resolves when the response is readable, providing the readable stream, headers, and status code. + * - onReadable: A function that takes a callback. The callback is invoked when the response is readable, + * providing an object with the readable stream, headers, and status code. */ function createServerResponse(incomingMessage: IncomingMessage) { const res = new ServerResponse(incomingMessage) const passThrough = new PassThrough() - const onReadable = new Promise<{ readable: Readable; headers: OutgoingHttpHeaders; statusCode: number }>( - (resolve, reject) => { - const handleReadable = () => { - resolve({ readable: Readable.from(passThrough), headers: res.getHeaders(), statusCode: res.statusCode }) - } - const handleError = (err: Error) => { - reject(err) - } - - passThrough.once('readable', handleReadable) - passThrough.once('end', handleReadable) - passThrough.once('error', handleError) - res.once('error', handleError) + const onReadable = ( + cb: (result: { readable: Readable; headers: OutgoingHttpHeaders; statusCode: number }) => void + ) => { + const handleReadable = () => { + cb({ readable: Readable.from(passThrough), headers: res.getHeaders(), statusCode: res.statusCode }) } - ) + + passThrough.once('readable', handleReadable) + passThrough.once('end', handleReadable) + } passThrough.once('finish', () => { res.emit('finish') }) passThrough.once('close', () => { + res.destroy() res.emit('close') }) passThrough.on('drain', () => { diff --git a/packages/vike-node/src/runtime/frameworks/fastify.ts b/packages/vike-node/src/runtime/frameworks/fastify.ts index 93a84c7..3f2d1ae 100644 --- a/packages/vike-node/src/runtime/frameworks/fastify.ts +++ b/packages/vike-node/src/runtime/frameworks/fastify.ts @@ -2,9 +2,9 @@ export { vike } import type { FastifyPluginCallback, FastifyRequest } from 'fastify' import { createServerResponse } from '../adapters/createServerResponse.js' +import { globalStore } from '../globalStore.js' import { createHandler } from '../handler.js' import type { VikeOptions } from '../types.js' -import { globalStore } from '../globalStore.js' /** * Creates a Fastify plugin to handle Vike requests and Hot Module Replacement (HMR). @@ -36,12 +36,11 @@ function vike(options?: VikeOptions): FastifyPluginCallback { instance.get('*', async (req, reply) => { globalStore.setupHMRProxy(req.raw) const { res, onReadable } = createServerResponse(req.raw) - ;(async () => { - const { readable, headers, statusCode } = await onReadable + onReadable(({ readable, headers, statusCode }) => { reply.code(statusCode) reply.headers(headers) reply.send(readable) - })() + }) await handler({ req: req.raw, res, diff --git a/packages/vike-node/src/runtime/handler.ts b/packages/vike-node/src/runtime/handler.ts index aa4c2ca..de19160 100644 --- a/packages/vike-node/src/runtime/handler.ts +++ b/packages/vike-node/src/runtime/handler.ts @@ -7,12 +7,6 @@ import { globalStore } from './globalStore.js' import type { ConnectMiddleware, VikeOptions } from './types.js' import { writeHttpResponse } from './utils/writeHttpResponse.js' -const argv1 = process.argv[1] -const entrypointDirAbs = argv1 - ? dirname(isAbsolute(argv1) ? argv1 : join(process.cwd(), argv1)) - : dirname(fileURLToPath(import.meta.url)) -const defaultStaticDir = join(entrypointDirAbs, '..', 'client') - export function createHandler(options: VikeOptions = {}) { const staticConfig = resolveStaticConfig(options.static) const shouldCache = staticConfig && staticConfig.cache @@ -124,6 +118,13 @@ function resolveStaticConfig(static_: VikeOptions['static']): false | { root: st // See vercel.json > outputDirectory if (process.env.VERCEL) return false if (static_ === false) return false + + const argv1 = process.argv[1] + const entrypointDirAbs = argv1 + ? dirname(isAbsolute(argv1) ? argv1 : join(process.cwd(), argv1)) + : dirname(fileURLToPath(import.meta.url)) + const defaultStaticDir = join(entrypointDirAbs, '..', 'client') + if (static_ === true || static_ === undefined) { return { root: defaultStaticDir, cache: true } }