Skip to content

Commit

Permalink
pipeline access for internal middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
lilnasy committed Feb 4, 2024
1 parent cfbf60f commit 8298c38
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 29 deletions.
2 changes: 0 additions & 2 deletions packages/astro/src/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,3 @@ export const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [

// The folder name where to find the middleware
export const MIDDLEWARE_PATH_SEGMENT_NAME = 'middleware';

export const ROUTE_DATA_SYMBOL = 'astro.routeData';
4 changes: 3 additions & 1 deletion packages/astro/src/core/endpoint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type CreateAPIContext = {
locales: Locales | undefined;
routingStrategy: RoutingStrategies | undefined;
defaultLocale: string | undefined;
route: string;
};

/**
Expand All @@ -41,6 +42,7 @@ export function createAPIContext({
locales,
routingStrategy,
defaultLocale,
route
}: CreateAPIContext): APIContext {
let preferredLocale: string | undefined = undefined;
let preferredLocaleList: string[] | undefined = undefined;
Expand Down Expand Up @@ -88,7 +90,7 @@ export function createAPIContext({
return currentLocale;
}
if (locales) {
currentLocale = computeCurrentLocale(request, locales, routingStrategy, defaultLocale);
currentLocale = computeCurrentLocale(route, locales, routingStrategy, defaultLocale);
}

return currentLocale;
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/core/middleware/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function createContext({ request, params, userDefinedLocales = [] }: CreateConte
locales: userDefinedLocales,
defaultLocale: undefined,
routingStrategy: undefined,
route: new URL(request.url).pathname,
});
}

Expand Down
39 changes: 32 additions & 7 deletions packages/astro/src/core/pipeline.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { ComponentInstance, EndpointHandler } from '../@types/astro.js';
import type { APIContext, ComponentInstance, EndpointHandler, MiddlewareHandler } from '../@types/astro.js';
import { renderEndpoint } from '../runtime/server/endpoint.js';
import { attachCookiesToResponse } from './cookies/response.js';
import { createAPIContext } from './endpoint/index.js';
import { callMiddleware } from './middleware/callMiddleware.js';
import { renderPage } from './render/core.js';
import { type Environment, type RenderContext } from './render/index.js';
import type { Environment, RenderContext } from './render/index.js';

/**
* This is the basic class of a pipeline.
Expand All @@ -15,10 +15,10 @@ export class Pipeline {
constructor(
readonly environment: Environment,
readonly locals: App.Locals,
readonly request: Request,
readonly middleware: MiddlewareHandler,
readonly pathname: string,
readonly renderContext: RenderContext,
readonly middleware = environment.middleware
readonly request = renderContext.request,
) {}

/**
Expand All @@ -35,16 +35,41 @@ export class Pipeline {
async renderRoute(
componentInstance: ComponentInstance | undefined
): Promise<Response> {
Reflect.set(this.renderContext.request, Symbol.for('astro.routeData'), this.renderContext.route)
const { renderContext, environment } = this;
const { defaultLocale, locales, params, props, request, routing: routingStrategy } = renderContext;
const { defaultLocale, locales, params, props, request, route: { route }, routing: routingStrategy } = renderContext;
const { adapterName, logger, site, serverLike } = environment;
const apiContext = createAPIContext({ adapterName, defaultLocale, locales, params, props, request, routingStrategy, site });
const apiContext = createAPIContext({ adapterName, defaultLocale, locales, params, props, request, route, routingStrategy, site });
HiddenPipeline.set(request, this);
const terminalNext = renderContext.route.type === 'endpoint'
? () => renderEndpoint(componentInstance as any as EndpointHandler, apiContext, serverLike, logger)
: () => renderPage({ mod: componentInstance, renderContext, env: environment, cookies: apiContext.cookies });
const response = await callMiddleware(this.middleware, apiContext, terminalNext);
attachCookiesToResponse(response, apiContext.cookies);
return response;
}

static get(request: Request) {
return HiddenPipeline.get(request)
}
}

/**
* Allows internal middleware to read the pipeline associated with the current request.
*/
class HiddenPipeline extends class { constructor(request: Request) { return request } } {
#pipeline!: Pipeline
static get(request: Request) {
if (#pipeline in request) return request.#pipeline
throw new Error("The request does not have an associated pipeline.")
}
static set(request: Request, pipeline: Pipeline) {
// this if-branch only needs to exist until `App` starts reusing the original pipeline for `renderError()`
// it can start to error afterwards as there shouldnt be multiple pipelines per request
if (#pipeline in request) {
request.#pipeline = pipeline
} else {
const req = new HiddenPipeline(request)
req.#pipeline = pipeline
}
}
}
11 changes: 2 additions & 9 deletions packages/astro/src/core/render/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ import { AstroError, AstroErrorData } from '../errors/index.js';
import type { Environment } from './environment.js';
import { getParamsAndProps } from './params-and-props.js';
import type { RoutingStrategies } from '../config/schema.js';
import { ROUTE_DATA_SYMBOL } from '../constants.js';

const clientLocalsSymbol = Symbol.for('astro.locals');
const routeDataSymbol = Symbol.for(ROUTE_DATA_SYMBOL);

/**
* The RenderContext represents the parts of rendering that are specific to one request.
Expand Down Expand Up @@ -240,17 +238,12 @@ export function computePreferredLocaleList(request: Request, locales: Locales):
}

export function computeCurrentLocale(
request: Request,
route: string,
locales: Locales,
routingStrategy: RoutingStrategies | undefined,
defaultLocale: string | undefined
): undefined | string {
const routeData: RouteData | undefined = Reflect.get(request, routeDataSymbol);
if (!routeData) {
return defaultLocale;
}

for (const segment of routeData.route.split('/')) {
for (const segment of route.split('/')) {
for (const locale of locales) {
if (typeof locale === 'string') {
if (normalizeTheLocale(locale) === normalizeTheLocale(segment)) {
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/core/render/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export async function renderPage({ mod, renderContext, env, cookies }: RenderPag
locales: renderContext.locales,
defaultLocale: renderContext.defaultLocale,
routingStrategy: renderContext.routing,
route: renderContext.route.route,
});

const response = await runtimeRenderPage(
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/render/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ export abstract class Environment {
}

createPipeline({ renderContext, pathname, middleware }: { pathname: string; renderContext: RenderContext; middleware?: MiddlewareHandler }) {
return new Pipeline(this, renderContext.locals ?? {}, renderContext.request, pathname, renderContext, sequence(this.internalMiddleware, middleware ?? this.middleware));
return new Pipeline(this, renderContext.locals ?? {}, sequence(this.internalMiddleware, middleware ?? this.middleware), pathname, renderContext);
}
}
5 changes: 3 additions & 2 deletions packages/astro/src/core/render/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface CreateResultArgs {
cookies?: AstroCookies;
locales: Locales | undefined;
defaultLocale: string | undefined;
route: string;
routingStrategy: RoutingStrategies | undefined;
}

Expand Down Expand Up @@ -134,7 +135,7 @@ class Slots {
}

export function createResult(args: CreateResultArgs): SSRResult {
const { params, request, resolve, locals } = args;
const { params, request, resolve, route, locals } = args;

const url = new URL(request.url);
const headers = new Headers();
Expand Down Expand Up @@ -233,7 +234,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
}
if (args.locales) {
currentLocale = computeCurrentLocale(
request,
route,
args.locales,
args.routingStrategy,
args.defaultLocale
Expand Down
12 changes: 5 additions & 7 deletions packages/astro/src/i18n/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { appendForwardSlash, joinPaths } from '@astrojs/internal-helpers/path';
import type { APIContext, Locales, MiddlewareHandler, RouteData, SSRManifest } from '../@types/astro.js';
import type { APIContext, Locales, MiddlewareHandler, SSRManifest } from '../@types/astro.js';
import { getPathByLocale, normalizeTheLocale } from './index.js';
import { shouldAppendForwardSlash } from '../core/build/util.js';
import { ROUTE_DATA_SYMBOL } from '../core/constants.js';
import type { SSRManifestI18n } from '../core/app/types.js';

const routeDataSymbol = Symbol.for(ROUTE_DATA_SYMBOL);
import { Pipeline } from '../core/pipeline.js';
import type { SSRManifestI18n } from '../core/app/types.js'

// Checks if the pathname has any locale, exception for the defaultLocale, which is ignored on purpose.
function pathnameHasLocale(pathname: string, locales: Locales): boolean {
Expand Down Expand Up @@ -101,9 +99,9 @@ export function createI18nMiddleware(
};

return async (context, next) => {
const routeData: RouteData | undefined = Reflect.get(context.request, routeDataSymbol);
const type = Pipeline.get(context.request).renderContext.route.type;
// If the route we're processing is not a page, then we ignore it
if (routeData?.type !== 'page' && routeData?.type !== 'fallback') {
if (type !== 'page' && type !== 'fallback') {
return await next();
}
const currentLocale = context.currentLocale;
Expand Down

0 comments on commit 8298c38

Please sign in to comment.