Skip to content

Commit

Permalink
internal middleware: i18n
Browse files Browse the repository at this point in the history
  • Loading branch information
lilnasy committed Jan 31, 2024
1 parent 2cb5bdc commit a6fd6b5
Show file tree
Hide file tree
Showing 8 changed files with 26 additions and 115 deletions.
17 changes: 2 additions & 15 deletions packages/astro/src/core/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import type {
SSRElement,
SSRManifest,
} from '../../@types/astro.js';
import { createI18nMiddleware, i18nPipelineHook } from '../../i18n/middleware.js';
import { REROUTE_DIRECTIVE_HEADER } from '../../runtime/server/consts.js';
import type { SinglePageBuiltModule } from '../build/types.js';
import { getSetCookiesFromResponse } from '../cookies/index.js';
import { consoleLogDestination } from '../logger/console.js';
import { AstroIntegrationLogger, Logger } from '../logger/core.js';
import { sequence } from '../middleware/index.js';
import {
appendForwardSlash,
collapseDuplicateSlashes,
Expand All @@ -20,7 +18,7 @@ import {
removeTrailingForwardSlash,
} from '../path.js';
import { RedirectSinglePageBuiltModule } from '../redirects/index.js';
import { Environment, createRenderContext, type RenderContext } from '../render/index.js';
import { createRenderContext, type RenderContext } from '../render/index.js';
import { RouteCache } from '../render/route-cache.js';
import {
createAssetLink,
Expand Down Expand Up @@ -325,18 +323,7 @@ export class App {
);
let response;
try {
const i18nMiddleware = createI18nMiddleware(
this.#manifest.i18n,
this.#manifest.base,
this.#manifest.trailingSlash,
this.#manifest.buildFormat
);
const pipeline = this.#environment.createPipeline({
pathname,
renderContext,
hookBefore: i18nPipelineHook,
middleware: sequence(i18nMiddleware, this.#manifest.middleware)
})
const pipeline = this.#environment.createPipeline({ pathname, renderContext });
response = await pipeline.renderRoute(pageModule);
} catch (err: any) {
this.#logger.error(null, err.stack || err.message || String(err));
Expand Down
10 changes: 0 additions & 10 deletions packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ import {
removeLeadingForwardSlash,
removeTrailingForwardSlash,
} from '../../core/path.js';
import { createI18nMiddleware, i18nPipelineHook } from '../../i18n/middleware.js';
import { runHookBuildGenerated } from '../../integrations/index.js';
import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
import type { SSRManifestI18n } from '../app/types.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
import { sequence } from '../middleware/index.js';
import { routeIsFallback } from '../redirects/helpers.js';
import {
RedirectSinglePageBuiltModule,
Expand Down Expand Up @@ -557,17 +555,9 @@ async function generatePath(
routing: i18n?.routing,
defaultLocale: i18n?.defaultLocale,
});
const i18nMiddleware = createI18nMiddleware(
manifest.i18n,
manifest.base,
manifest.trailingSlash,
manifest.buildFormat
)
const pipeline = environment.createPipeline({
pathname,
renderContext,
hookBefore: i18nPipelineHook,
middleware: sequence(i18nMiddleware, manifest.middleware)
})

let body: string | Uint8Array;
Expand Down
13 changes: 4 additions & 9 deletions packages/astro/src/core/endpoint/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export async function callEndpoint(
mod: EndpointHandler,
env: Environment,
ctx: RenderContext,
onRequest: MiddlewareHandler | undefined
onRequest: MiddlewareHandler
): Promise<Response> {
const context = createAPIContext({
request: ctx.request,
Expand All @@ -156,14 +156,9 @@ export async function callEndpoint(
locales: ctx.locales,
});

let response;
if (onRequest) {
response = await callMiddleware(onRequest, context, async () => {
return await renderEndpoint(mod, context, env.serverLike, env.logger);
});
} else {
response = await renderEndpoint(mod, context, env.serverLike, env.logger);
}
const response = await callMiddleware(onRequest, context, async () => {
return await renderEndpoint(mod, context, env.serverLike, env.logger);
});

attachCookiesToResponse(response, context.cookies);
return response;
Expand Down
53 changes: 8 additions & 45 deletions packages/astro/src/core/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { callMiddleware } from './middleware/callMiddleware.js';
import { renderPage } from './render/core.js';
import { type Environment, type RenderContext } from './render/index.js';

export type PipelineHookFunction = (ctx: RenderContext, mod: ComponentInstance | undefined) => void;

/**
* This is the basic class of a pipeline.
*
Expand All @@ -18,35 +16,11 @@ export class Pipeline {
readonly request: Request,
readonly pathname: string,
readonly renderContext: RenderContext,
readonly hookBefore: PipelineHookFunction = () => {},
private middleware = environment.middleware
readonly middleware = environment.middleware
) {}

/**
* A middleware function that will be called before each request.
*/
setMiddlewareFunction(middleware: MiddlewareHandler) {
this.middleware = middleware;
}

/**
* Removes the current middleware function. Subsequent requests won't trigger any middleware.
*/
unsetMiddlewareFunction() {
this.middleware = (_, next) => next();
}

/**
* The main function of the pipeline. Use this function to render any route known to Astro;
*/
async renderRoute(
componentInstance: ComponentInstance | undefined
): Promise<Response> {
this.hookBefore(this.renderContext, componentInstance);
return await this.#tryRenderRoute(componentInstance, this.middleware);
}

/**
* It attempts to render a route. A route can be a:
* - page
* - redirect
Expand All @@ -56,10 +30,10 @@ export class Pipeline {
*
* It throws an error if the page can't be rendered.
*/
async #tryRenderRoute(
mod: Readonly<ComponentInstance> | undefined,
onRequest?: MiddlewareHandler
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 { adapterName, site } = environment;
Expand All @@ -69,26 +43,15 @@ export class Pipeline {
case 'page':
case 'fallback':
case 'redirect': {
if (onRequest) {
return await callMiddleware(onRequest, apiContext, () => {
return renderPage({
mod,
renderContext,
env: environment,
cookies: apiContext.cookies,
});
});
} else {
return await renderPage({
mod,
return await callMiddleware(this.middleware, apiContext, () => renderPage({
mod: componentInstance,
renderContext,
env: environment,
cookies: apiContext.cookies,
});
}
}))
}
case 'endpoint': {
return await callEndpoint(mod as any as EndpointHandler, environment, renderContext, onRequest);
return await callEndpoint(componentInstance as any as EndpointHandler, environment, renderContext, this.middleware);
}
default:
throw new Error(`Couldn't find route of type [${renderContext.route.type}]`);
Expand Down
14 changes: 10 additions & 4 deletions packages/astro/src/core/render/environment.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import type { MiddlewareHandler, RuntimeMode, SSRLoadedRenderer, SSRManifest } from '../../@types/astro.js';
import type { Logger } from '../logger/core.js';
import type { RouteCache } from './route-cache.js';
import { Pipeline, type PipelineHookFunction } from '../pipeline.js';
import { Pipeline } from '../pipeline.js';
import type { RenderContext } from './context.js';
import { createI18nMiddleware } from '../../i18n/middleware.js';
import { sequence } from '../middleware/index.js';

/**
* The environment represents the static parts of rendering that do not change between requests.
* These are mostly known when the server first starts up and do not change.
* Thus, an environment is created once at process start and then used by every pipeline.
*/
export abstract class Environment {
readonly internalMiddleware: MiddlewareHandler;

constructor(
readonly logger: Logger,
readonly manifest: SSRManifest,
Expand Down Expand Up @@ -37,9 +41,11 @@ export abstract class Environment {
* Used for `Astro.site`.
*/
readonly site = manifest.site,
) {}
) {
this.internalMiddleware = createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat);
}

createPipeline({ renderContext, pathname, hookBefore, middleware }: { pathname: string; renderContext: RenderContext; hookBefore?: PipelineHookFunction; middleware?: MiddlewareHandler }) {
return new Pipeline(this, renderContext.locals ?? {}, renderContext.request, pathname, renderContext, hookBefore, middleware);
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));
}
}
4 changes: 0 additions & 4 deletions packages/astro/src/core/render/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,4 @@ export interface SSROptions {
request: Request;
/** optional, in case we need to render something outside a dev server */
route: RouteData;
/**
* Optional middlewares
*/
middleware?: AstroMiddlewareInstance;
}
16 changes: 1 addition & 15 deletions packages/astro/src/i18n/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import { appendForwardSlash, joinPaths } from '@astrojs/internal-helpers/path';
import type {
APIContext,
Locales,
MiddlewareHandler,
RouteData,
SSRManifest,
} from '../@types/astro.js';
import type { PipelineHookFunction } from '../core/pipeline.js';
import type { APIContext, Locales, MiddlewareHandler, RouteData, 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';
Expand Down Expand Up @@ -214,13 +207,6 @@ export function createI18nMiddleware(
};
}

/**
* This pipeline hook attaches a `RouteData` object to the `Request`
*/
export const i18nPipelineHook: PipelineHookFunction = (ctx) => {
Reflect.set(ctx.request, routeDataSymbol, ctx.route);
};

/**
* Checks if the current locale doesn't belong to a configured domain
* @param i18n
Expand Down
14 changes: 1 addition & 13 deletions packages/astro/src/vite-plugin-astro-server/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { getInfoOutput } from '../cli/info/index.js';
import { ASTRO_VERSION } from '../core/constants.js';
import { AstroErrorData, isAstroError } from '../core/errors/index.js';
import { req } from '../core/messages.js';
import { sequence } from '../core/middleware/index.js';
import { loadMiddleware } from '../core/middleware/loadMiddleware.js';
import {
createRenderContext,
Expand All @@ -25,7 +24,6 @@ import { createRequest } from '../core/request.js';
import { matchAllRoutes } from '../core/routing/index.js';
import { isPage, resolveIdToUrl } from '../core/util.js';
import { normalizeTheLocale } from '../i18n/index.js';
import { createI18nMiddleware, i18nPipelineHook } from '../i18n/middleware.js';
import { getSortedPreloadedMatches } from '../prerender/routing.js';
import { isServerLikeOutput } from '../prerender/utils.js';
import { PAGE_SCRIPT_ID } from '../vite-plugin-scripts/index.js';
Expand Down Expand Up @@ -183,8 +181,6 @@ export async function handleRoute({
let mod: ComponentInstance | undefined = undefined;
let options: SSROptions | undefined = undefined;
let route: RouteData;
const middleware = await loadMiddleware(environment.loader);
const onRequest: MiddlewareHandler = middleware.onRequest

if (!matchedRoute) {
if (config.i18n) {
Expand Down Expand Up @@ -274,7 +270,6 @@ export async function handleRoute({
pathname,
request,
route,
middleware,
};

mod = options.preload;
Expand All @@ -301,17 +296,10 @@ export async function handleRoute({
defaultLocale: i18n?.defaultLocale,
});
}
const i18Middleware = createI18nMiddleware(
manifest.i18n,
config.base,
config.trailingSlash,
config.build.format
);
const pipeline = environment.createPipeline({
pathname,
renderContext,
hookBefore: i18nPipelineHook,
middleware: sequence(i18Middleware, onRequest),
middleware: (await loadMiddleware(environment.loader)).onRequest,
});

let response = await pipeline.renderRoute(mod);
Expand Down

0 comments on commit a6fd6b5

Please sign in to comment.