mirror of
https://github.com/withastro/astro.git
synced 2025-02-03 22:29:08 -05:00
fix: dynamically imported middlewares
This commit is contained in:
parent
7fa6f782cd
commit
d1e5977533
2 changed files with 101 additions and 73 deletions
|
@ -9,9 +9,12 @@ import type {
|
|||
SSRManifest,
|
||||
SSRResult,
|
||||
} from '../types/public/internal.js';
|
||||
import { createOriginCheckMiddleware } from './app/middlewares.js';
|
||||
import { AstroError } from './errors/errors.js';
|
||||
import { AstroErrorData } from './errors/index.js';
|
||||
import type { Logger } from './logger/core.js';
|
||||
import { NOOP_MIDDLEWARE_FN } from './middleware/noop-middleware.js';
|
||||
import { sequence } from './middleware/sequence.js';
|
||||
import { RouteCache } from './render/route-cache.js';
|
||||
import { createDefaultRoutes } from './routing/default.js';
|
||||
|
||||
|
@ -22,82 +25,107 @@ import { createDefaultRoutes } from './routing/default.js';
|
|||
* Thus, a `Pipeline` is created once at process start and then used by every `RenderContext`.
|
||||
*/
|
||||
export abstract class Pipeline {
|
||||
readonly internalMiddleware: MiddlewareHandler[];
|
||||
|
||||
constructor(
|
||||
readonly logger: Logger,
|
||||
readonly manifest: SSRManifest,
|
||||
/**
|
||||
* "development" or "production"
|
||||
*/
|
||||
readonly mode: RuntimeMode,
|
||||
readonly renderers: SSRLoadedRenderer[],
|
||||
readonly resolve: (s: string) => Promise<string>,
|
||||
/**
|
||||
* Based on Astro config's `output` option, `true` if "server" or "hybrid".
|
||||
*/
|
||||
readonly serverLike: boolean,
|
||||
readonly streaming: boolean,
|
||||
/**
|
||||
* Used to provide better error messages for `Astro.clientAddress`
|
||||
*/
|
||||
readonly adapterName = manifest.adapterName,
|
||||
readonly clientDirectives = manifest.clientDirectives,
|
||||
readonly inlinedScripts = manifest.inlinedScripts,
|
||||
readonly compressHTML = manifest.compressHTML,
|
||||
readonly i18n = manifest.i18n,
|
||||
readonly middleware = manifest.middleware,
|
||||
readonly routeCache = new RouteCache(logger, mode),
|
||||
/**
|
||||
* Used for `Astro.site`.
|
||||
*/
|
||||
readonly site = manifest.site ? new URL(manifest.site) : undefined,
|
||||
readonly callSetGetEnv = true,
|
||||
/**
|
||||
* Array of built-in, internal, routes.
|
||||
* Used to find the route module
|
||||
*/
|
||||
readonly defaultRoutes = createDefaultRoutes(manifest),
|
||||
) {
|
||||
this.internalMiddleware = [];
|
||||
// We do use our middleware only if the user isn't using the manual setup
|
||||
if (i18n?.strategy !== 'manual') {
|
||||
this.internalMiddleware.push(
|
||||
createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat),
|
||||
);
|
||||
readonly internalMiddleware: MiddlewareHandler[];
|
||||
resolvedMiddleware: MiddlewareHandler | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
readonly logger: Logger,
|
||||
readonly manifest: SSRManifest,
|
||||
/**
|
||||
* "development" or "production"
|
||||
*/
|
||||
readonly mode: RuntimeMode,
|
||||
readonly renderers: SSRLoadedRenderer[],
|
||||
readonly resolve: (s: string) => Promise<string>,
|
||||
/**
|
||||
* Based on Astro config's `output` option, `true` if "server" or "hybrid".
|
||||
*/
|
||||
readonly serverLike: boolean,
|
||||
readonly streaming: boolean,
|
||||
/**
|
||||
* Used to provide better error messages for `Astro.clientAddress`
|
||||
*/
|
||||
readonly adapterName = manifest.adapterName,
|
||||
readonly clientDirectives = manifest.clientDirectives,
|
||||
readonly inlinedScripts = manifest.inlinedScripts,
|
||||
readonly compressHTML = manifest.compressHTML,
|
||||
readonly i18n = manifest.i18n,
|
||||
readonly middleware = manifest.middleware,
|
||||
readonly routeCache = new RouteCache(logger, mode),
|
||||
/**
|
||||
* Used for `Astro.site`.
|
||||
*/
|
||||
readonly site = manifest.site ? new URL(manifest.site) : undefined,
|
||||
readonly callSetGetEnv = true,
|
||||
/**
|
||||
* Array of built-in, internal, routes.
|
||||
* Used to find the route module
|
||||
*/
|
||||
readonly defaultRoutes = createDefaultRoutes(manifest),
|
||||
) {
|
||||
this.internalMiddleware = [];
|
||||
// We do use our middleware only if the user isn't using the manual setup
|
||||
if (i18n?.strategy !== 'manual') {
|
||||
this.internalMiddleware.push(
|
||||
createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat),
|
||||
);
|
||||
}
|
||||
// In SSR, getSecret should fail by default. Setting it here will run before the
|
||||
// adapter override.
|
||||
if (callSetGetEnv && manifest.envGetSecretEnabled) {
|
||||
setGetEnv(() => {
|
||||
throw new AstroError(AstroErrorData.EnvUnsupportedGetSecret);
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
// In SSR, getSecret should fail by default. Setting it here will run before the
|
||||
// adapter override.
|
||||
if (callSetGetEnv && manifest.envGetSecretEnabled) {
|
||||
setGetEnv(() => {
|
||||
throw new AstroError(AstroErrorData.EnvUnsupportedGetSecret);
|
||||
}, true);
|
||||
|
||||
abstract headElements(routeData: RouteData): Promise<HeadElements> | HeadElements;
|
||||
|
||||
abstract componentMetadata(
|
||||
routeData: RouteData,
|
||||
): Promise<SSRResult['componentMetadata']> | void;
|
||||
|
||||
/**
|
||||
* It attempts to retrieve the `RouteData` that matches the input `url`, and the component that belongs to the `RouteData`.
|
||||
*
|
||||
* ## Errors
|
||||
*
|
||||
* - if not `RouteData` is found
|
||||
*
|
||||
* @param {RewritePayload} rewritePayload The payload provided by the user
|
||||
* @param {Request} request The original request
|
||||
*/
|
||||
abstract tryRewrite(
|
||||
rewritePayload: RewritePayload,
|
||||
request: Request,
|
||||
): Promise<TryRewriteResult>;
|
||||
|
||||
/**
|
||||
* Tells the pipeline how to retrieve a component give a `RouteData`
|
||||
* @param routeData
|
||||
*/
|
||||
abstract getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
||||
|
||||
/**
|
||||
* Resolves the middleware from the manifest, and returns the `onRequest` function. If `onRequest` isn't there,
|
||||
* it returns a no-op function
|
||||
*/
|
||||
async getMiddleware(): Promise<MiddlewareHandler> {
|
||||
if (this.resolvedMiddleware) {
|
||||
return this.resolvedMiddleware;
|
||||
} else {
|
||||
const middlewareInstance = await this.middleware();
|
||||
const onRequest = middlewareInstance.onRequest ?? NOOP_MIDDLEWARE_FN;
|
||||
if (this.manifest.checkOrigin) {
|
||||
this.resolvedMiddleware = sequence(createOriginCheckMiddleware(), onRequest);
|
||||
} else {
|
||||
this.resolvedMiddleware = onRequest;
|
||||
}
|
||||
return this.resolvedMiddleware;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract headElements(routeData: RouteData): Promise<HeadElements> | HeadElements;
|
||||
|
||||
abstract componentMetadata(routeData: RouteData): Promise<SSRResult['componentMetadata']> | void;
|
||||
|
||||
/**
|
||||
* It attempts to retrieve the `RouteData` that matches the input `url`, and the component that belongs to the `RouteData`.
|
||||
*
|
||||
* ## Errors
|
||||
*
|
||||
* - if not `RouteData` is found
|
||||
*
|
||||
* @param {RewritePayload} rewritePayload The payload provided by the user
|
||||
* @param {Request} request The original request
|
||||
*/
|
||||
abstract tryRewrite(rewritePayload: RewritePayload, request: Request): Promise<TryRewriteResult>;
|
||||
|
||||
/**
|
||||
* Tells the pipeline how to retrieve a component give a `RouteData`
|
||||
* @param routeData
|
||||
*/
|
||||
abstract getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface HeadElements extends Pick<SSRResult, 'scripts' | 'styles' | 'links'> {}
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import type { MiddlewareHandler } from '../../@types/astro.js';
|
||||
import type { MiddlewareHandler } from "../../types/public/common.js";
|
||||
|
||||
export const NOOP_MIDDLEWARE_FN: MiddlewareHandler = (_, next) => next();
|
||||
|
|
Loading…
Add table
Reference in a new issue