From cbe652bbd8d4e55cc86eb448dfe5113e377da684 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Mon, 17 Nov 2025 17:13:44 +0000 Subject: [PATCH] fix: flag `serverLike` incorrectly computed --- packages/astro/src/container/index.ts | 3 +- packages/astro/src/container/pipeline.ts | 20 ++++--------- packages/astro/src/core/app/dev/pipeline.ts | 7 +++-- packages/astro/src/core/app/pipeline.ts | 7 +++-- packages/astro/src/core/app/types.ts | 7 +++++ packages/astro/src/core/base-pipeline.ts | 10 ++++--- packages/astro/src/core/build/generate.ts | 6 ++-- packages/astro/src/core/build/pipeline.ts | 29 ++++++++++--------- .../src/core/build/plugins/plugin-manifest.ts | 19 +++++++----- .../astro/src/core/middleware/sequence.ts | 2 +- packages/astro/src/core/render-context.ts | 8 ++--- packages/astro/src/manifest/serialized.ts | 1 + packages/astro/src/vite-plugin-app/app.ts | 4 +-- .../astro/src/vite-plugin-app/pipeline.ts | 7 +++-- .../src/vite-plugin-astro-server/plugin.ts | 1 + packages/astro/src/vite-plugin-css/index.ts | 6 +--- 16 files changed, 76 insertions(+), 61 deletions(-) diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 6c1eade0c863..f3851defb626 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -145,6 +145,7 @@ function createManifest( trailingSlash: manifest?.trailingSlash ?? ASTRO_CONFIG_DEFAULTS.trailingSlash, buildFormat: manifest?.buildFormat ?? ASTRO_CONFIG_DEFAULTS.build.format, compressHTML: manifest?.compressHTML ?? ASTRO_CONFIG_DEFAULTS.compressHTML, + serverLike: manifest?.serverLike ?? false, assets: manifest?.assets ?? new Set(), assetsPrefix: manifest?.assetsPrefix ?? undefined, entryModules: manifest?.entryModules ?? {}, @@ -254,6 +255,7 @@ type AstroContainerManifest = Pick< | 'cacheDir' | 'csp' | 'allowedDomains' + | 'serverLike' >; type AstroContainerConstructor = { @@ -287,7 +289,6 @@ export class experimental_AstroContainer { }), manifest: createManifest(manifest, renderers), streaming, - serverLike: true, renderers: renderers ?? manifest?.renderers ?? [], resolve: async (specifier: string) => { if (this.#withManifest) { diff --git a/packages/astro/src/container/pipeline.ts b/packages/astro/src/container/pipeline.ts index 919edb0083b0..ffdb490875bf 100644 --- a/packages/astro/src/container/pipeline.ts +++ b/packages/astro/src/container/pipeline.ts @@ -19,26 +19,18 @@ export class ContainerPipeline extends Pipeline { SinglePageBuiltModule >(); + getName(): string { + return 'ContainerPipeline'; + } + static create({ logger, manifest, renderers, resolve, - serverLike, streaming, - }: Pick< - ContainerPipeline, - 'logger' | 'manifest' | 'renderers' | 'resolve' | 'serverLike' | 'streaming' - >) { - return new ContainerPipeline( - logger, - manifest, - 'development', - renderers, - resolve, - serverLike, - streaming, - ); + }: Pick) { + return new ContainerPipeline(logger, manifest, 'development', renderers, resolve, streaming); } componentMetadata(_routeData: RouteData): Promise | void {} diff --git a/packages/astro/src/core/app/dev/pipeline.ts b/packages/astro/src/core/app/dev/pipeline.ts index e9240c9d32fe..412dd4e16893 100644 --- a/packages/astro/src/core/app/dev/pipeline.ts +++ b/packages/astro/src/core/app/dev/pipeline.ts @@ -13,6 +13,10 @@ import { findRouteToRewrite } from '../../routing/rewrite.js'; type DevPipelineCreate = Pick; export class DevPipeline extends Pipeline { + getName(): string { + return 'DevPipeline'; + } + static create({ logger, manifest, streaming }: DevPipelineCreate) { async function resolve(specifier: string): Promise { if (specifier.startsWith('/')) { @@ -28,7 +32,6 @@ export class DevPipeline extends Pipeline { 'production', manifest.renderers, resolve, - true, streaming, undefined, undefined, @@ -126,7 +129,7 @@ export class DevPipeline extends Pipeline { trailingSlash: this.manifest.trailingSlash, buildFormat: this.manifest.buildFormat, base: this.manifest.base, - outDir: this.serverLike ? this.manifest.buildClientDir : this.manifest.outDir, + outDir: this.manifest?.serverLike ? this.manifest.buildClientDir : this.manifest.outDir, }); const componentInstance = await this.getComponentByRoute(routeData); diff --git a/packages/astro/src/core/app/pipeline.ts b/packages/astro/src/core/app/pipeline.ts index cbe7fd782595..646b11cedd40 100644 --- a/packages/astro/src/core/app/pipeline.ts +++ b/packages/astro/src/core/app/pipeline.ts @@ -10,6 +10,10 @@ import { import { findRouteToRewrite } from '../routing/rewrite.js'; export class AppPipeline extends Pipeline { + getName(): string { + return 'AppPipeline'; + } + static create({ logger, manifest, @@ -32,7 +36,6 @@ export class AppPipeline extends Pipeline { 'production', manifest.renderers, resolve, - true, streaming, undefined, undefined, @@ -84,7 +87,7 @@ export class AppPipeline extends Pipeline { trailingSlash: this.manifest.trailingSlash, buildFormat: this.manifest.buildFormat, base: this.manifest.base, - outDir: this.serverLike ? this.manifest.buildClientDir : this.manifest.outDir, + outDir: this.manifest?.serverLike ? this.manifest.buildClientDir : this.manifest.outDir, }); const componentInstance = await this.getComponentByRoute(routeData); diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts index dcef115ce28c..875c0fc2f16a 100644 --- a/packages/astro/src/core/app/types.ts +++ b/packages/astro/src/core/app/types.ts @@ -74,6 +74,13 @@ export type SSRManifest = { compressHTML: boolean; assetsPrefix?: AssetsPrefix; renderers: SSRLoadedRenderer[]; + /** + * Based on Astro config's `output` option, `true` if "server" or "hybrid". + * + * Whether this application is SSR-like. If so, this has some implications, such as + * the creation of `dist/client` and `dist/server` folders. + */ + serverLike: boolean; /** * Map of directive name (e.g. `load`) to the directive script code */ diff --git a/packages/astro/src/core/base-pipeline.ts b/packages/astro/src/core/base-pipeline.ts index b766932e5f06..535dd54f774e 100644 --- a/packages/astro/src/core/base-pipeline.ts +++ b/packages/astro/src/core/base-pipeline.ts @@ -46,10 +46,7 @@ export abstract class Pipeline { readonly runtimeMode: RuntimeMode, readonly renderers: SSRLoadedRenderer[], readonly resolve: (s: string) => Promise, - /** - * 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` @@ -106,6 +103,11 @@ export abstract class Pipeline { */ abstract getComponentByRoute(routeData: RouteData): Promise; + /** + * The current name of the pipeline. Useful for debugging + */ + abstract getName(): string; + /** * Resolves the middleware from the manifest, and returns the `onRequest` function. If `onRequest` isn't there, * it returns a no-op function diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 5175ac5e9564..fae103248430 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -48,7 +48,7 @@ export async function generatePages( const prerenderEntryFileName = internals.prerenderEntryFileName; if (!prerenderEntryFileName) { throw new Error( - `Prerender entry filename not found in build internals. This is likely a bug in Astro.` + `Prerender entry filename not found in build internals. This is likely a bug in Astro.`, ); } const prerenderEntryUrl = new URL(prerenderEntryFileName, prerenderOutputDir); @@ -296,7 +296,7 @@ async function getPathsForRoute( pipeline: BuildPipeline, builtPaths: Set, ): Promise> { - const { logger, options, routeCache, serverLike, manifest } = pipeline; + const { logger, options, routeCache, manifest } = pipeline; let paths: Array = []; if (route.pathname) { paths.push(route.pathname); @@ -317,7 +317,7 @@ async function getPathsForRoute( route, routeCache, logger, - ssr: serverLike, + ssr: manifest.serverLike, base: manifest.base, trailingSlash: manifest.trailingSlash, }).catch((err) => { diff --git a/packages/astro/src/core/build/pipeline.ts b/packages/astro/src/core/build/pipeline.ts index 1d74628bd955..f09aeffd275d 100644 --- a/packages/astro/src/core/build/pipeline.ts +++ b/packages/astro/src/core/build/pipeline.ts @@ -1,11 +1,10 @@ import type { ComponentInstance } from '../../types/astro.js'; import type { RewritePayload } from '../../types/public/common.js'; -import type { - RouteData, - SSRElement, - SSRResult, -} from '../../types/public/internal.js'; -import { VIRTUAL_PAGE_MODULE_ID, VIRTUAL_PAGE_RESOLVED_MODULE_ID } from '../../vite-plugin-pages/index.js'; +import type { RouteData, SSRElement, SSRResult } from '../../types/public/internal.js'; +import { + VIRTUAL_PAGE_MODULE_ID, + VIRTUAL_PAGE_RESOLVED_MODULE_ID, +} from '../../vite-plugin-pages/index.js'; import { getVirtualModulePageName } from '../../vite-plugin-pages/util.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import type { SSRManifest } from '../app/types.js'; @@ -24,6 +23,10 @@ import type { SinglePageBuiltModule, StaticBuildOptions } from './types.js'; * The build pipeline is responsible to gather the files emitted by the SSR build and generate the pages by executing these files. */ export class BuildPipeline extends Pipeline { + getName(): string { + return 'BuildPipeline'; + } + #componentsInterner: WeakMap = new WeakMap< RouteData, SinglePageBuiltModule @@ -69,17 +72,14 @@ export class BuildPipeline extends Pipeline { return assetLink; } - const serverLike = settings.buildOutput === 'server'; // We can skip streaming in SSG for performance as writing as strings are faster - const streaming = serverLike; super( options.logger, manifest, options.runtimeMode, manifest.renderers, resolve, - serverLike, - streaming, + manifest.serverLike, ); } @@ -143,9 +143,12 @@ export class BuildPipeline extends Pipeline { retrieveRoutesToGenerate(): Map { const pages = new Map(); - for(const { routeData } of this.manifest.routes) { + for (const { routeData } of this.manifest.routes) { // Here, we take the component path and transform it in the virtual module name - const moduleSpecifier = getVirtualModulePageName(VIRTUAL_PAGE_RESOLVED_MODULE_ID, routeData.component); + const moduleSpecifier = getVirtualModulePageName( + VIRTUAL_PAGE_RESOLVED_MODULE_ID, + routeData.component, + ); // We retrieve the original JS module const filePath = this.internals.entrySpecifierToBundleMap.get(moduleSpecifier); if (filePath) { @@ -187,7 +190,7 @@ export class BuildPipeline extends Pipeline { trailingSlash: this.config.trailingSlash, buildFormat: this.config.build.format, base: this.config.base, - outDir: this.serverLike ? this.manifest.buildClientDir : this.manifest.outDir, + outDir: this.manifest.serverLike ? this.manifest.buildClientDir : this.manifest.outDir, }); const componentInstance = await this.getComponentByRoute(routeData); diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index e28eaf043fab..dedea47d8cf3 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -5,9 +5,7 @@ import type * as vite from 'vite'; import { getAssetsPrefix } from '../../../assets/utils/getAssetsPrefix.js'; import { normalizeTheLocale } from '../../../i18n/index.js'; import { runHookBuildSsr } from '../../../integrations/hooks.js'; -import { - SERIALIZED_MANIFEST_RESOLVED_ID, -} from '../../../manifest/serialized.js'; +import { SERIALIZED_MANIFEST_RESOLVED_ID } from '../../../manifest/serialized.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js'; import { toFallbackType } from '../../app/common.js'; import { serializeRouteData, toRoutingStrategy } from '../../app/index.js'; @@ -68,15 +66,19 @@ const replaceExp = new RegExp(`['"]${MANIFEST_REPLACE}['"]`, 'g'); export async function manifestBuildPostHook( options: StaticBuildOptions, internals: BuildInternals, - { ssrOutputs, prerenderOutputs, mutate }: { - ssrOutputs: vite.Rollup.RollupOutput[], - prerenderOutputs: vite.Rollup.RollupOutput[], + { + ssrOutputs, + prerenderOutputs, + mutate, + }: { + ssrOutputs: vite.Rollup.RollupOutput[]; + prerenderOutputs: vite.Rollup.RollupOutput[]; mutate: (chunk: OutputChunk, envs: ['server'], code: string) => void; }, ) { const manifest = await createManifest(options, internals); - if(ssrOutputs.length > 0) { + if (ssrOutputs.length > 0) { let manifestEntryChunk: OutputChunk | undefined; // Find the serialized manifest chunk in SSR outputs @@ -245,7 +247,7 @@ async function buildManifest( }); // Add the built .html file as a staticFile - if(route.prerender && route.pathname) { + if (route.prerender && route.pathname) { const outFolder = getOutFolder(opts.settings, route.pathname, route); const outFile = getOutFile(opts.settings.config, outFolder, route.pathname, route); const file = outFile.toString().replace(opts.settings.config.build.client.toString(), ''); @@ -319,6 +321,7 @@ async function buildManifest( buildServerDir: opts.settings.config.build.server.toString(), adapterName: opts.settings.adapter?.name ?? '', routes, + serverLike: opts.settings.buildOutput === 'server', site: settings.config.site, base: settings.config.base, userAssetsBase: settings.config?.vite?.base, diff --git a/packages/astro/src/core/middleware/sequence.ts b/packages/astro/src/core/middleware/sequence.ts index 7c08136cdd5a..a470e5a97487 100644 --- a/packages/astro/src/core/middleware/sequence.ts +++ b/packages/astro/src/core/middleware/sequence.ts @@ -59,7 +59,7 @@ export function sequence(...handlers: MiddlewareHandler[]): MiddlewareHandler { // This case isn't valid because when building for SSR, the prerendered route disappears from the server output because it becomes an HTML file, // so Astro can't retrieve it from the emitted manifest. if ( - pipeline.serverLike === true && + pipeline.manifest.serverLike === true && handleContext.isPrerendered === false && routeData.prerender === true ) { diff --git a/packages/astro/src/core/render-context.ts b/packages/astro/src/core/render-context.ts index 5f8388bdfadd..79d72cff1f9f 100644 --- a/packages/astro/src/core/render-context.ts +++ b/packages/astro/src/core/render-context.ts @@ -164,7 +164,7 @@ export class RenderContext { slots: Record = {}, ): Promise { const { middleware, pipeline } = this; - const { logger, serverLike, streaming, manifest } = pipeline; + const { logger, streaming, manifest } = pipeline; const props = Object.keys(this.props).length > 0 @@ -175,7 +175,7 @@ export class RenderContext { routeCache: this.pipeline.routeCache, pathname: this.pathname, logger, - serverLike, + serverLike: manifest.serverLike, base: manifest.base, trailingSlash: manifest.trailingSlash, }); @@ -207,7 +207,7 @@ export class RenderContext { // This case isn't valid because when building for SSR, the prerendered route disappears from the server output because it becomes an HTML file, // so Astro can't retrieve it from the emitted manifest. if ( - this.pipeline.serverLike === true && + this.pipeline.manifest.serverLike === true && this.routeData.prerender === false && routeData.prerender === true ) { @@ -360,7 +360,7 @@ export class RenderContext { // Allow i18n fallback rewrites - if the target route has fallback routes, this is likely an i18n scenario const isI18nFallback = routeData.fallbackRoutes && routeData.fallbackRoutes.length > 0; if ( - this.pipeline.serverLike && + this.pipeline.manifest.serverLike && !this.routeData.prerender && routeData.prerender && !isI18nFallback diff --git a/packages/astro/src/manifest/serialized.ts b/packages/astro/src/manifest/serialized.ts index b32b03ad89d2..14e5a4605737 100644 --- a/packages/astro/src/manifest/serialized.ts +++ b/packages/astro/src/manifest/serialized.ts @@ -122,6 +122,7 @@ async function createSerializedManifest(settings: AstroSettings): Promise { - const { logger, routeCache, serverLike } = pipeline; + const { logger, routeCache } = pipeline; const matches = matchAllRoutes(pathname, routesList); const preloadedMatches = await getSortedPreloadedMatches({ @@ -504,7 +504,7 @@ async function matchRoute( routeCache, pathname: pathname, logger, - serverLike, + serverLike: pipeline.manifest.serverLike, base: manifest.base, trailingSlash: manifest.trailingSlash, }); diff --git a/packages/astro/src/vite-plugin-app/pipeline.ts b/packages/astro/src/vite-plugin-app/pipeline.ts index 09ba6f9f97fb..16024d49a815 100644 --- a/packages/astro/src/vite-plugin-app/pipeline.ts +++ b/packages/astro/src/vite-plugin-app/pipeline.ts @@ -26,6 +26,10 @@ import { createResolve } from '../vite-plugin-astro-server/resolve.js'; import { PAGE_SCRIPT_ID } from '../vite-plugin-scripts/index.js'; export class AstroServerPipeline extends Pipeline { + getName(): string { + return 'AstroServerPipeline'; + } + // renderers are loaded on every request, // so it needs to be mutable here unlike in other environments override renderers = new Array(); @@ -45,9 +49,8 @@ export class AstroServerPipeline extends Pipeline { readonly defaultRoutes = createDefaultRoutes(manifest), ) { const resolve = createResolve(loader, manifest.rootDir); - const serverLike = settings?.buildOutput === 'server'; const streaming = true; - super(logger, manifest, 'development', [], resolve, serverLike, streaming); + super(logger, manifest, 'development', [], resolve, streaming); } static create( diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index e3d9fbf27c20..869f71648b42 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -219,6 +219,7 @@ export async function createDevelopmentManifest(settings: AstroSettings): Promis trailingSlash: settings.config.trailingSlash, buildFormat: settings.config.build.format, compressHTML: settings.config.compressHTML, + serverLike: settings.buildOutput === 'server', assets: new Set(), entryModules: {}, routes: [], diff --git a/packages/astro/src/vite-plugin-css/index.ts b/packages/astro/src/vite-plugin-css/index.ts index 05605a6f5597..b2c4d2d01326 100644 --- a/packages/astro/src/vite-plugin-css/index.ts +++ b/packages/astro/src/vite-plugin-css/index.ts @@ -36,11 +36,7 @@ export function astroDevCssPlugin({ routesList, command }: AstroVitePluginOption return next(); }); }, - - applyToEnvironment(env) { - return env.name === 'ssr' || env.name === 'astro'; - }, - + resolveId(id) { if (id === MODULE_DEV_CSS) { return RESOLVED_MODULE_DEV_CSS;