Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/astro/dev-only.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ declare module 'virtual:astro:renderers' {
import type { AstroRenderer } from './src/index.js';
export const renderers: AstroRenderer[];
}

declare module 'virtual:astro:middleware' {
import type { AstroMiddlewareInstance } from './src/index.js';
const middleware: AstroMiddlewareInstance;
export default middleware;
}
3 changes: 1 addition & 2 deletions packages/astro/src/core/app/dev/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import { DevPipeline } from './pipeline.js';
export class DevApp extends BaseApp<DevPipeline> {
logger: Logger;
currentRenderContext: RenderContext | undefined = undefined;
constructor(manifest: SSRManifest, streaming = true, logger: Logger, routesList: RoutesList) {
constructor(manifest: SSRManifest, streaming = true, logger: Logger) {
super(manifest, streaming, logger);
this.logger = logger;
this.manifestData = routesList;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't needed because it's done in base.ts

}

createPipeline(streaming: boolean, manifest: SSRManifest, logger: Logger): DevPipeline {
Expand Down
15 changes: 13 additions & 2 deletions packages/astro/src/core/app/entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,27 @@ import { App } from './app.js';
import type { BaseApp } from './base.js';
import { DevApp } from './dev/app.js';
import { createConsoleLogger } from './logging.js';
import type { SSRManifest } from './types.js';

const actions = async () => {
return await import('virtual:astro:actions/entrypoint');
};
const manifest = Object.assign(serializedManifest, { renderers, actions });

const middleware = async () => {
return await import('virtual:astro:middleware');
};

const manifest: SSRManifest = Object.assign(serializedManifest, {
renderers,
actions,
middleware,
routes,
});

export function getApp(dev = import.meta.env.DEV): BaseApp {
if (dev) {
const logger = createConsoleLogger('debug');
return new DevApp(manifest, true, logger, { routes: routes.map((r) => r.routeData) });
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return new DevApp(manifest, true, logger);
} else {
return new App(manifest);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/base-pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export abstract class Pipeline {
if (this.resolvedActions) {
return this.resolvedActions;
} else if (this.actions) {
return await this.actions();
return this.actions();
}
return NOOP_ACTIONS_MOD;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/build/plugins/plugin-ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Plugin as VitePlugin } from 'vite';
import { ENTRYPOINT_VIRTUAL_MODULE_ID } from '../../../actions/consts.js';
import type { AstroAdapter } from '../../../types/public/integrations.js';
import { ASTRO_RENDERERS_MODULE_ID } from '../../../vite-plugin-renderers/index.js';
import { MIDDLEWARE_MODULE_ID } from '../../middleware/vite-plugin.js';
import { MIDDLEWARE_RESOLVED_MODULE_ID } from '../../middleware/vite-plugin.js';
import { routeIsRedirect } from '../../redirects/index.js';
import { VIRTUAL_ISLAND_MAP_ID } from '../../server-islands/vite-plugin-server-islands.js';
import { addRollupInput } from '../add-rollup-input.js';
Expand Down Expand Up @@ -101,7 +101,7 @@ function vitePluginSSR(
}
contents.push(`const pageMap = new Map([\n ${pageMap.join(',\n ')}\n]);`);
exports.push(`export { pageMap }`);
const middleware = await this.resolve(MIDDLEWARE_MODULE_ID);
const middleware = await this.resolve(MIDDLEWARE_RESOLVED_MODULE_ID);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change needed?

Copy link
Member Author

@ematipico ematipico Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because up until now the middleware virtual module was never imported via import. Now we do that, so we need a simple name, and the one with \0

Copy link
Member

@florian-lefebvre florian-lefebvre Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I don't understand, why do we need to import the module with the null byte? Asking because my understanding is that Vite is supposed to be able to resolve the id without the null byte (which is kinda like an implementation detail of the virtual module)

const ssrCode = generateSSRCode(adapter, middleware!.id);
imports.push(...ssrCode.imports);
contents.push(...ssrCode.contents);
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/core/middleware/loadMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MiddlewareCantBeLoaded } from '../errors/errors-data.js';
import { AstroError } from '../errors/index.js';
import type { ModuleLoader } from '../module-loader/index.js';
import { MIDDLEWARE_MODULE_ID } from './vite-plugin.js';
import { MIDDLEWARE_RESOLVED_MODULE_ID } from './vite-plugin.js';

/**
* It accepts a module loader and the astro settings, and it attempts to load the middlewares defined in the configuration.
Expand All @@ -10,7 +10,7 @@ import { MIDDLEWARE_MODULE_ID } from './vite-plugin.js';
*/
export async function loadMiddleware(moduleLoader: ModuleLoader) {
try {
return await moduleLoader.import(MIDDLEWARE_MODULE_ID);
return await moduleLoader.import(MIDDLEWARE_RESOLVED_MODULE_ID);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should still import MIDDLEWARE_MODULE_ID to let Vite handle the module resolution. I'd be happy to be proved wrong tho

} catch (error: any) {
const astroError = new AstroError(MiddlewareCantBeLoaded, { cause: error });
throw astroError;
Expand Down
18 changes: 11 additions & 7 deletions packages/astro/src/core/middleware/vite-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { MissingMiddlewareForInternationalization } from '../errors/errors-data.
import { AstroError } from '../errors/index.js';
import { normalizePath } from '../viteUtils.js';

export const MIDDLEWARE_MODULE_ID = '\0astro-internal:middleware';
export const MIDDLEWARE_MODULE_ID = 'virtual:astro:middleware';
export const MIDDLEWARE_RESOLVED_MODULE_ID = '\0' + MIDDLEWARE_MODULE_ID;
const NOOP_MIDDLEWARE = '\0noop-middleware';

export function vitePluginMiddleware({ settings }: { settings: AstroSettings }): VitePlugin {
Expand All @@ -19,7 +20,10 @@ export function vitePluginMiddleware({ settings }: { settings: AstroSettings }):
let userMiddlewareIsPresent = false;

return {
name: '@astro/plugin-middleware',
name: MIDDLEWARE_MODULE_ID,
applyToEnvironment(environment) {
return environment.name === 'ssr';
},
async resolveId(id) {
if (id === MIDDLEWARE_MODULE_ID) {
const middlewareId = await this.resolve(
Expand All @@ -28,9 +32,9 @@ export function vitePluginMiddleware({ settings }: { settings: AstroSettings }):
userMiddlewareIsPresent = !!middlewareId;
if (middlewareId) {
resolvedMiddlewareId = middlewareId.id;
return MIDDLEWARE_MODULE_ID;
return MIDDLEWARE_RESOLVED_MODULE_ID;
} else if (hasIntegrationMiddleware) {
return MIDDLEWARE_MODULE_ID;
return MIDDLEWARE_RESOLVED_MODULE_ID;
} else {
return NOOP_MIDDLEWARE;
}
Expand All @@ -45,7 +49,7 @@ export function vitePluginMiddleware({ settings }: { settings: AstroSettings }):
throw new AstroError(MissingMiddlewareForInternationalization);
}
return { code: 'export const onRequest = (_, next) => next()' };
} else if (id === MIDDLEWARE_MODULE_ID) {
} else if (id === MIDDLEWARE_RESOLVED_MODULE_ID) {
if (!userMiddlewareIsPresent && settings.config.i18n?.routing === 'manual') {
throw new AstroError(MissingMiddlewareForInternationalization);
}
Expand Down Expand Up @@ -106,12 +110,12 @@ export function vitePluginMiddlewareBuild(
name: '@astro/plugin-middleware-build',

options(options) {
return addRollupInput(options, [MIDDLEWARE_MODULE_ID]);
return addRollupInput(options, [MIDDLEWARE_RESOLVED_MODULE_ID]);
},

writeBundle(_, bundle) {
for (const [chunkName, chunk] of Object.entries(bundle)) {
if (chunk.type !== 'asset' && chunk.facadeModuleId === MIDDLEWARE_MODULE_ID) {
if (chunk.type !== 'asset' && chunk.facadeModuleId === MIDDLEWARE_RESOLVED_MODULE_ID) {
const outputDirectory = getServerOutputDirectory(opts.settings);
internals.middlewareEntryPoint = new URL(chunkName, outputDirectory);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/integrations/cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@
"dependencies": {
"@astrojs/internal-helpers": "workspace:*",
"@astrojs/underscore-redirects": "workspace:*",
"@cloudflare/vite-plugin": "^1.13.13",
"@cloudflare/workers-types": "^4.20251011.0",
"@cloudflare/vite-plugin": "^1.13.14",
"@cloudflare/workers-types": "^4.20251014.0",
"tinyglobby": "^0.2.15",
"vite": "^7.1.7",
"wrangler": "4.43.0"
"vite": "^7.1.12",
"wrangler": "4.44.0"
},
"peerDependencies": {
"astro": "^5.7.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defineMiddleware } from 'astro:middleware'

export const onRequest = defineMiddleware(async (ctx, next) => {
const url = new URL(ctx.request.url);

if (url.pathname.includes("/mid/to-redirect")) {
return ctx.redirect("/mid/from-redirect");
}
if (url.pathname.includes("/mid/to-rewrite")) {
return ctx.rewrite("/mid/from-rewrite");
}


ctx.locals.getGreeting = () => {
return `Hello from ${url.pathname}`;
};

return next()
})
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ const { Content } = await render(increment);
<a href="/env">Environment variables</a>
<h2>Client router</h2>
<a href="/client-router">Client router</a>
<h2>Middleware</h2>
<a href="/mid/to-redirect">Redirect</a>
<a href="/mid/to-rewrite">Rewrite</a>
<a href="/mid/locals">Locals</a>
<h2>Dogs</h2>
<p>Running on: {workerRuntime ?? 'unknown runtime'}</p>
<div id="framework">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@


<h1>Came from a redirect</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>I am a rewrite</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
const greeting = Astro.locals.getGreeting();
---

<h1>Greeting from locals</h1>
<p>{greeting}</p>
Loading
Loading