From 771b0a9a04ca4b4bcdd098b2062a5903cc988112 Mon Sep 17 00:00:00 2001 From: "Houston (Bot)" <108291165+astrobot-houston@users.noreply.github.com> Date: Tue, 18 Aug 2026 14:15:53 -0700 Subject: [PATCH] fix(container): wire astroConfig.site through to the SSR manifest so Astro.site is available in container rendering (#17682) (#17703) Co-authored-by: Matthew Phillips --- .changeset/social-paws-throw.md | 5 +++ packages/astro/src/container/index.ts | 15 ++++---- .../astro/test/units/render/container.test.ts | 34 +++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 .changeset/social-paws-throw.md diff --git a/.changeset/social-paws-throw.md b/.changeset/social-paws-throw.md new file mode 100644 index 000000000000..a3ef0b5cc5d8 --- /dev/null +++ b/.changeset/social-paws-throw.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes `Astro.site` always being `undefined` when rendering components via the Container API, even when `site` is set in `astroConfig` diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 74d90a1ead15..f554bc8c50dd 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -134,6 +134,7 @@ function createManifest( manifest?: AstroContainerManifest, renderers?: SSRLoadedRenderer[], middleware?: MiddlewareHandler, + site?: string, ): SSRManifest { function middlewareInstance(): AstroMiddlewareInstance { return { @@ -174,6 +175,7 @@ function createManifest( componentMetadata: manifest?.componentMetadata ?? new Map(), inlinedScripts: manifest?.inlinedScripts ?? new Map(), i18n: manifest?.i18n, + site: site ?? manifest?.site, checkOrigin: false, allowedDomains: manifest?.allowedDomains ?? [], actionBodySizeLimit: 1024 * 1024, @@ -281,6 +283,7 @@ type AstroContainerManifest = Pick< | 'middlewareMode' | 'assetsDir' | 'image' + | 'site' >; type AstroContainerConstructor = { @@ -288,6 +291,7 @@ type AstroContainerConstructor = { renderers?: SSRLoadedRenderer[]; manifest?: AstroContainerManifest; resolve?: SSRResult['resolve']; + site?: string; }; export class experimental_AstroContainer { @@ -315,8 +319,9 @@ export class experimental_AstroContainer { manifest, renderers, resolve, + site, }: AstroContainerConstructor) { - const ssrManifest = createManifest(manifest, renderers); + const ssrManifest = createManifest(manifest, renderers, undefined, site); const containerRenderers = renderers ?? manifest?.renderers ?? []; const containerResolve = async (specifier: string): Promise => { if (this.#withManifest) { @@ -327,7 +332,6 @@ export class experimental_AstroContainer { return specifier; }; const interner = new WeakMap(); - // Composition order: logger → environment → warm the route table. setLogger(ssrManifest, createConsoleLogger({ level: 'error' })); setEnvironment( ssrManifest, @@ -338,10 +342,6 @@ export class experimental_AstroContainer { streaming, }), ); - // Warm the derived route table. Deliberately left un-refreshed when - // routes are inserted later — route matching is irrelevant here - // because `renderToResponse` always assigns `state.routeData` - // explicitly. getRouteTable(ssrManifest); this.#manifest = ssrManifest; this.#interner = interner; @@ -363,12 +363,13 @@ export class experimental_AstroContainer { public static async create( containerOptions: AstroContainerOptions = {}, ): Promise { - const { streaming = false, manifest, renderers = [], resolve } = containerOptions; + const { streaming = false, manifest, renderers = [], resolve, astroConfig } = containerOptions; return new experimental_AstroContainer({ streaming, manifest, renderers, resolve, + site: astroConfig?.site ?? manifest?.site, }); } diff --git a/packages/astro/test/units/render/container.test.ts b/packages/astro/test/units/render/container.test.ts index e95a9460b0bf..1ef41f3f3594 100644 --- a/packages/astro/test/units/render/container.test.ts +++ b/packages/astro/test/units/render/container.test.ts @@ -276,4 +276,38 @@ describe('Container', () => { assert.match(result, /Is open/); }); + + it('Astro.site reflects astroConfig.site', async () => { + const $Astro = createAstro('https://example.com'); + const SitePage = createComponent((result, props, slots) => { + const Astro = result.createAstro($Astro, props, slots); + const site = Astro.site; + return render`${maybeRenderHead()}
${site ? site.toString() : 'SITE_UNDEFINED'}
`; + }); + + const container = await experimental_AstroContainer.create({ + astroConfig: { + site: 'https://example.com', + }, + }); + + const response = await container.renderToString(SitePage); + + assert.match(response, /https:\/\/example\.com/); + assert.doesNotMatch(response, /SITE_UNDEFINED/); + }); + + it('Astro.site is undefined when astroConfig.site is not set', async () => { + const $Astro = createAstro(undefined); + const SitePage = createComponent((result, props, slots) => { + const Astro = result.createAstro($Astro, props, slots); + const site = Astro.site; + return render`${maybeRenderHead()}
${site ? site.toString() : 'SITE_UNDEFINED'}
`; + }); + + const container = await experimental_AstroContainer.create(); + const response = await container.renderToString(SitePage); + + assert.match(response, /SITE_UNDEFINED/); + }); });