From 4913908710ae3fc46b4249c7b5bcb0d2f48a8211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Charles?= Date: Wed, 16 Oct 2024 10:53:15 +0200 Subject: [PATCH] chore: cleanup --- .../src/runtime/adapters/connectToWeb.ts | 41 +----- .../src/runtime/frameworks/connect.ts | 3 +- .../src/runtime/handler-node-only.ts | 121 ------------------ .../src/runtime/handler-web-and-node.ts | 44 ------- .../vike-node/src/runtime/handler-web-only.ts | 12 -- packages/vike-node/src/runtime/types.ts | 2 +- .../src/runtime/utils/header-utils.ts | 25 +--- .../runtime/utils/resolve-static-config.ts | 29 +++++ .../src/runtime/utils/writeHttpResponse.ts | 18 --- .../vike-node/src/runtime/vike-handler.ts | 20 +-- packages/vike-node/tsup.config.js | 4 +- 11 files changed, 51 insertions(+), 268 deletions(-) delete mode 100644 packages/vike-node/src/runtime/handler-node-only.ts delete mode 100644 packages/vike-node/src/runtime/handler-web-and-node.ts delete mode 100644 packages/vike-node/src/runtime/handler-web-only.ts create mode 100644 packages/vike-node/src/runtime/utils/resolve-static-config.ts delete mode 100644 packages/vike-node/src/runtime/utils/writeHttpResponse.ts diff --git a/packages/vike-node/src/runtime/adapters/connectToWeb.ts b/packages/vike-node/src/runtime/adapters/connectToWeb.ts index d0fb25c..6bd058d 100644 --- a/packages/vike-node/src/runtime/adapters/connectToWeb.ts +++ b/packages/vike-node/src/runtime/adapters/connectToWeb.ts @@ -1,11 +1,11 @@ -export { connectToWeb, connectToWebFallback } +export { connectToWeb } import type { IncomingMessage } from 'node:http' import { Readable } from 'node:stream' +import { DUMMY_BASE_URL } from '../constants.js' import type { ConnectMiddleware, ConnectMiddlewareBoolean, WebHandler } from '../types.js' import { flattenHeaders } from '../utils/header-utils.js' import { createServerResponse } from './createServerResponse.js' -import { DUMMY_BASE_URL } from '../constants.js' const statusCodesWithoutBody = [ 100, // Continue @@ -20,41 +20,10 @@ const statusCodesWithoutBody = [ /** * Converts a Connect-style middleware to a web-compatible request handler. * - * @param {ConnectMiddleware} handler - The Connect-style middleware function to be converted. + * @param {ConnectMiddleware | ConnectMiddlewareBoolean} handler - The Connect-style middleware function to be converted. * @returns {WebHandler} A function that handles web requests and returns a Response or undefined. */ -function connectToWeb(handler: ConnectMiddleware): WebHandler { - return async (request: Request): Promise => { - const req = createIncomingMessage(request) - const { res, onReadable } = createServerResponse(req) - - return new Promise((resolve, reject) => { - 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) { - reject(error instanceof Error ? error : new Error(String(error))) - } else { - resolve(undefined) - } - } - - Promise.resolve(handler(req, res, next)).catch(next) - }) - } -} - -function connectToWebFallback(handler: ConnectMiddlewareBoolean): WebHandler { +function connectToWeb(handler: ConnectMiddleware | ConnectMiddlewareBoolean): WebHandler { return async (request: Request): Promise => { const req = createIncomingMessage(request) const { res, onReadable } = createServerResponse(req) @@ -83,7 +52,7 @@ function connectToWebFallback(handler: ConnectMiddlewareBoolean): WebHandler { try { const handled = await handler(req, res, next) - if (!handled) { + if (handled === false) { res.destroy() resolve(undefined) } diff --git a/packages/vike-node/src/runtime/frameworks/connect.ts b/packages/vike-node/src/runtime/frameworks/connect.ts index 19f0927..8c30782 100644 --- a/packages/vike-node/src/runtime/frameworks/connect.ts +++ b/packages/vike-node/src/runtime/frameworks/connect.ts @@ -1,9 +1,8 @@ export { vike } import type { IncomingMessage, ServerResponse } from 'http' -import { createHandler } from '../handler-node-only.js' -import type { NextFunction, VikeOptions } from '../types.js' import { globalStore } from '../globalStore.js' +import type { NextFunction, VikeOptions } from '../types.js' /** * Creates middleware for Express-like frameworks to handle Vike requests. diff --git a/packages/vike-node/src/runtime/handler-node-only.ts b/packages/vike-node/src/runtime/handler-node-only.ts deleted file mode 100644 index ffef152..0000000 --- a/packages/vike-node/src/runtime/handler-node-only.ts +++ /dev/null @@ -1,121 +0,0 @@ -import type { IncomingMessage, ServerResponse } from 'http' -import { dirname, isAbsolute, join } from 'path' -import { fileURLToPath } from 'url' - -import { assert } from '../utils/assert.js' -import { globalStore } from './globalStore.js' -import type { ConnectMiddleware, VikeOptions } from './types.js' -import { writeHttpResponse } from './utils/writeHttpResponse.js' -import { renderPage } from './vike-handler.js' -import { parseHeaders } from './utils/header-utils.js' -import { isVercel } from '../utils/isVercel.js' - -export function createHandler(options: VikeOptions = {}) { - const staticConfig = resolveStaticConfig(options.static) - const shouldCache = staticConfig && staticConfig.cache - const compressionType = options.compress ?? !isVercel() - let staticMiddleware: ConnectMiddleware | undefined - let compressMiddleware: ConnectMiddleware | undefined - - return async function handler({ - req, - res, - next, - platformRequest - }: { - req: IncomingMessage - res: ServerResponse - next?: (err?: unknown) => void - platformRequest: PlatformRequest - }): Promise { - if (req.method !== 'GET') { - next?.() - return false - } - - if (globalStore.isPluginLoaded) { - const handled = await handleViteDevServer(req, res) - if (handled) return true - } else { - const isAsset = req.url?.startsWith('/assets/') - const shouldCompressResponse = compressionType === true || (compressionType === 'static' && isAsset) - if (shouldCompressResponse) { - await applyCompression(req, res, shouldCache) - } - - if (staticConfig) { - const handled = await serveStaticFiles(req, res, staticConfig) - if (handled) return true - } - } - - const httpResponse = await renderPage({ - url: req.url!, - headers: parseHeaders(req.headers), - options - }) - if (!httpResponse) { - next?.() - return false - } - await writeHttpResponse(httpResponse, res) - return true - } - - async function applyCompression(req: IncomingMessage, res: ServerResponse, shouldCache: boolean) { - if (!compressMiddleware) { - const { default: shrinkRay } = await import('@nitedani/shrink-ray-current') - compressMiddleware = shrinkRay({ cacheSize: shouldCache ? '128mB' : false }) as ConnectMiddleware - } - compressMiddleware(req, res, () => {}) - } - - async function serveStaticFiles( - req: IncomingMessage, - res: ServerResponse, - config: { root: string; cache: boolean } - ): Promise { - if (!staticMiddleware) { - const { default: sirv } = await import('sirv') - staticMiddleware = sirv(config.root, { etag: true }) - } - - return new Promise((resolve) => { - res.once('close', () => resolve(true)) - staticMiddleware!(req, res, () => resolve(false)) - }) - } -} - -function handleViteDevServer(req: IncomingMessage, res: ServerResponse): Promise { - return new Promise((resolve) => { - res.once('close', () => resolve(true)) - assert(globalStore.viteDevServer) - globalStore.viteDevServer.middlewares(req, res, () => resolve(false)) - }) -} - -export function resolveStaticConfig(static_: VikeOptions['static']): false | { root: string; cache: boolean } { - // Disable static file serving for Vercel - // Vercel will serve static files on its own - // See vercel.json > outputDirectory - if (isVercel()) 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 } - } - if (typeof static_ === 'string') { - return { root: static_, cache: true } - } - return { - root: static_.root ?? defaultStaticDir, - cache: static_.cache ?? true - } -} diff --git a/packages/vike-node/src/runtime/handler-web-and-node.ts b/packages/vike-node/src/runtime/handler-web-and-node.ts deleted file mode 100644 index f0a05a7..0000000 --- a/packages/vike-node/src/runtime/handler-web-and-node.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { isNodeLike } from '../utils/isNodeLike.js' -import type { VikeOptions } from './types.js' - -type Handler = (params: { - request: Request - platformRequest: PlatformRequest -}) => Response | undefined | Promise - -export function createHandler(options: VikeOptions = {}): Handler { - let nodeLike: boolean | undefined = undefined - let nodeHandler: Handler | undefined = undefined - let webHandler: Handler | undefined = undefined - - return async function handler({ request, platformRequest }) { - if (request.method !== 'GET') { - return undefined - } - - nodeLike ??= await isNodeLike() - - if (nodeLike) { - if (!nodeHandler) { - const { connectToWeb } = await import('./adapters/connectToWeb.js') - const { createHandler } = await import('./handler-node-only.js') - const nodeOnlyHandler = createHandler(options) - nodeHandler = ({ request, platformRequest }) => { - const connectedHandler = connectToWeb((req, res, next) => - nodeOnlyHandler({ req, res, platformRequest, next }) - ) - return connectedHandler(request) - } - } - - return nodeHandler({ request, platformRequest }) - } - - if (!webHandler) { - const { createHandler } = await import('./handler-web-only.js') - webHandler = createHandler(options) - } - - return webHandler({ request, platformRequest }) - } -} diff --git a/packages/vike-node/src/runtime/handler-web-only.ts b/packages/vike-node/src/runtime/handler-web-only.ts deleted file mode 100644 index 2ba5b72..0000000 --- a/packages/vike-node/src/runtime/handler-web-only.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { VikeOptions } from './types.js' -import { parseHeaders } from './utils/header-utils.js' -import { renderPageWeb } from './vike-handler.js' - -export function createHandler(options: VikeOptions = {}) { - return async function handler({ request, platformRequest }: { request: Request; platformRequest: PlatformRequest }) { - if (request.method !== 'GET') { - return undefined - } - return renderPageWeb({ url: request.url, headers: parseHeaders(request.headers), platformRequest, options }) - } -} diff --git a/packages/vike-node/src/runtime/types.ts b/packages/vike-node/src/runtime/types.ts index 8c5db2d..155bb2a 100644 --- a/packages/vike-node/src/runtime/types.ts +++ b/packages/vike-node/src/runtime/types.ts @@ -12,7 +12,7 @@ export type VikeOptions = { export type ConnectMiddleware< PlatformRequest extends IncomingMessage = IncomingMessage, PlatformResponse extends ServerResponse = ServerResponse -> = (req: PlatformRequest, res: PlatformResponse, next: NextFunction) => void +> = (req: PlatformRequest, res: PlatformResponse, next: NextFunction) => void | Promise export type ConnectMiddlewareBoolean< PlatformRequest extends IncomingMessage = IncomingMessage, PlatformResponse extends ServerResponse = ServerResponse diff --git a/packages/vike-node/src/runtime/utils/header-utils.ts b/packages/vike-node/src/runtime/utils/header-utils.ts index 90786c9..3e08b43 100644 --- a/packages/vike-node/src/runtime/utils/header-utils.ts +++ b/packages/vike-node/src/runtime/utils/header-utils.ts @@ -1,29 +1,8 @@ -export { flattenHeaders, groupHeaders, parseHeaders } +export { flattenHeaders, parseHeaders } -import type { OutgoingHttpHeaders } from 'http' +import type { OutgoingHttpHeaders } from 'node:http' import { HeadersProvided } from '../types.js' -function groupHeaders(headers: [string, string][]): [string, string | string[]][] { - const grouped: { [key: string]: string | string[] } = {} - - headers.forEach(([key, value]) => { - if (grouped[key]) { - // If the key already exists, append the new value - if (Array.isArray(grouped[key])) { - ;(grouped[key] as string[]).push(value) - } else { - grouped[key] = [grouped[key] as string, value] - } - } else { - // If the key doesn't exist, add it to the object - grouped[key] = value - } - }) - - // Convert the object back to an array - return Object.entries(grouped) -} - function flattenHeaders(headers: OutgoingHttpHeaders): [string, string][] { const flatHeaders: [string, string][] = [] diff --git a/packages/vike-node/src/runtime/utils/resolve-static-config.ts b/packages/vike-node/src/runtime/utils/resolve-static-config.ts new file mode 100644 index 0000000..1821384 --- /dev/null +++ b/packages/vike-node/src/runtime/utils/resolve-static-config.ts @@ -0,0 +1,29 @@ +import { dirname, isAbsolute, join } from 'node:path' +import { fileURLToPath } from 'node:url' +import { isVercel } from '../../utils/isVercel.js' +import type { VikeOptions } from '../types.js' + +export function resolveStaticConfig(static_: VikeOptions['static']): false | { root: string; cache: boolean } { + // Disable static file serving for Vercel + // Vercel will serve static files on its own + // See vercel.json > outputDirectory + if (isVercel()) 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 } + } + if (typeof static_ === 'string') { + return { root: static_, cache: true } + } + return { + root: static_.root ?? defaultStaticDir, + cache: static_.cache ?? true + } +} diff --git a/packages/vike-node/src/runtime/utils/writeHttpResponse.ts b/packages/vike-node/src/runtime/utils/writeHttpResponse.ts deleted file mode 100644 index 488cec2..0000000 --- a/packages/vike-node/src/runtime/utils/writeHttpResponse.ts +++ /dev/null @@ -1,18 +0,0 @@ -export { writeHttpResponse } - -import type { ServerResponse } from 'http' -import { assert } from '../../utils/assert.js' -import type { VikeHttpResponse } from '../types.js' -import { groupHeaders } from './header-utils.js' - -async function writeHttpResponse(httpResponse: VikeHttpResponse, res: ServerResponse) { - assert(httpResponse) - const { statusCode, headers } = httpResponse - const groupedHeaders = groupHeaders(headers) - groupedHeaders.forEach(([name, value]) => res.setHeader(name, value)) - res.statusCode = statusCode - httpResponse.pipe(res) - await new Promise((resolve) => { - res.once('close', resolve) - }) -} diff --git a/packages/vike-node/src/runtime/vike-handler.ts b/packages/vike-node/src/runtime/vike-handler.ts index 5194392..50f6718 100644 --- a/packages/vike-node/src/runtime/vike-handler.ts +++ b/packages/vike-node/src/runtime/vike-handler.ts @@ -1,13 +1,13 @@ -import { parseHeaders } from './utils/header-utils.js' -import { renderPage as _renderPage } from 'vike/server' -import type { ConnectMiddleware, VikeHttpResponse, VikeOptions } from './types.js' -import { type Get, pipe, type UniversalHandler, type UniversalMiddleware } from '@universal-middleware/core' +import type { IncomingMessage, ServerResponse } from 'http' import compressMiddlewareFactory from '@universal-middleware/compress' -import { globalStore } from './globalStore.js' +import { type Get, type UniversalHandler, type UniversalMiddleware, pipe } from '@universal-middleware/core' +import { renderPage as _renderPage } from 'vike/server' import { assert } from '../utils/assert.js' -import type { IncomingMessage, ServerResponse } from 'http' -import { connectToWebFallback } from './adapters/connectToWeb.js' import { isVercel } from '../utils/isVercel.js' +import { connectToWeb } from './adapters/connectToWeb.js' +import { globalStore } from './globalStore.js' +import type { ConnectMiddleware, VikeHttpResponse, VikeOptions } from './types.js' +import { parseHeaders } from './utils/header-utils.js' export { renderPage, renderPageWeb } @@ -80,7 +80,7 @@ export const renderPageHandler = ((options?) => async (request, context, runtime if (nodeReq) { globalStore.setupHMRProxy(nodeReq) - const { resolveStaticConfig } = await import('./handler-node-only.js') + const { resolveStaticConfig } = await import('./utils/resolve-static-config.js') staticConfig = resolveStaticConfig(options?.static) } @@ -91,7 +91,7 @@ export const renderPageHandler = ((options?) => async (request, context, runtime if (handled) return handled } else if (nodeReq) { if (staticConfig) { - const handled = await connectToWebFallback(serveStaticFiles)(request) + const handled = await connectToWeb(serveStaticFiles)(request) if (handled) return handled } } @@ -133,7 +133,7 @@ export const renderPageHandler = ((options?) => async (request, context, runtime export const renderPageUniversal = ((options?) => pipe(renderPageCompress(options), renderPageHandler(options))) satisfies Get<[options: VikeOptions], UniversalHandler> -const web = connectToWebFallback(handleViteDevServer) +const web = connectToWeb(handleViteDevServer) function handleViteDevServer(req: IncomingMessage, res: ServerResponse): Promise { return new Promise((resolve) => { diff --git a/packages/vike-node/tsup.config.js b/packages/vike-node/tsup.config.js index ace9e21..aa4e81d 100644 --- a/packages/vike-node/tsup.config.js +++ b/packages/vike-node/tsup.config.js @@ -1,6 +1,8 @@ import { defineConfig } from 'tsup' import universalMiddleware from 'universal-middleware/esbuild' +const external = ['stream', 'http', 'path', 'url', 'zlib'] + export default defineConfig([ { entry: { @@ -18,7 +20,7 @@ export default defineConfig([ esbuildOptions(opts) { opts.outbase = 'src' }, - external: ['stream', 'http', 'node:stream', 'node:http', 'path', 'url', 'node:zlib'], + external: external.map((e) => [e, `node:${e}`]).flat(1), dts: true, outDir: 'dist', bundle: true