Skip to content

Commit f9bae95

Browse files
authored
fix(cloudflare): resolve vite plugin config once across call sites (#16868)
* fix(cloudflare): resolve vite plugin config once across call sites User options like remoteBindings, inspectorPort, persistState, configPath, and auxiliaryWorkers were silently dropped during astro preview because the preview entrypoint only received the adapter-computed half of the config. Resolve the full @cloudflare/vite-plugin config once at integration setup time so every call site (dev/build, prerenderer, preview) spreads a single merged object and cannot accidentally drop user options. * test(cloudflare): add regression test for remoteBindings during astro preview Verifies that astro preview honors remoteBindings: false when a wrangler binding is flagged remote: true. Confirmed to fail before the fix in b4946e2 — wrangler.maybeStartOrUpdateRemoteProxySession throws from the @cloudflare/vite-plugin preview path because the option is dropped. * chore: cleanup comments
1 parent b27d967 commit f9bae95

9 files changed

Lines changed: 78 additions & 22 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@astrojs/cloudflare': patch
3+
---
4+
5+
Fixes user options passed to `cloudflare({...})` (`remoteBindings`, `inspectorPort`, `persistState`, `configPath`, `auxiliaryWorkers`) being silently ignored during `astro preview`. The adapter now resolves the full `@cloudflare/vite-plugin` config once at integration setup time and reuses that single resolved value across the dev/build plugin, the prerenderer's preview server, and the `astro preview` entrypoint, so user options can no longer be dropped at one of the call sites.

packages/integrations/cloudflare/src/entrypoints/preview.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const createPreviewServer: CreatePreviewServer = async ({
4949
allowedHosts,
5050
},
5151
plugins: [
52-
cfVitePlugin({ ...globalThis.astroCloudflareOptions, viteEnvironment: { name: 'ssr' } }),
52+
cfVitePlugin({ ...globalThis.astroCloudflareConfig, viteEnvironment: { name: 'ssr' } }),
5353
],
5454
});
5555
} catch (err) {

packages/integrations/cloudflare/src/index.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export default function createIntegration({
175175
const usesContentCollections = hasContentCollectionsConfig(config.srcDir);
176176
const prebundleContentRuntime = command === 'dev' && usesContentCollections;
177177

178-
cfPluginConfig = {
178+
const adapterPluginConfig: Partial<PluginConfig> = {
179179
config: cloudflareConfigCustomizer({
180180
needsSessionKVBinding,
181181
sessionKVBindingName,
@@ -203,11 +203,21 @@ export default function createIntegration({
203203
},
204204
}),
205205
};
206-
207-
// The preview entrypoint uses Cloudflare's vite plugin and so it needs access
208-
// to the config. But there's no proper API for this so we use globalThis.
206+
// Resolve the full `@cloudflare/vite-plugin` config exactly once by merging
207+
// the user's `cloudflare({...})` options (e.g. `remoteBindings`,
208+
// `inspectorPort`, `persistState`, `configPath`, `auxiliaryWorkers`) with
209+
// the adapter's computed bindings/wrangler wiring. Downstream call sites
210+
// (the dev/build plugin instance, the prerenderer's preview server, and
211+
// the `astro preview` entrypoint) then just spread `cfPluginConfig` and
212+
// cannot accidentally drop user options (see #16705 and related CHANGELOG
213+
// entries).
214+
cfPluginConfig = { ...cloudflareOptions, ...adapterPluginConfig };
215+
216+
// The preview entrypoint uses Cloudflare's vite plugin and so it needs
217+
// access to the resolved config. There's no proper API for this so we
218+
// use globalThis.
209219
if (command === 'preview') {
210-
globalThis.astroCloudflareOptions = cfPluginConfig;
220+
globalThis.astroCloudflareConfig = cfPluginConfig;
211221
}
212222

213223
// Including prismjs files in `optimizeDeps.includes` when `@astrojs/prism` is not installed
@@ -241,11 +251,7 @@ export default function createIntegration({
241251
...(prerenderEnvironment === 'node' && command === 'dev'
242252
? [createNodePrerenderPlugin()]
243253
: []),
244-
cfVitePlugin({
245-
...cloudflareOptions,
246-
...cfPluginConfig,
247-
viteEnvironment: { name: 'ssr' },
248-
}),
254+
cfVitePlugin({ ...cfPluginConfig, viteEnvironment: { name: 'ssr' } }),
249255
{
250256
name: '@astrojs/cloudflare:cf-imports',
251257
enforce: 'pre',
@@ -447,7 +453,6 @@ export default function createIntegration({
447453
if (prerenderEnvironment === 'workerd') {
448454
setPrerenderer(
449455
createCloudflarePrerenderer({
450-
cloudflareOptions,
451456
root: _config.root,
452457
serverDir: _config.build.server,
453458
clientDir: _config.build.client,

packages/integrations/cloudflare/src/prerenderer.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
} from './utils/prerender-constants.js';
2222

2323
interface CloudflarePrerendererOptions {
24-
cloudflareOptions: Partial<PluginConfig>;
2524
root: AstroConfig['root'];
2625
serverDir: AstroConfig['build']['server'];
2726
clientDir: AstroConfig['build']['client'];
@@ -36,7 +35,6 @@ interface CloudflarePrerendererOptions {
3635
* This allows prerendering to happen in the same runtime that will serve the pages.
3736
*/
3837
export function createCloudflarePrerenderer({
39-
cloudflareOptions,
4038
root,
4139
serverDir,
4240
clientDir,
@@ -84,13 +82,7 @@ export function createCloudflarePrerenderer({
8482
port: 0, // Let the OS pick a free port
8583
open: false,
8684
},
87-
plugins: [
88-
cfVitePlugin({
89-
...cloudflareOptions,
90-
...cfPluginConfig,
91-
viteEnvironment: { name: 'prerender' },
92-
}),
93-
],
85+
plugins: [cfVitePlugin({ ...cfPluginConfig, viteEnvironment: { name: 'prerender' } })],
9486
});
9587

9688
const address = previewServer.httpServer.address();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// @ts-check
2+
import { defineConfig } from 'astro/config';
3+
import cloudflare from '@astrojs/cloudflare';
4+
5+
export default defineConfig({
6+
output: 'server',
7+
adapter: cloudflare({
8+
remoteBindings: false,
9+
}),
10+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
---
3+
<h1>preview ok</h1>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "test-preview-remote-bindings",
3+
"compatibility_date": "2026-01-28",
4+
"assets": {
5+
"directory": "./dist",
6+
"binding": "ASSETS"
7+
},
8+
"kv_namespaces": [
9+
{
10+
"binding": "REMOTE_KV",
11+
"id": "abcdef0123456789abcdef0123456789",
12+
"remote": true
13+
}
14+
]
15+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import assert from 'node:assert/strict';
2+
import { after, before, describe, it } from 'node:test';
3+
import { type Fixture, loadFixture, type PreviewServer } from './test-utils.ts';
4+
5+
describe('astro preview with remoteBindings: false', () => {
6+
let fixture: Fixture;
7+
let previewServer: PreviewServer | undefined;
8+
9+
before(async () => {
10+
fixture = await loadFixture({
11+
root: './fixtures/preview-remote-bindings/',
12+
});
13+
await fixture.build();
14+
});
15+
16+
after(async () => {
17+
await previewServer?.stop();
18+
});
19+
20+
// assumption: will reject in CI since since remote proxy session is expected unavailable in CI
21+
it('starts the preview server without attempting a remote proxy session', async () => {
22+
await assert.doesNotReject(async () => {
23+
previewServer = await fixture.preview();
24+
}, 'preview server should start without requiring Cloudflare credentials');
25+
});
26+
});

packages/integrations/cloudflare/virtual.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ interface Env extends Cloudflare.Env {}
2020
type ImagesBinding = import('@cloudflare/workers-types').ImagesBinding;
2121
type Fetcher = import('@cloudflare/workers-types').Fetcher;
2222

23-
declare var astroCloudflareOptions: import('@cloudflare/vite-plugin').PluginConfig;
23+
declare var astroCloudflareConfig: import('@cloudflare/vite-plugin').PluginConfig;

0 commit comments

Comments
 (0)