diff --git a/.changeset/dirty-breads-wish.md b/.changeset/dirty-breads-wish.md new file mode 100644 index 000000000000..b89eb1520b7a --- /dev/null +++ b/.changeset/dirty-breads-wish.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes a regression where the the routes emitted by the `astro:build:done` hook didn't have the `distURL` array correctly populated. diff --git a/.changeset/fix-cloudflare-configpath.md b/.changeset/fix-cloudflare-configpath.md new file mode 100644 index 000000000000..932327d1d430 --- /dev/null +++ b/.changeset/fix-cloudflare-configpath.md @@ -0,0 +1,9 @@ +--- +'@astrojs/cloudflare': patch +--- + +fix(cloudflare): forward `configPath` and other `PluginConfig` options to the Cloudflare Vite Plugin + +Options like `configPath`, `inspectorPort`, `persistState`, `remoteBindings`, and `auxiliaryWorkers` were accepted by the type system but never forwarded to `cfVitePlugin()`, making them silently ignored. + +Also fixes `addWatchFile` for `configPath` which resolved the path relative to the adapter's `node_modules` directory instead of the project root. diff --git a/.changeset/tall-loops-take.md b/.changeset/tall-loops-take.md new file mode 100644 index 000000000000..1e377c54922e --- /dev/null +++ b/.changeset/tall-loops-take.md @@ -0,0 +1,5 @@ +--- +'@astrojs/cloudflare': patch +--- + +fix cloudflare image transform ignoring quality parameter diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 85921a553e00..7c300d76bd05 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -189,6 +189,24 @@ export async function generatePages( } } + // After generation, propagate distURL from the deserialized routes (used during generation) + // back to the original routes in allPages. The prerenderer operates on deserialized route + // objects (reconstructed from the serialized manifest), so distURL mutations during generation + // don't affect the original route objects that are later passed to the astro:build:done hook. + for (const { route: generatedRoute } of filteredPaths) { + if (generatedRoute.distURL && generatedRoute.distURL.length > 0) { + for (const pageData of Object.values(options.allPages)) { + if ( + pageData.route.route === generatedRoute.route && + pageData.route.component === generatedRoute.component + ) { + pageData.route.distURL = generatedRoute.distURL; + break; + } + } + } + } + const staticImageList = getStaticImageList(); // Must happen before teardown since collectStaticImages fetches from the prerender server diff --git a/packages/astro/test/static-build-page-dist-url.test.js b/packages/astro/test/static-build-page-dist-url.test.js index 671de39c56b2..4ebd9b5d327e 100644 --- a/packages/astro/test/static-build-page-dist-url.test.js +++ b/packages/astro/test/static-build-page-dist-url.test.js @@ -24,9 +24,14 @@ describe('Static build: pages routes have distURL', () => { }); it('Pages routes have distURL', async () => { assert.equal(assets.size > 0, true, 'Pages not found: build end hook not being called'); - for (const [p, distURL] of assets.entries()) { + for (const [route, distURL] of assets.entries()) { + assert.equal( + distURL.length > 0, + true, + `Route "${route}" has an empty distURL array — asset URLs were not propagated to astro:build:done`, + ); for (const url of distURL) { - assert.equal(url instanceof URL, true, `${p.pathname} doesn't include distURL`); + assert.equal(url instanceof URL, true, `Route "${route}" distURL entry is not a URL`); } } }); diff --git a/packages/integrations/cloudflare/src/index.ts b/packages/integrations/cloudflare/src/index.ts index 013db549d128..620239a10a52 100644 --- a/packages/integrations/cloudflare/src/index.ts +++ b/packages/integrations/cloudflare/src/index.ts @@ -21,7 +21,6 @@ import { import { parseEnv } from 'node:util'; import { sessionDrivers } from 'astro/config'; import { createCloudflarePrerenderer } from './prerenderer.js'; -import { createRequire } from 'node:module'; const CLOUDFLARE_KV_SESSION_DRIVER_ENTRYPOINT = sessionDrivers.cloudflareKVBinding().entrypoint; @@ -176,7 +175,11 @@ export default function createIntegration({ session, vite: { plugins: [ - cfVitePlugin({ ...cfPluginConfig, viteEnvironment: { name: 'ssr' } }), + cfVitePlugin({ + ...cloudflareOptions, + ...cfPluginConfig, + viteEnvironment: { name: 'ssr' }, + }), { name: '@astrojs/cloudflare:cf-imports', enforce: 'pre', @@ -278,7 +281,7 @@ export default function createIntegration({ }); if (cloudflareOptions.configPath) { - addWatchFile(createRequire(import.meta.url).resolve(cloudflareOptions.configPath)); + addWatchFile(new URL(cloudflareOptions.configPath, config.root)); } addWatchFile(new URL('./wrangler.toml', config.root)); diff --git a/packages/integrations/cloudflare/src/utils/image-binding-transform.ts b/packages/integrations/cloudflare/src/utils/image-binding-transform.ts index 84c383e300d0..d1d0c2db555e 100644 --- a/packages/integrations/cloudflare/src/utils/image-binding-transform.ts +++ b/packages/integrations/cloudflare/src/utils/image-binding-transform.ts @@ -2,6 +2,14 @@ import { imageConfig } from 'astro:assets'; import { isRemotePath } from '@astrojs/internal-helpers/path'; import { isRemoteAllowed } from '@astrojs/internal-helpers/remote'; import type { ImageOutputOptions, ImageTransform } from '@cloudflare/workers-types'; +import type { ImageQualityPreset } from 'astro'; + +const qualityTable: Record = { + low: 25, + mid: 50, + high: 80, + max: 100, +}; export async function transform( rawUrl: string, @@ -43,10 +51,14 @@ export async function transform( .transform({ width: url.searchParams.has('w') ? Number.parseInt(url.searchParams.get('w')!) : undefined, height: url.searchParams.has('h') ? Number.parseInt(url.searchParams.get('h')!) : undefined, - // `quality` is documented, but doesn't appear to work in manual testing... - // quality: url.searchParams.get('q'), fit: url.searchParams.get('fit') as ImageTransform['fit'], }) - .output({ format: outputFormat }) + .output({ + quality: url.searchParams.get('q') + ? (qualityTable[url.searchParams.get('q') as ImageQualityPreset] ?? + Number.parseInt(url.searchParams.get('q')!)) + : undefined, + format: outputFormat, + }) ).response(); }