From ce9013df9b4def1151caa1f8403c810121df31b6 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 5 Apr 2023 16:04:36 +0100 Subject: [PATCH] feat: support middlewares in SSG for endpoints and pages --- packages/astro/src/@types/astro.ts | 19 +++-- packages/astro/src/core/app/index.ts | 3 +- packages/astro/src/core/build/generate.ts | 70 ++++++++++++++++-- .../src/core/build/plugins/plugin-pages.ts | 12 +++- packages/astro/src/core/build/static-build.ts | 5 +- packages/astro/src/core/build/types.ts | 2 + packages/astro/src/core/config/schema.ts | 1 - packages/astro/src/core/endpoint/dev/index.ts | 15 +++- packages/astro/src/core/endpoint/index.ts | 24 ++++++- .../src/core/middleware/callMiddleware.ts | 72 +++++++++++++++++++ packages/astro/src/core/middleware/index.ts | 6 +- .../src/core/middleware/loadMiddleware.ts | 19 +++++ .../astro/src/core/middleware/sequence.ts | 11 ++- packages/astro/src/core/render/dev/index.ts | 40 ++--------- .../src/vite-plugin-astro-server/route.ts | 27 +------ 15 files changed, 233 insertions(+), 93 deletions(-) create mode 100644 packages/astro/src/core/middleware/callMiddleware.ts create mode 100644 packages/astro/src/core/middleware/loadMiddleware.ts diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 67ea7234151f2..ddf8a46a763ac 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1391,11 +1391,6 @@ interface AstroSharedContext = Record void; } export interface APIContext = Record> @@ -1562,14 +1557,16 @@ export interface AstroIntegration { }; } -export type MiddlewareResolve = (context: APIContext) => Promise; -export type MiddlewareHandler = ( +export type MiddlewareResolve = (context: APIContext) => Promise; +export type MiddlewareHandler = ( context: Readonly, - response: MiddlewareResolve -) => Promise; + response: MiddlewareResolve +) => Promise; -export type AstroMiddlewareInstance = { - onRequest?: MiddlewareHandler; +// NOTE: when updating this file with other functions, +// remember to update `plugin-page.ts` too, to add that function as a no-op function. +export type AstroMiddlewareInstance = { + onRequest?: MiddlewareHandler; }; export interface AstroPluginOptions { diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts index 328769f2a5a88..c7aad40a2dbb0 100644 --- a/packages/astro/src/core/app/index.ts +++ b/packages/astro/src/core/app/index.ts @@ -231,7 +231,8 @@ export class App { status, }); - const result = await callEndpoint(handler, this.#env, ctx, this.#logging); + // TODO PLT-104 add adapter middleware here + const result = await callEndpoint(handler, this.#env, ctx, this.#logging, undefined); if (result.type === 'response') { if (result.response.headers.get('X-Astro-Response') === 'Not-Found') { diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index a89db40ad136f..1087564d22a74 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -6,13 +6,16 @@ import type { OutputAsset, OutputChunk } from 'rollup'; import { fileURLToPath } from 'url'; import type { AstroConfig, + AstroMiddlewareInstance, AstroSettings, ComponentInstance, EndpointHandler, ImageTransform, + MiddlewareHandler, RouteType, SSRError, SSRLoadedRenderer, + EndpointOutput, } from '../../@types/astro'; import { generateImage as generateImageInternal, @@ -27,10 +30,20 @@ import { } from '../../core/path.js'; import { runHookBuildGenerated } from '../../integrations/index.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; -import { call as callEndpoint, throwIfRedirectNotAllowed } from '../endpoint/index.js'; -import { AstroError } from '../errors/index.js'; +import { + call as callEndpoint, + createAPIContext, + throwIfRedirectNotAllowed, +} from '../endpoint/index.js'; +import { AstroError, AstroErrorData } from '../errors/index.js'; import { debug, info } from '../logger/core.js'; -import { createEnvironment, createRenderContext, renderPage } from '../render/index.js'; +import { + createEnvironment, + createRenderContext, + getParamsAndProps, + GetParamsAndPropsError, + renderPage, +} from '../render/index.js'; import { callGetStaticPaths } from '../render/route-cache.js'; import { createLinkStylesheetElementSet, createModuleScriptsSet } from '../render/ssr-element.js'; import { createRequest } from '../request.js'; @@ -45,6 +58,7 @@ import { } from './internal.js'; import type { PageBuildData, SingleFileBuiltModule, StaticBuildOptions } from './types'; import { getTimeStat } from './util.js'; +import { callMiddleware } from '../middleware/index.js'; function shouldSkipDraft(pageModule: ComponentInstance, settings: AstroSettings): boolean { return ( @@ -168,6 +182,7 @@ async function generatePage( const scripts = pageInfo?.hoistedScript ?? null; const pageModule = ssrEntry.pageMap?.get(pageData.component); + const middleware = ssrEntry.middleware; if (!pageModule) { throw new Error( @@ -197,7 +212,7 @@ async function generatePage( for (let i = 0; i < paths.length; i++) { const path = paths[i]; - await generatePath(path, opts, generationOptions); + await generatePath(path, opts, generationOptions, middleware); const timeEnd = performance.now(); const timeChange = getTimeStat(timeStart, timeEnd); const timeIncrease = `(+${timeChange})`; @@ -339,7 +354,8 @@ function getUrlForPath( async function generatePath( pathname: string, opts: StaticBuildOptions, - gopts: GeneratePathOptions + gopts: GeneratePathOptions, + middleware: AstroMiddlewareInstance ) { const { settings, logging, origin, routeCache } = opts; const { mod, internals, linkIds, scripts: hoistedScripts, pageData, renderers } = gopts; @@ -412,6 +428,7 @@ async function generatePath( ssr, streaming: true, }); + const ctx = createRenderContext({ origin, pathname, @@ -426,7 +443,14 @@ async function generatePath( let encoding: BufferEncoding | undefined; if (pageData.route.type === 'endpoint') { const endpointHandler = mod as unknown as EndpointHandler; - const result = await callEndpoint(endpointHandler, env, ctx, logging); + + const result = await callEndpoint( + endpointHandler, + env, + ctx, + logging, + middleware as AstroMiddlewareInstance + ); if (result.type === 'response') { throwIfRedirectNotAllowed(result.response, opts.settings.config); @@ -441,7 +465,39 @@ async function generatePath( } else { let response: Response; try { - response = await renderPage(mod, ctx, env); + const paramsAndPropsResp = await getParamsAndProps({ + mod: mod as any, + route: ctx.route, + routeCache: env.routeCache, + pathname: ctx.pathname, + logging: env.logging, + ssr: env.ssr, + }); + + if (paramsAndPropsResp === GetParamsAndPropsError.NoMatchingStaticPath) { + throw new AstroError({ + ...AstroErrorData.NoMatchingStaticPathFound, + message: AstroErrorData.NoMatchingStaticPathFound.message(ctx.pathname), + hint: ctx.route?.component + ? AstroErrorData.NoMatchingStaticPathFound.hint([ctx.route?.component]) + : '', + }); + } + const [params, props] = paramsAndPropsResp; + + const context = createAPIContext({ + request: ctx.request, + params, + props, + site: env.site, + adapterName: env.adapterName, + }); + // If the user doesn't configure a middleware, the rollup plugin emits a no-op function, + // so it's safe to use `callMiddleware` regardless + let onRequest = middleware.onRequest as MiddlewareHandler; + response = await callMiddleware(onRequest, context, () => { + return renderPage(mod, ctx, env, context); + }); } catch (err) { if (!AstroError.is(err) && !(err as SSRError).id && typeof err === 'object') { (err as SSRError).id = pageData.component; diff --git a/packages/astro/src/core/build/plugins/plugin-pages.ts b/packages/astro/src/core/build/plugins/plugin-pages.ts index 5bb070978729a..ece0bbc6e7344 100644 --- a/packages/astro/src/core/build/plugins/plugin-pages.ts +++ b/packages/astro/src/core/build/plugins/plugin-pages.ts @@ -1,10 +1,10 @@ import type { Plugin as VitePlugin } from 'vite'; import type { AstroBuildPlugin } from '../plugin'; import type { StaticBuildOptions } from '../types'; - import { pagesVirtualModuleId, resolvedPagesVirtualModuleId } from '../../app/index.js'; import { addRollupInput } from '../add-rollup-input.js'; import { eachPageData, hasPrerenderedPages, type BuildInternals } from '../internal.js'; +import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../../constants.js'; export function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin { return { @@ -22,8 +22,10 @@ export function vitePluginPages(opts: StaticBuildOptions, internals: BuildIntern } }, - load(id) { + async load(id) { if (id === resolvedPagesVirtualModuleId) { + const middlewareId = await this.resolve(`./src/${MIDDLEWARE_PATH_SEGMENT_NAME}`); + let importMap = ''; let imports = []; let i = 0; @@ -47,8 +49,12 @@ export function vitePluginPages(opts: StaticBuildOptions, internals: BuildIntern const def = `${imports.join('\n')} +${middlewareId ? `import * as _middleware from "${middlewareId.id}";` : ''} + export const pageMap = new Map([${importMap}]); -export const renderers = [${rendererItems}];`; +export const renderers = [${rendererItems}]; +export const middleware = ${middlewareId ? '_middleware' : '{ onRequest() {} }'}; +`; return def; } diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index e3cd4f0e9860f..8db4b2cc0d2e2 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -12,7 +12,7 @@ import { } from '../../core/build/internal.js'; import { emptyDir, removeEmptyDirs } from '../../core/fs/index.js'; import { appendForwardSlash, prependForwardSlash } from '../../core/path.js'; -import { isModeServerWithNoAdapter } from '../../core/util.js'; +import { isModeServerWithNoAdapter, viteID } from '../../core/util.js'; import { runHookBuildSetup } from '../../integrations/index.js'; import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { resolvedPagesVirtualModuleId } from '../app/index.js'; @@ -25,6 +25,7 @@ import { createPluginContainer, type AstroBuildPluginContainer } from './plugin. import { registerAllPlugins } from './plugins/index.js'; import type { PageBuildData, StaticBuildOptions } from './types'; import { getTimeStat } from './util.js'; +import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../constants.js'; export async function viteBuild(opts: StaticBuildOptions) { const { allPages, settings } = opts; @@ -114,7 +115,7 @@ export async function staticBuild(opts: StaticBuildOptions, internals: BuildInte case 'static': { settings.timer.start('Static generate'); await generatePages(opts, internals); - await cleanServerOutput(opts); + // await cleanServerOutput(opts); settings.timer.end('Static generate'); return; } diff --git a/packages/astro/src/core/build/types.ts b/packages/astro/src/core/build/types.ts index 02f5618d87762..fc7839390698d 100644 --- a/packages/astro/src/core/build/types.ts +++ b/packages/astro/src/core/build/types.ts @@ -1,6 +1,7 @@ import type { default as vite, InlineConfig } from 'vite'; import type { AstroConfig, + AstroMiddlewareInstance, AstroSettings, BuildConfig, ComponentInstance, @@ -44,6 +45,7 @@ export interface StaticBuildOptions { export interface SingleFileBuiltModule { pageMap: Map; + middleware: AstroMiddlewareInstance; renderers: SSRLoadedRenderer[]; } diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 80db6703a5a81..5b374ce33ec37 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -29,7 +29,6 @@ const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = { open: false, }, integrations: [], - middlewares: [], markdown: { drafts: false, ...markdownConfigDefaults, diff --git a/packages/astro/src/core/endpoint/dev/index.ts b/packages/astro/src/core/endpoint/dev/index.ts index 515b7aa41a8e7..14432ca3a0e5a 100644 --- a/packages/astro/src/core/endpoint/dev/index.ts +++ b/packages/astro/src/core/endpoint/dev/index.ts @@ -1,4 +1,8 @@ -import type { EndpointHandler } from '../../../@types/astro'; +import type { + AstroMiddlewareInstance, + EndpointHandler, + EndpointOutput, +} from '../../../@types/astro'; import type { LogOptions } from '../../logger/core'; import type { SSROptions } from '../../render/dev'; import { createRenderContext } from '../../render/index.js'; @@ -8,6 +12,7 @@ export async function call(options: SSROptions, logging: LogOptions) { const { env, preload: [, mod], + middleware, } = options; const endpointHandler = mod as unknown as EndpointHandler; @@ -18,5 +23,11 @@ export async function call(options: SSROptions, logging: LogOptions) { route: options.route, }); - return await callEndpoint(endpointHandler, env, ctx, logging); + return await callEndpoint( + endpointHandler, + env, + ctx, + logging, + middleware as AstroMiddlewareInstance + ); } diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index 22d901cbc6676..e1be43ce36d1a 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -1,4 +1,12 @@ -import type { APIContext, AstroConfig, EndpointHandler, Params } from '../../@types/astro'; +import type { + APIContext, + AstroConfig, + AstroMiddlewareInstance, + EndpointHandler, + EndpointOutput, + MiddlewareHandler, + Params, +} from '../../@types/astro'; import type { Environment, RenderContext } from '../render/index'; import { renderEndpoint } from '../../runtime/server/index.js'; @@ -7,6 +15,7 @@ import { AstroCookies, attachToResponse } from '../cookies/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; import { warn, type LogOptions } from '../logger/core.js'; import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js'; +import { callMiddleware } from '../middleware/index.js'; const clientAddressSymbol = Symbol.for('astro.clientAddress'); const clientLocalsSymbol = Symbol.for('astro.locals'); @@ -75,7 +84,8 @@ export async function call( mod: EndpointHandler, env: Environment, ctx: RenderContext, - logging: LogOptions + logging: LogOptions, + middleware: AstroMiddlewareInstance | undefined ): Promise { const paramsAndPropsResp = await getParamsAndProps({ mod: mod as any, @@ -105,7 +115,15 @@ export async function call( adapterName: env.adapterName, }); - const response = await renderEndpoint(mod, context, env.ssr); + let response; + if (middleware && middleware.onRequest) { + const onRequest = middleware.onRequest as MiddlewareHandler; + response = await callMiddleware(onRequest, context, () => { + return renderEndpoint(mod, context, env.ssr); + }); + } else { + response = await renderEndpoint(mod, context, env.ssr); + } if (response instanceof Response) { attachToResponse(response, context.cookies); diff --git a/packages/astro/src/core/middleware/callMiddleware.ts b/packages/astro/src/core/middleware/callMiddleware.ts new file mode 100644 index 0000000000000..aa42da7706d87 --- /dev/null +++ b/packages/astro/src/core/middleware/callMiddleware.ts @@ -0,0 +1,72 @@ +import type { APIContext, MiddlewareHandler, MiddlewareResolve } from '../../@types/astro'; +import { renderPage as coreRenderPage } from '../render'; + +/** + * Utility function that is in charge of calling the middleware + * + * It accepts a `R` generic, which usually the `Response` returned. + * It is a generic because endpoints can return a different response. + * + * When calling a middleware, we provide a `resolve` function, this function might or + * might not be called. Because of that, we use a `Promise.race` to understand which + * promise is resolved first. + * + * If `resolve` is called first, we resolve the `responseFunction` and we pass that response + * as resolved value to `resolve`. Finally, we resolve the middleware. + * This logic covers examples like: + * + * ```js + * const onRequest = async (context, resolve) => { + * const response = await resolve(context); + * return response; + * } + * ``` + * + * If the middleware is called first, we return the response without fancy logic. This covers cases like: + * + * ```js + * const onRequest = async (context, _) => { + * context.locals = "foo"; + * } + * ``` + * + * @param onRequest The function called which accepts a `context` and a `resolve` function + * @param apiContext The API context + * @param responseFunction A callback function that should return a promise with the response + */ +export async function callMiddleware( + onRequest: MiddlewareHandler, + apiContext: APIContext, + responseFunction: () => Promise +): Promise { + let resolveResolve: any; + new Promise((resolve) => { + resolveResolve = resolve; + }); + + let resolveCalledResolve: any; + let resolveCalled = new Promise((resolve) => { + resolveCalledResolve = resolve; + }); + const resolve: MiddlewareResolve = () => { + const response = responseFunction(); + resolveCalledResolve('resolveCalled'); + return response; + }; + + let middlewarePromise = onRequest(apiContext, resolve); + + return await Promise.race([middlewarePromise, resolveCalled]).then(async (value) => { + if (value === 'resolveCalled') { + // Middleware called resolve() + // render the page and then pass back to middleware + // for post-processing + const responseResult = await responseFunction(); + await resolveResolve(responseResult); + return middlewarePromise; + } else { + // Middleware did not call resolve() + return await responseFunction(); + } + }); +} diff --git a/packages/astro/src/core/middleware/index.ts b/packages/astro/src/core/middleware/index.ts index e9e03a18d279f..667cf65e0a2e8 100644 --- a/packages/astro/src/core/middleware/index.ts +++ b/packages/astro/src/core/middleware/index.ts @@ -1 +1,5 @@ -export { sequence } from './sequence'; +import { sequence } from './sequence.js'; +import { callMiddleware } from './callMiddleware.js'; +import { loadMiddleware } from './loadMiddleware.js'; + +export { sequence, callMiddleware, loadMiddleware }; diff --git a/packages/astro/src/core/middleware/loadMiddleware.ts b/packages/astro/src/core/middleware/loadMiddleware.ts new file mode 100644 index 0000000000000..7da8c4070aff6 --- /dev/null +++ b/packages/astro/src/core/middleware/loadMiddleware.ts @@ -0,0 +1,19 @@ +import { fileURLToPath } from 'node:url'; +import type { ModuleLoader } from '../module-loader'; +import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../constants.js'; + +/** + * It accepts a module loader and the astro settings, and it attempts to load the middlewares defined in the configuration. + * + * If not middlewares were not set, the function returns an empty array. + */ +export async function loadMiddleware(moduleLoader: ModuleLoader, basePath: URL) { + let path = fileURLToPath(basePath); + let middlewarePath = path + 'src/' + MIDDLEWARE_PATH_SEGMENT_NAME; + try { + const module = await moduleLoader.import(middlewarePath); + return module; + } catch { + return void 0; + } +} diff --git a/packages/astro/src/core/middleware/sequence.ts b/packages/astro/src/core/middleware/sequence.ts index c4b09e91c8d34..7410cba0a45be 100644 --- a/packages/astro/src/core/middleware/sequence.ts +++ b/packages/astro/src/core/middleware/sequence.ts @@ -5,14 +5,19 @@ import type { APIContext, MiddlewareHandler } from '../../@types/astro'; * * It accepts one or more middleware handlers and makes sure that they are run in sequence. */ -export function sequence(...handlers: MiddlewareHandler[]): MiddlewareHandler { +export function sequence(...handlers: MiddlewareHandler[]): MiddlewareHandler { const length = handlers.length; - if (!length) return (context, resolve) => resolve(context); + if (!length) { + const handler: MiddlewareHandler = (context, resolve) => { + return resolve(context); + }; + return handler; + } return (context, resolve) => { return applyHandle(0, context); - function applyHandle(i: number, handleContext: APIContext): Promise { + function applyHandle(i: number, handleContext: APIContext): Promise { const handle = handlers[i]; return handle(handleContext, (nextContext) => { diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts index a3d590e92ce83..0e7a0e1a4a68b 100644 --- a/packages/astro/src/core/render/dev/index.ts +++ b/packages/astro/src/core/render/dev/index.ts @@ -4,7 +4,6 @@ import type { AstroSettings, ComponentInstance, MiddlewareHandler, - MiddlewareResolve, RouteData, SSRElement, SSRLoadedRenderer, @@ -32,7 +31,7 @@ import type { DevelopmentEnvironment } from './environment'; import { getComponentMetadata } from './metadata.js'; import { getScriptsForURL } from './scripts.js'; import { createAPIContext } from '../../endpoint/index.js'; -import { sequence } from '../../middleware/sequence.js'; +import { sequence, callMiddleware } from '../../middleware/index.js'; export { createDevelopmentEnvironment } from './environment.js'; export type { DevelopmentEnvironment }; @@ -54,7 +53,7 @@ export interface SSROptions { /** * Optional middlewares */ - middleware?: AstroMiddlewareInstance; + middleware?: AstroMiddlewareInstance; } export type ComponentPreload = [SSRLoadedRenderer[], ComponentInstance]; @@ -211,8 +210,7 @@ export async function renderPage(options: SSROptions): Promise { }); } - const { onRequest } = options.middleware; - if (onRequest) { + if (options.middleware && options.middleware.onRequest) { const [params, pageProps] = paramsAndPropsRes; const apiContext = createAPIContext({ @@ -222,35 +220,9 @@ export async function renderPage(options: SSROptions): Promise { adapterName: options.env.adapterName, }); - let resolveResolve: any; - new Promise((resolve) => { - resolveResolve = resolve; - }); - - let resolveCalledResolve: any; - let resolveCalled = new Promise((resolve) => { - resolveCalledResolve = resolve; - }); - const resolve: MiddlewareResolve = (context) => { - const response = coreRenderPage(mod, ctx, options.env, apiContext); - resolveCalledResolve('resolveCalled'); - return response; - }; - - let middlewarePromise = onRequest(apiContext, resolve); - - let response = await Promise.race([middlewarePromise, resolveCalled]).then(async (value) => { - if (value === 'resolveCalled') { - // Middleware called resolve() - // render the page and then pass back to middleware - // for post-processing - const responseResult = await coreRenderPage(mod, ctx, options.env, apiContext); - await resolveResolve(responseResult); - return middlewarePromise; - } else { - // Middleware did not call resolve() - return await coreRenderPage(mod, ctx, options.env, apiContext); - } + const onRequest = options.middleware.onRequest as MiddlewareHandler; + const response = await callMiddleware(onRequest, apiContext, () => { + return coreRenderPage(mod, ctx, options.env, apiContext); }); return response; diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index a66d67fd35ebc..9997e9e34aa5b 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -6,11 +6,10 @@ import type { DevelopmentEnvironment, SSROptions, } from '../core/render/dev/index'; - import { attachToResponse } from '../core/cookies/index.js'; import { call as callEndpoint } from '../core/endpoint/dev/index.js'; import { throwIfRedirectNotAllowed } from '../core/endpoint/index.js'; -import { AstroError, AstroErrorData } from '../core/errors/index.js'; +import { AstroErrorData } from '../core/errors/index.js'; import { warn } from '../core/logger/core.js'; import { appendForwardSlash } from '../core/path.js'; import { preload, renderPage } from '../core/render/dev/index.js'; @@ -20,10 +19,7 @@ import { matchAllRoutes } from '../core/routing/index.js'; import { resolvePages } from '../core/util.js'; import { log404 } from './common.js'; import { handle404Response, writeSSRResult, writeWebResponse } from './response.js'; -import type { ModuleLoader } from '../core/module-loader'; -import type { AstroMiddlewareInstance } from '../@types/astro'; -import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../core/constants.js'; -import { fileURLToPath } from 'node:url'; +import { loadMiddleware } from '../core/middleware/index.js'; type AsyncReturnType Promise> = T extends ( ...args: any @@ -120,25 +116,6 @@ export async function matchRoute( return undefined; } -/** - * It accepts a module loader and the astro settings, and it attempts to load the middlewares defined in the configuration. - * - * If not middlewares were not set, the function returns an empty array. - */ -export async function loadMiddleware( - moduleLoader: ModuleLoader, - basePath: URL -): Promise { - let path = fileURLToPath(basePath); - let middlewarePath = path + 'src' + '/' + MIDDLEWARE_PATH_SEGMENT_NAME; - try { - const module = (await moduleLoader.import(middlewarePath)) as AstroMiddlewareInstance; - return module as AstroMiddlewareInstance; - } catch { - return undefined; - } -} - export async function handleRoute( matchedRoute: AsyncReturnType, url: URL,