diff --git a/.changeset/early-times-drop.md b/.changeset/early-times-drop.md new file mode 100644 index 000000000000..59fdc8cb8bd9 --- /dev/null +++ b/.changeset/early-times-drop.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': patch +--- + +Fixes duplicate logging showing up in some cases when prerendering pages diff --git a/.changeset/long-bushes-rest.md b/.changeset/long-bushes-rest.md new file mode 100644 index 000000000000..9107682aeb6b --- /dev/null +++ b/.changeset/long-bushes-rest.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes images not working in MDX when using the Cloudflare adapter in certain cases diff --git a/packages/astro/src/assets/utils/proxy.ts b/packages/astro/src/assets/utils/proxy.ts index 975e8e0f36c6..05325b5d4986 100644 --- a/packages/astro/src/assets/utils/proxy.ts +++ b/packages/astro/src/assets/utils/proxy.ts @@ -13,7 +13,7 @@ export function getProxyCode(options: ImageMetadata, isSSR: boolean): string { } ${ !isSSR - ? `if (target[name] !== undefined && globalThis.astroAsset) globalThis.astroAsset?.referencedImages.add(${stringifiedFSPath});` + ? `if (target[name] !== undefined && globalThis.astroAsset) globalThis.astroAsset?.referencedImages?.add(${stringifiedFSPath});` : '' } return target[name]; diff --git a/packages/astro/src/content/vite-plugin-content-assets.ts b/packages/astro/src/content/vite-plugin-content-assets.ts index b6c1689043d7..71bbe7a7f25d 100644 --- a/packages/astro/src/content/vite-plugin-content-assets.ts +++ b/packages/astro/src/content/vite-plugin-content-assets.ts @@ -78,10 +78,19 @@ export function astroContentAssetPropagationPlugin({ }, }, configureServer(server) { - if (!isRunnableDevEnvironment(server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr])) { - return; + const ssrEnv = server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr]; + if (isRunnableDevEnvironment(ssrEnv)) { + environment = ssrEnv; + } else if ( + isRunnableDevEnvironment(server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.astro]) + ) { + // When the ssr environment is not a RunnableDevEnvironment (e.g. when using the + // Cloudflare adapter which runs ssr in workerd), fall back to the 'astro' environment + // which is always a RunnableDevEnvironment available in dev. + environment = server.environments[ + ASTRO_VITE_ENVIRONMENT_NAMES.astro + ] as RunnableDevEnvironment; } - environment = server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr] as RunnableDevEnvironment; }, transform: { filter: { @@ -96,7 +105,11 @@ export function astroContentAssetPropagationPlugin({ // so resolve collected styles and scripts here. if (isAstroServerEnvironment(this.environment) && environment) { if (!environment.moduleGraph.getModuleById(basePath)?.ssrModule) { - await environment.runner.import(basePath); + // Ignore errors here — when using a fallback environment (e.g. the 'astro' + // env when Cloudflare's ssr env is non-runnable), the module may already be + // loaded in the fallback env's graph even if this import throws due to + // concurrent bundle editing. + await environment.runner.import(basePath).catch(() => {}); } const { styles, diff --git a/packages/integrations/cloudflare/src/prerenderer.ts b/packages/integrations/cloudflare/src/prerenderer.ts index 7bac45c085c7..8a3554ea695e 100644 --- a/packages/integrations/cloudflare/src/prerenderer.ts +++ b/packages/integrations/cloudflare/src/prerenderer.ts @@ -61,6 +61,7 @@ export function createCloudflarePrerenderer({ outDir: fileURLToPath(serverDir), }, root: fileURLToPath(root), + logLevel: 'error', preview: { host: 'localhost', port: 0, // Let the OS pick a free port diff --git a/packages/integrations/cloudflare/test/fixtures/prerender-styles/astro.config.mjs b/packages/integrations/cloudflare/test/fixtures/prerender-styles/astro.config.mjs index 2b45c7068f52..a5924b350fd7 100644 --- a/packages/integrations/cloudflare/test/fixtures/prerender-styles/astro.config.mjs +++ b/packages/integrations/cloudflare/test/fixtures/prerender-styles/astro.config.mjs @@ -1,7 +1,9 @@ +import mdx from '@astrojs/mdx'; import { defineConfig } from 'astro/config'; import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ + integrations: [mdx()], vite: { plugins: [tailwindcss()], }, diff --git a/packages/integrations/cloudflare/test/fixtures/prerender-styles/package.json b/packages/integrations/cloudflare/test/fixtures/prerender-styles/package.json index f2fa6954030c..a2a6ea674f7b 100644 --- a/packages/integrations/cloudflare/test/fixtures/prerender-styles/package.json +++ b/packages/integrations/cloudflare/test/fixtures/prerender-styles/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@astrojs/cloudflare": "workspace:*", + "@astrojs/mdx": "workspace:*", "@tailwindcss/vite": "^4.2.0", "astro": "workspace:*", "tailwindcss": "^4.2.0" diff --git a/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/components/StyledCard.astro b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/components/StyledCard.astro new file mode 100644 index 000000000000..f97e50b6608f --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/components/StyledCard.astro @@ -0,0 +1,13 @@ +--- +--- + +
+ +
+ + diff --git a/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/content.config.ts b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/content.config.ts new file mode 100644 index 000000000000..ba89389c8032 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/content.config.ts @@ -0,0 +1,11 @@ +import { defineCollection, z } from 'astro:content'; +import { glob } from 'astro/loaders'; + +const posts = defineCollection({ + loader: glob({ pattern: '**/*.mdx', base: './src/content/posts' }), + schema: z.object({ + title: z.string(), + }), +}); + +export const collections = { posts }; diff --git a/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/content/posts/styled.mdx b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/content/posts/styled.mdx new file mode 100644 index 000000000000..473eedc04d40 --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/content/posts/styled.mdx @@ -0,0 +1,7 @@ +--- +title: Styled Post +--- + +import StyledCard from '../../components/StyledCard.astro'; + +Hello from MDX diff --git a/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/pages/posts/[slug].astro b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/pages/posts/[slug].astro new file mode 100644 index 000000000000..8fe535e1928c --- /dev/null +++ b/packages/integrations/cloudflare/test/fixtures/prerender-styles/src/pages/posts/[slug].astro @@ -0,0 +1,27 @@ +--- +import { getEntry, render } from 'astro:content'; + +export const prerender = true; + +export async function getStaticPaths() { + const { getCollection } = await import('astro:content'); + const posts = await getCollection('posts'); + return posts.map((post) => ({ + params: { slug: post.id }, + props: { post }, + })); +} + +const { post } = Astro.props; +const { Content } = await render(post); +--- + + + + + {post.data.title} + + + + + diff --git a/packages/integrations/cloudflare/test/prerender-styles.test.js b/packages/integrations/cloudflare/test/prerender-styles.test.js index 73892a62f282..77df3fb8b270 100644 --- a/packages/integrations/cloudflare/test/prerender-styles.test.js +++ b/packages/integrations/cloudflare/test/prerender-styles.test.js @@ -43,8 +43,69 @@ describe('Prerendered page styles', () => { it('includes Tailwind styles in prerendered page', async () => { // With cloudflare adapter, prerendered pages are in dist/client/ const html = await fixture.readFile('/client/index.html'); - // Check that the bg-amber-500 class has its styles included - assert.ok(html.includes('.bg-amber-500'), 'Expected .bg-amber-500 class to be in the HTML'); + // Tailwind CSS is emitted as an external stylesheet linked from the HTML. + // Verify the HTML references a stylesheet and that the stylesheet contains the expected class. + assert.ok(html.includes('rel="stylesheet"'), 'Expected the HTML to reference a stylesheet'); + const cssFiles = await fixture.glob('client/_astro/*.css'); + assert.ok(cssFiles.length > 0, 'Expected at least one CSS file in _astro/'); + let foundClass = false; + for (const cssFile of cssFiles) { + const css = await fixture.readFile('/' + cssFile); + if (css.includes('.bg-amber-500')) { + foundClass = true; + break; + } + } + assert.ok(foundClass, 'Expected .bg-amber-500 class to be in a generated CSS file'); + }); + }); +}); + +describe('Styles from Astro components imported in MDX content collections', () => { + /** @type {import('../../../astro/test/test-utils').Fixture} */ + let fixture; + let devServer; + + before(async () => { + fixture = await loadFixture({ + root: new URL('./fixtures/prerender-styles/', import.meta.url).toString(), + adapter: cloudflare(), + }); + }); + + after(async () => { + await devServer?.stop(); + await fixture.clean(); + }); + + describe('dev', () => { + before(async () => { + devServer = await fixture.startDevServer(); + }); + + it('includes styles from an Astro component imported in an MDX content collection entry', async () => { + const res = await fixture.fetch('/posts/styled'); + const html = await res.text(); + assert.ok( + html.includes('.mdx-styled-card'), + 'Expected .mdx-styled-card styles from StyledCard.astro to be injected in the MDX page', + ); + }); + }); + + describe('build', () => { + before(async () => { + await devServer?.stop(); + devServer = undefined; + await fixture.build(); + }); + + it('includes styles from an Astro component imported in an MDX content collection entry', async () => { + const html = await fixture.readFile('/client/posts/styled/index.html'); + assert.ok( + html.includes('.mdx-styled-card'), + 'Expected .mdx-styled-card styles from StyledCard.astro to be in the built MDX page', + ); }); }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2d2ca0808e5..db432a3a971d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4988,6 +4988,9 @@ importers: '@astrojs/cloudflare': specifier: workspace:* version: link:../../.. + '@astrojs/mdx': + specifier: workspace:* + version: link:../../../../mdx '@tailwindcss/vite': specifier: ^4.2.0 version: 4.2.0(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))