diff --git a/.changeset/warm-gifts-jam.md b/.changeset/warm-gifts-jam.md new file mode 100644 index 000000000000..8c2ccd85c5a8 --- /dev/null +++ b/.changeset/warm-gifts-jam.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix some global state related to `astro:assets` not getting cleaned out properly in SSR with no pre-rendered pages diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 1f8d170a04b7..708295296399 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -130,7 +130,12 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn ? opts.settings.config.build.server : getOutDirWithinCwd(opts.settings.config.outDir); - if (ssr && !hasPrerenderedPages(internals)) return; + // HACK! `astro:assets` relies on a global to know if its running in dev, prod, ssr, ssg, full moon + // If we don't delete it here, it's technically not impossible (albeit improbable) for it to leak + if (ssr && !hasPrerenderedPages(internals)) { + delete globalThis?.astroAsset?.addStaticImage; + return; + } const verb = ssr ? 'prerendering' : 'generating'; info(opts.logging, null, `\n${bgGreen(black(` ${verb} static routes `))}`); @@ -186,7 +191,7 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn await generateImage(opts, imageData[1].options, imageData[1].path); } - delete globalThis.astroAsset.addStaticImage; + delete globalThis?.astroAsset?.addStaticImage; } await runHookBuildGenerated({ diff --git a/packages/astro/test/astro-assets-prefix.test.js b/packages/astro/test/astro-assets-prefix.test.js index 58eb11e39b6a..40562afd4788 100644 --- a/packages/astro/test/astro-assets-prefix.test.js +++ b/packages/astro/test/astro-assets-prefix.test.js @@ -132,14 +132,14 @@ describe('Assets Prefix - Server', () => { expect(island.attr('renderer-url')).to.match(assetsPrefixRegex); }); - it('markdown image src start with assetsPrefix', async () => { + it('markdown optimized image src does not start with assetsPrefix in SSR', async () => { const request = new Request('http://example.com/custom-base/markdown/'); const response = await app.render(request); expect(response.status).to.equal(200); const html = await response.text(); const $ = cheerio.load(html); const imgAsset = $('img'); - expect(imgAsset.attr('src')).to.match(assetsPrefixRegex); + expect(imgAsset.attr('src')).to.not.match(assetsPrefixRegex); }); }); diff --git a/packages/integrations/node/test/fixtures/image/package.json b/packages/integrations/node/test/fixtures/image/package.json new file mode 100644 index 000000000000..94066576deab --- /dev/null +++ b/packages/integrations/node/test/fixtures/image/package.json @@ -0,0 +1,13 @@ +{ + "name": "@test/nodejs-image", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*", + "@astrojs/node": "workspace:*" + }, + "scripts": { + "build": "astro build", + "preview": "astro preview" + } +} diff --git a/packages/integrations/node/test/fixtures/image/src/assets/some_penguin.png b/packages/integrations/node/test/fixtures/image/src/assets/some_penguin.png new file mode 100644 index 000000000000..fad1494c81c8 Binary files /dev/null and b/packages/integrations/node/test/fixtures/image/src/assets/some_penguin.png differ diff --git a/packages/integrations/node/test/fixtures/image/src/pages/index.astro b/packages/integrations/node/test/fixtures/image/src/pages/index.astro new file mode 100644 index 000000000000..474a2f0c950a --- /dev/null +++ b/packages/integrations/node/test/fixtures/image/src/pages/index.astro @@ -0,0 +1,6 @@ +--- +import { Image } from "astro:assets"; +import penguin from "../assets/some_penguin.png"; +--- + +Penguins diff --git a/packages/integrations/node/test/image.test.js b/packages/integrations/node/test/image.test.js new file mode 100644 index 000000000000..0834bc175fa4 --- /dev/null +++ b/packages/integrations/node/test/image.test.js @@ -0,0 +1,40 @@ +import { expect } from 'chai'; +import nodejs from '../dist/index.js'; +import { loadFixture } from './test-utils.js'; + +describe('Image endpoint', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let devPreview; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/image/', + output: 'server', + adapter: nodejs({ mode: 'standalone' }), + experimental: { + assets: true, + }, + }); + await fixture.build(); + devPreview = await fixture.preview(); + }); + + after(async () => { + await devPreview.stop(); + }); + + it('it returns images', async () => { + const res = await fixture.fetch('/'); + expect(res.status).to.equal(200); + + const resImage = await fixture.fetch( + '/_image?href=/_astro/some_penguin.97ef5f92.png&w=50&f=webp' + ); + + console.log(resImage); + const content = resImage.text(); + console.log(content); + expect(resImage.status).to.equal(200); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0657a76cb26b..85e7f3c03854 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4620,6 +4620,15 @@ importers: specifier: workspace:* version: link:../../../../../astro + packages/integrations/node/test/fixtures/image: + dependencies: + '@astrojs/node': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + packages/integrations/node/test/fixtures/locals: dependencies: '@astrojs/node':