feat: remove experimental flag middleware (#7109)
* fix: middleware for API endpoints * feat: remove experimental flag middleware * chore: rebase and update * chore: check if physical file exists * chore: restore change * merge * merge * fix: remove options, not needed * remove experimental from types * chore: don't have the middleware inside the manifest * Update how redirects work, slightly --------- Co-authored-by: Matthew Phillips <matthew@skypack.dev>
This commit is contained in:
parent
435a231a26
commit
101f032098
16 changed files with 45 additions and 83 deletions
5
.changeset/young-flies-allow.md
Normal file
5
.changeset/young-flies-allow.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Remove experimental flag for the middleware
|
|
@ -8,6 +8,6 @@ export default defineConfig({
|
||||||
mode: 'standalone',
|
mode: 'standalone',
|
||||||
}),
|
}),
|
||||||
experimental: {
|
experimental: {
|
||||||
middleware: true,
|
middleware: true
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -108,7 +108,6 @@ export interface CLIFlags {
|
||||||
drafts?: boolean;
|
drafts?: boolean;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
experimentalAssets?: boolean;
|
experimentalAssets?: boolean;
|
||||||
experimentalMiddleware?: boolean;
|
|
||||||
experimentalRedirects?: boolean;
|
experimentalRedirects?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,27 +1188,6 @@ export interface AstroUserConfig {
|
||||||
*/
|
*/
|
||||||
customClientDirectives?: boolean;
|
customClientDirectives?: boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* @docs
|
|
||||||
* @name experimental.middleware
|
|
||||||
* @type {boolean}
|
|
||||||
* @default `false`
|
|
||||||
* @version 2.4.0
|
|
||||||
* @description
|
|
||||||
* Enable experimental support for Astro middleware.
|
|
||||||
*
|
|
||||||
* To enable this feature, set `experimental.middleware` to `true` in your Astro config:
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* {
|
|
||||||
* experimental: {
|
|
||||||
* middleware: true,
|
|
||||||
* },
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
middleware?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @docs
|
* @docs
|
||||||
* @name experimental.hybridOutput
|
* @name experimental.hybridOutput
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { consoleLogDestination } from '../logger/console.js';
|
||||||
import { error, type LogOptions } from '../logger/core.js';
|
import { error, type LogOptions } from '../logger/core.js';
|
||||||
import { callMiddleware } from '../middleware/callMiddleware.js';
|
import { callMiddleware } from '../middleware/callMiddleware.js';
|
||||||
import { prependForwardSlash, removeTrailingForwardSlash } from '../path.js';
|
import { prependForwardSlash, removeTrailingForwardSlash } from '../path.js';
|
||||||
import { RedirectComponentInstance } from '../redirects/index.js';
|
import { RedirectSinglePageBuiltModule } from '../redirects/index.js';
|
||||||
import {
|
import {
|
||||||
createEnvironment,
|
createEnvironment,
|
||||||
createRenderContext,
|
createRenderContext,
|
||||||
|
@ -29,6 +29,7 @@ import {
|
||||||
createStylesheetElementSet,
|
createStylesheetElementSet,
|
||||||
} from '../render/ssr-element.js';
|
} from '../render/ssr-element.js';
|
||||||
import { matchRoute } from '../routing/match.js';
|
import { matchRoute } from '../routing/match.js';
|
||||||
|
import type { SinglePageBuiltModule } from '../build/types';
|
||||||
export { deserializeManifest } from './common.js';
|
export { deserializeManifest } from './common.js';
|
||||||
|
|
||||||
const clientLocalsSymbol = Symbol.for('astro.locals');
|
const clientLocalsSymbol = Symbol.for('astro.locals');
|
||||||
|
@ -171,9 +172,9 @@ export class App {
|
||||||
return getSetCookiesFromResponse(response);
|
return getSetCookiesFromResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getModuleForRoute(route: RouteData): Promise<ComponentInstance> {
|
async #getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule> {
|
||||||
if (route.type === 'redirect') {
|
if (route.type === 'redirect') {
|
||||||
return RedirectComponentInstance;
|
return RedirectSinglePageBuiltModule;
|
||||||
} else {
|
} else {
|
||||||
const importComponentInstance = this.#manifest.pageMap.get(route.component);
|
const importComponentInstance = this.#manifest.pageMap.get(route.component);
|
||||||
if (!importComponentInstance) {
|
if (!importComponentInstance) {
|
||||||
|
@ -182,14 +183,14 @@ export class App {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const built = await importComponentInstance();
|
const built = await importComponentInstance();
|
||||||
return built.page();
|
return built;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async #renderPage(
|
async #renderPage(
|
||||||
request: Request,
|
request: Request,
|
||||||
routeData: RouteData,
|
routeData: RouteData,
|
||||||
mod: ComponentInstance,
|
page: SinglePageBuiltModule,
|
||||||
status = 200
|
status = 200
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
@ -214,6 +215,7 @@ export class App {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const mod = (await page.page()) as any;
|
||||||
const renderContext = await createRenderContext({
|
const renderContext = await createRenderContext({
|
||||||
request,
|
request,
|
||||||
origin: url.origin,
|
origin: url.origin,
|
||||||
|
@ -224,7 +226,7 @@ export class App {
|
||||||
links,
|
links,
|
||||||
route: routeData,
|
route: routeData,
|
||||||
status,
|
status,
|
||||||
mod: mod as any,
|
mod,
|
||||||
env: this.#env,
|
env: this.#env,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -235,7 +237,7 @@ export class App {
|
||||||
site: this.#env.site,
|
site: this.#env.site,
|
||||||
adapterName: this.#env.adapterName,
|
adapterName: this.#env.adapterName,
|
||||||
});
|
});
|
||||||
const onRequest = this.#manifest.middleware?.onRequest;
|
const onRequest = page.middleware?.onRequest;
|
||||||
let response;
|
let response;
|
||||||
if (onRequest) {
|
if (onRequest) {
|
||||||
response = await callMiddleware<Response>(
|
response = await callMiddleware<Response>(
|
||||||
|
@ -268,11 +270,12 @@ export class App {
|
||||||
async #callEndpoint(
|
async #callEndpoint(
|
||||||
request: Request,
|
request: Request,
|
||||||
routeData: RouteData,
|
routeData: RouteData,
|
||||||
mod: ComponentInstance,
|
page: SinglePageBuiltModule,
|
||||||
status = 200
|
status = 200
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const pathname = '/' + this.removeBase(url.pathname);
|
const pathname = '/' + this.removeBase(url.pathname);
|
||||||
|
const mod = await page.page();
|
||||||
const handler = mod as unknown as EndpointHandler;
|
const handler = mod as unknown as EndpointHandler;
|
||||||
|
|
||||||
const ctx = await createRenderContext({
|
const ctx = await createRenderContext({
|
||||||
|
@ -285,13 +288,7 @@ export class App {
|
||||||
mod: handler as any,
|
mod: handler as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await callEndpoint(
|
const result = await callEndpoint(handler, this.#env, ctx, this.#logging, page.middleware);
|
||||||
handler,
|
|
||||||
this.#env,
|
|
||||||
ctx,
|
|
||||||
this.#logging,
|
|
||||||
this.#manifest.middleware
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.type === 'response') {
|
if (result.type === 'response') {
|
||||||
if (result.response.headers.get('X-Astro-Response') === 'Not-Found') {
|
if (result.response.headers.get('X-Astro-Response') === 'Not-Found') {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { MarkdownRenderingOptions } from '@astrojs/markdown-remark';
|
import type { MarkdownRenderingOptions } from '@astrojs/markdown-remark';
|
||||||
import type {
|
import type {
|
||||||
AstroMiddlewareInstance,
|
AstroMiddlewareInstance,
|
||||||
|
ComponentInstance,
|
||||||
RouteData,
|
RouteData,
|
||||||
SerializedRouteData,
|
SerializedRouteData,
|
||||||
SSRComponentMetadata,
|
SSRComponentMetadata,
|
||||||
|
@ -49,7 +50,6 @@ export interface SSRManifest {
|
||||||
entryModules: Record<string, string>;
|
entryModules: Record<string, string>;
|
||||||
assets: Set<string>;
|
assets: Set<string>;
|
||||||
componentMetadata: SSRResult['componentMetadata'];
|
componentMetadata: SSRResult['componentMetadata'];
|
||||||
middleware?: AstroMiddlewareInstance<unknown>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SerializedSSRManifest = Omit<
|
export type SerializedSSRManifest = Omit<
|
||||||
|
|
|
@ -41,7 +41,7 @@ import { debug, info } from '../logger/core.js';
|
||||||
import { callMiddleware } from '../middleware/callMiddleware.js';
|
import { callMiddleware } from '../middleware/callMiddleware.js';
|
||||||
import {
|
import {
|
||||||
getRedirectLocationOrThrow,
|
getRedirectLocationOrThrow,
|
||||||
RedirectComponentInstance,
|
RedirectSinglePageBuiltModule,
|
||||||
routeIsRedirect,
|
routeIsRedirect,
|
||||||
} from '../redirects/index.js';
|
} from '../redirects/index.js';
|
||||||
import { createEnvironment, createRenderContext, renderPage } from '../render/index.js';
|
import { createEnvironment, createRenderContext, renderPage } from '../render/index.js';
|
||||||
|
@ -69,10 +69,6 @@ import type {
|
||||||
} from './types';
|
} from './types';
|
||||||
import { getTimeStat } from './util.js';
|
import { getTimeStat } from './util.js';
|
||||||
|
|
||||||
const StaticMiddlewareInstance: AstroMiddlewareInstance<unknown> = {
|
|
||||||
onRequest: (ctx, next) => next(),
|
|
||||||
};
|
|
||||||
|
|
||||||
function createEntryURL(filePath: string, outFolder: URL) {
|
function createEntryURL(filePath: string, outFolder: URL) {
|
||||||
return new URL('./' + filePath + `?time=${Date.now()}`, outFolder);
|
return new URL('./' + filePath + `?time=${Date.now()}`, outFolder);
|
||||||
}
|
}
|
||||||
|
@ -94,11 +90,7 @@ async function getEntryForRedirectRoute(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return RedirectSinglePageBuiltModule;
|
||||||
page: () => Promise.resolve(RedirectComponentInstance),
|
|
||||||
middleware: StaticMiddlewareInstance,
|
|
||||||
renderers: [],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldSkipDraft(pageModule: ComponentInstance, settings: AstroSettings): boolean {
|
function shouldSkipDraft(pageModule: ComponentInstance, settings: AstroSettings): boolean {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../../constants.js';
|
import { MIDDLEWARE_PATH_SEGMENT_NAME } from '../../constants.js';
|
||||||
import { addRollupInput } from '../add-rollup-input.js';
|
|
||||||
import type { BuildInternals } from '../internal.js';
|
import type { BuildInternals } from '../internal.js';
|
||||||
import type { AstroBuildPlugin } from '../plugin';
|
import type { AstroBuildPlugin } from '../plugin';
|
||||||
import type { StaticBuildOptions } from '../types';
|
import type { StaticBuildOptions } from '../types';
|
||||||
|
@ -13,14 +12,9 @@ export function vitePluginMiddleware(
|
||||||
): VitePlugin {
|
): VitePlugin {
|
||||||
return {
|
return {
|
||||||
name: '@astro/plugin-middleware',
|
name: '@astro/plugin-middleware',
|
||||||
options(options) {
|
|
||||||
if (opts.settings.config.experimental.middleware) {
|
|
||||||
return addRollupInput(options, [MIDDLEWARE_MODULE_ID]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async resolveId(id) {
|
async resolveId(id) {
|
||||||
if (id === MIDDLEWARE_MODULE_ID && opts.settings.config.experimental.middleware) {
|
if (id === MIDDLEWARE_MODULE_ID) {
|
||||||
const middlewareId = await this.resolve(
|
const middlewareId = await this.resolve(
|
||||||
`${opts.settings.config.srcDir.pathname}/${MIDDLEWARE_PATH_SEGMENT_NAME}`
|
`${opts.settings.config.srcDir.pathname}/${MIDDLEWARE_PATH_SEGMENT_NAME}`
|
||||||
);
|
);
|
||||||
|
|
|
@ -80,9 +80,10 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
|
||||||
imports.push(`import { renderers } from "${RENDERERS_MODULE_ID}";`);
|
imports.push(`import { renderers } from "${RENDERERS_MODULE_ID}";`);
|
||||||
exports.push(`export { renderers };`);
|
exports.push(`export { renderers };`);
|
||||||
|
|
||||||
if (opts.settings.config.experimental.middleware) {
|
const middlewareModule = await this.resolve(MIDDLEWARE_MODULE_ID);
|
||||||
imports.push(`import * as _middleware from "${MIDDLEWARE_MODULE_ID}";`);
|
if (middlewareModule) {
|
||||||
exports.push(`export const middleware = _middleware;`);
|
imports.push(`import * as middleware from "${middlewareModule.id}";`);
|
||||||
|
exports.push(`export { middleware };`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${imports.join('\n')}${exports.join('\n')}`;
|
return `${imports.join('\n')}${exports.join('\n')}`;
|
||||||
|
|
|
@ -48,11 +48,6 @@ function vitePluginSSR(
|
||||||
const imports: string[] = [];
|
const imports: string[] = [];
|
||||||
const contents: string[] = [];
|
const contents: string[] = [];
|
||||||
const exports: string[] = [];
|
const exports: string[] = [];
|
||||||
let middleware;
|
|
||||||
if (config.experimental?.middleware === true) {
|
|
||||||
imports.push(`import * as _middleware from "${MIDDLEWARE_MODULE_ID}"`);
|
|
||||||
middleware = 'middleware: _middleware';
|
|
||||||
}
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const pageMap: string[] = [];
|
const pageMap: string[] = [];
|
||||||
|
|
||||||
|
@ -84,7 +79,6 @@ import { _privateSetManifestDontUseThis } from 'astro:ssr-manifest';
|
||||||
const _manifest = Object.assign(_deserializeManifest('${manifestReplace}'), {
|
const _manifest = Object.assign(_deserializeManifest('${manifestReplace}'), {
|
||||||
pageMap,
|
pageMap,
|
||||||
renderers,
|
renderers,
|
||||||
${middleware}
|
|
||||||
});
|
});
|
||||||
_privateSetManifestDontUseThis(_manifest);
|
_privateSetManifestDontUseThis(_manifest);
|
||||||
const _args = ${adapter.args ? JSON.stringify(adapter.args) : 'undefined'};
|
const _args = ${adapter.args ? JSON.stringify(adapter.args) : 'undefined'};
|
||||||
|
|
|
@ -179,9 +179,9 @@ async function ssrBuild(
|
||||||
return makeAstroPageEntryPointFileName(chunkInfo.facadeModuleId);
|
return makeAstroPageEntryPointFileName(chunkInfo.facadeModuleId);
|
||||||
} else if (
|
} else if (
|
||||||
// checks if the path of the module we have middleware, e.g. middleware.js / middleware/index.js
|
// checks if the path of the module we have middleware, e.g. middleware.js / middleware/index.js
|
||||||
chunkInfo.facadeModuleId?.includes('middleware') &&
|
chunkInfo.moduleIds.find((m) => m.includes('middleware')) !== undefined &&
|
||||||
// checks if the file actually export the `onRequest` function
|
// checks if the file actually export the `onRequest` function
|
||||||
chunkInfo.exports.includes('onRequest')
|
chunkInfo.exports.includes('_middleware')
|
||||||
) {
|
) {
|
||||||
return 'middleware.mjs';
|
return 'middleware.mjs';
|
||||||
} else if (chunkInfo.facadeModuleId === SSR_VIRTUAL_MODULE_ID) {
|
} else if (chunkInfo.facadeModuleId === SSR_VIRTUAL_MODULE_ID) {
|
||||||
|
|
|
@ -104,8 +104,6 @@ export function resolveFlags(flags: Partial<Flags>): CLIFlags {
|
||||||
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined,
|
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined,
|
||||||
experimentalAssets:
|
experimentalAssets:
|
||||||
typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined,
|
typeof flags.experimentalAssets === 'boolean' ? flags.experimentalAssets : undefined,
|
||||||
experimentalMiddleware:
|
|
||||||
typeof flags.experimentalMiddleware === 'boolean' ? flags.experimentalMiddleware : undefined,
|
|
||||||
experimentalRedirects:
|
experimentalRedirects:
|
||||||
typeof flags.experimentalRedirects === 'boolean' ? flags.experimentalRedirects : undefined,
|
typeof flags.experimentalRedirects === 'boolean' ? flags.experimentalRedirects : undefined,
|
||||||
};
|
};
|
||||||
|
@ -141,9 +139,6 @@ function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) {
|
||||||
// TODO: Come back here and refactor to remove this expected error.
|
// TODO: Come back here and refactor to remove this expected error.
|
||||||
astroConfig.server.open = flags.open;
|
astroConfig.server.open = flags.open;
|
||||||
}
|
}
|
||||||
if (typeof flags.experimentalMiddleware === 'boolean') {
|
|
||||||
astroConfig.experimental.middleware = true;
|
|
||||||
}
|
|
||||||
return astroConfig;
|
return astroConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,6 @@ export const AstroConfigSchema = z.object({
|
||||||
.boolean()
|
.boolean()
|
||||||
.optional()
|
.optional()
|
||||||
.default(ASTRO_CONFIG_DEFAULTS.experimental.customClientDirecives),
|
.default(ASTRO_CONFIG_DEFAULTS.experimental.customClientDirecives),
|
||||||
middleware: z.oboolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.middleware),
|
|
||||||
hybridOutput: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.hybridOutput),
|
hybridOutput: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.hybridOutput),
|
||||||
redirects: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.redirects),
|
redirects: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.redirects),
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { ComponentInstance } from '../../@types/astro';
|
import type { AstroMiddlewareInstance, ComponentInstance } from '../../@types/astro';
|
||||||
|
import type { SinglePageBuiltModule } from '../build/types';
|
||||||
|
|
||||||
// A stub of a component instance for a given route
|
// A stub of a component instance for a given route
|
||||||
export const RedirectComponentInstance: ComponentInstance = {
|
export const RedirectComponentInstance: ComponentInstance = {
|
||||||
|
@ -8,3 +9,13 @@ export const RedirectComponentInstance: ComponentInstance = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const StaticMiddlewareInstance: AstroMiddlewareInstance<unknown> = {
|
||||||
|
onRequest: (ctx, next) => next(),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RedirectSinglePageBuiltModule: SinglePageBuiltModule = {
|
||||||
|
page: () => Promise.resolve(RedirectComponentInstance),
|
||||||
|
middleware: StaticMiddlewareInstance,
|
||||||
|
renderers: [],
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export { RedirectComponentInstance } from './component.js';
|
export { RedirectComponentInstance, RedirectSinglePageBuiltModule } from './component.js';
|
||||||
export { redirectRouteGenerate, redirectRouteStatus, routeIsRedirect } from './helpers.js';
|
export { redirectRouteGenerate, redirectRouteStatus, routeIsRedirect } from './helpers.js';
|
||||||
export { getRedirectLocationOrThrow } from './validate.js';
|
export { getRedirectLocationOrThrow } from './validate.js';
|
||||||
|
|
|
@ -180,11 +180,9 @@ export async function handleRoute(
|
||||||
request,
|
request,
|
||||||
route,
|
route,
|
||||||
};
|
};
|
||||||
if (env.settings.config.experimental.middleware) {
|
const middleware = await loadMiddleware(env.loader, env.settings.config.srcDir);
|
||||||
const middleware = await loadMiddleware(env.loader, env.settings.config.srcDir);
|
if (middleware) {
|
||||||
if (middleware) {
|
options.middleware = middleware;
|
||||||
options.middleware = middleware;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Route successfully matched! Render it.
|
// Route successfully matched! Render it.
|
||||||
if (route.type === 'endpoint') {
|
if (route.type === 'endpoint') {
|
||||||
|
|
|
@ -109,9 +109,7 @@ describe('Middleware API in PROD mode, SSR', () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
root: './fixtures/middleware-dev/',
|
root: './fixtures/middleware-dev/',
|
||||||
output: 'server',
|
output: 'server',
|
||||||
adapter: testAdapter({
|
adapter: testAdapter({}),
|
||||||
// exports: ['manifest', 'createApp', 'middleware'],
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue