@astrojs/cloudflare 13.0.0-beta.1 → 13.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/entrypoints/{image-service.js → image-service-external.js} +2 -2
  2. package/dist/entrypoints/image-service-workerd.d.ts +14 -0
  3. package/dist/entrypoints/image-service-workerd.js +11 -0
  4. package/dist/entrypoints/image-transform-endpoint.js +21 -2
  5. package/dist/entrypoints/preview.js +4 -7
  6. package/dist/esbuild-plugin-astro-frontmatter.d.ts +9 -0
  7. package/dist/esbuild-plugin-astro-frontmatter.js +30 -0
  8. package/dist/index.d.ts +7 -57
  9. package/dist/index.js +108 -81
  10. package/dist/info.d.ts +5 -0
  11. package/dist/info.js +4 -0
  12. package/dist/prerender-types.d.ts +32 -0
  13. package/dist/prerender-types.js +0 -0
  14. package/dist/prerenderer.d.ts +17 -0
  15. package/dist/prerenderer.js +116 -0
  16. package/dist/utils/generate-routes-json.d.ts +1 -8
  17. package/dist/utils/generate-routes-json.js +0 -203
  18. package/dist/utils/handler.d.ts +3 -8
  19. package/dist/utils/handler.js +40 -18
  20. package/dist/utils/image-binding-transform.d.ts +1 -2
  21. package/dist/utils/image-binding-transform.js +14 -6
  22. package/dist/utils/image-config.d.ts +19 -6
  23. package/dist/utils/image-config.js +30 -8
  24. package/dist/utils/prerender-constants.d.ts +9 -0
  25. package/dist/utils/prerender-constants.js +8 -0
  26. package/dist/utils/prerender.d.ts +37 -0
  27. package/dist/utils/prerender.js +76 -0
  28. package/dist/utils/static-image-collection.d.ts +7 -0
  29. package/dist/utils/static-image-collection.js +51 -0
  30. package/dist/vite-plugin-config.d.ts +10 -3
  31. package/dist/vite-plugin-config.js +5 -2
  32. package/dist/wrangler.d.ts +3 -3
  33. package/package.json +17 -17
  34. package/types.d.ts +3 -18
  35. package/dist/entrypoints/image-endpoint.d.ts +0 -3
  36. package/dist/entrypoints/image-endpoint.js +0 -29
  37. package/dist/utils/cloudflare-module-loader.d.ts +0 -16
  38. package/dist/utils/cloudflare-module-loader.js +0 -152
  39. /package/dist/entrypoints/{image-service.d.ts → image-service-external.d.ts} +0 -0
@@ -28,7 +28,7 @@ const service = {
28
28
  return imageEndpoint;
29
29
  }
30
30
  };
31
- var image_service_default = service;
31
+ var image_service_external_default = service;
32
32
  export {
33
- image_service_default as default
33
+ image_service_external_default as default
34
34
  };
@@ -0,0 +1,14 @@
1
+ import type { LocalImageService } from 'astro';
2
+ /**
3
+ * Workerd-compatible image service stub.
4
+ *
5
+ * Handles getURL/getHTMLAttributes/addStaticImage in the workerd prerender
6
+ * environment without importing Sharp. Actual image transforms are handled
7
+ * elsewhere:
8
+ * - `compile`: Sharp runs on the Node side via the generation pipeline
9
+ * - `cloudflare-binding`: image-transform-endpoint uses the IMAGES binding directly
10
+ *
11
+ * transform() is a passthrough so the generic endpoint can call it in dev.
12
+ */
13
+ declare const service: LocalImageService;
14
+ export default service;
@@ -0,0 +1,11 @@
1
+ import { baseService } from "astro/assets";
2
+ const service = {
3
+ ...baseService,
4
+ async transform(inputBuffer, transform) {
5
+ return { data: inputBuffer, format: transform.format };
6
+ }
7
+ };
8
+ var image_service_workerd_default = service;
9
+ export {
10
+ image_service_workerd_default as default
11
+ };
@@ -1,8 +1,27 @@
1
+ import { env } from "cloudflare:workers";
1
2
  import { transform } from "../utils/image-binding-transform.js";
2
3
  const prerender = false;
3
4
  const GET = async (ctx) => {
4
- const { env } = await import("cloudflare:workers");
5
- return transform(ctx.request.url, env.IMAGES, env.ASSETS);
5
+ const cache = caches.default;
6
+ if (cache) {
7
+ const cached = await cache.match(ctx.request.url);
8
+ if (cached) return cached;
9
+ }
10
+ const response = await transform(ctx.request.url, env.IMAGES, env.ASSETS);
11
+ if (!response.ok) return response;
12
+ const headers = new Headers(response.headers);
13
+ headers.set("Cache-Control", "public, max-age=31536000, immutable");
14
+ const cachedResponse = new Response(response.body, {
15
+ status: response.status,
16
+ headers
17
+ });
18
+ if (cache) {
19
+ const cfContext = ctx.locals.cfContext;
20
+ if (cfContext) {
21
+ cfContext.waitUntil(cache.put(ctx.request.url, cachedResponse.clone()));
22
+ }
23
+ }
24
+ return cachedResponse;
6
25
  };
7
26
  export {
8
27
  GET,
@@ -5,7 +5,6 @@ import { fileURLToPath } from "node:url";
5
5
  import { cloudflare as cfVitePlugin } from "@cloudflare/vite-plugin";
6
6
  import colors from "piccolore";
7
7
  import { performance } from "node:perf_hooks";
8
- import { cloudflareConfigCustomizer } from "../wrangler.js";
9
8
  const createPreviewServer = async ({
10
9
  logger,
11
10
  base,
@@ -17,10 +16,6 @@ const createPreviewServer = async ({
17
16
  }) => {
18
17
  const startServerTime = performance.now();
19
18
  let previewServer;
20
- const cfPluginConfig = {
21
- viteEnvironment: { name: "ssr" },
22
- config: cloudflareConfigCustomizer()
23
- };
24
19
  try {
25
20
  previewServer = await preview({
26
21
  configFile: false,
@@ -37,7 +32,9 @@ const createPreviewServer = async ({
37
32
  open: false,
38
33
  allowedHosts: []
39
34
  },
40
- plugins: [cfVitePlugin(cfPluginConfig)]
35
+ plugins: [
36
+ cfVitePlugin({ ...globalThis.astroCloudflareOptions, viteEnvironment: { name: "ssr" } })
37
+ ]
41
38
  });
42
39
  } catch (err) {
43
40
  if (err instanceof Error) {
@@ -83,7 +80,7 @@ function serverStart({
83
80
  host,
84
81
  base
85
82
  }) {
86
- const version = "13.0.0-beta.1";
83
+ const version = "13.0.0-beta.11";
87
84
  const localPrefix = `${colors.dim("\u2503")} Local `;
88
85
  const networkPrefix = `${colors.dim("\u2503")} Network `;
89
86
  const emptyPrefix = " ".repeat(11);
@@ -0,0 +1,9 @@
1
+ import type { DepOptimizationConfig } from 'vite';
2
+ type ESBuildPlugin = NonNullable<NonNullable<DepOptimizationConfig['esbuildOptions']>['plugins']>[0];
3
+ /**
4
+ * An esbuild plugin that extracts frontmatter from .astro files during
5
+ * dependency optimization scanning. This allows Vite to discover imports
6
+ * in the server-side frontmatter code.
7
+ */
8
+ export declare function astroFrontmatterScanPlugin(): ESBuildPlugin;
9
+ export {};
@@ -0,0 +1,30 @@
1
+ import { readFile } from "node:fs/promises";
2
+ const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
3
+ function astroFrontmatterScanPlugin() {
4
+ return {
5
+ name: "astro-frontmatter-scan",
6
+ setup(build) {
7
+ build.onLoad({ filter: /\.astro$/ }, async (args) => {
8
+ try {
9
+ const code = await readFile(args.path, "utf-8");
10
+ const frontmatterMatch = FRONTMATTER_RE.exec(code);
11
+ if (frontmatterMatch) {
12
+ const contents = frontmatterMatch[1].replace(/\breturn\b/g, "throw ");
13
+ return {
14
+ contents,
15
+ loader: "ts"
16
+ };
17
+ }
18
+ } catch {
19
+ }
20
+ return {
21
+ contents: "",
22
+ loader: "ts"
23
+ };
24
+ });
25
+ }
26
+ };
27
+ }
28
+ export {
29
+ astroFrontmatterScanPlugin
30
+ };
package/dist/index.d.ts CHANGED
@@ -1,41 +1,10 @@
1
+ import { type PluginConfig } from '@cloudflare/vite-plugin';
1
2
  import type { AstroIntegration } from 'astro';
2
- import { type ImageService } from './utils/image-config.js';
3
+ import { type ImageServiceConfig } from './utils/image-config.js';
3
4
  export type { Runtime } from './utils/handler.js';
4
- export type Options = {
5
+ export interface Options extends Pick<PluginConfig, 'auxiliaryWorkers' | 'configPath' | 'inspectorPort' | 'persistState' | 'remoteBindings'> {
5
6
  /** Options for handling images. */
6
- imageService?: ImageService;
7
- /** Configuration for `_routes.json` generation. A _routes.json file controls when your Function is invoked. This file will include three different properties:
8
- *
9
- * - version: Defines the version of the schema. Currently there is only one version of the schema (version 1), however, we may add more in the future and aim to be backwards compatible.
10
- * - include: Defines routes that will be invoked by Functions. Accepts wildcard behavior.
11
- * - exclude: Defines routes that will not be invoked by Functions. Accepts wildcard behavior. `exclude` always take priority over `include`.
12
- *
13
- * Wildcards match any number of path segments (slashes). For example, `/users/*` will match everything after the `/users/` path.
14
- *
15
- */
16
- routes?: {
17
- /** Extend `_routes.json` */
18
- extend: {
19
- /** Paths which should be routed to the SSR function */
20
- include?: {
21
- /** Generally this is in pathname format, but does support wildcards, e.g. `/users`, `/products/*` */
22
- pattern: string;
23
- }[];
24
- /** Paths which should be routed as static assets */
25
- exclude?: {
26
- /** Generally this is in pathname format, but does support wildcards, e.g. `/static`, `/assets/*`, `/images/avatar.jpg` */
27
- pattern: string;
28
- }[];
29
- };
30
- };
31
- /**
32
- * Allow bundling cloudflare worker specific file types as importable modules. Defaults to true.
33
- * When enabled, allows imports of '.wasm', '.bin', and '.txt' file types
34
- *
35
- * See https://developers.cloudflare.com/pages/functions/module-support/
36
- * for reference on how these file types are exported
37
- */
38
- cloudflareModules?: boolean;
7
+ imageService?: ImageServiceConfig;
39
8
  /**
40
9
  * By default, Astro will be configured to use Cloudflare KV to store session data. The KV namespace
41
10
  * will be automatically provisioned when you deploy.
@@ -56,25 +25,6 @@ export type Options = {
56
25
  * See https://developers.cloudflare.com/images/transform-images/bindings/ for more details.
57
26
  */
58
27
  imagesBindingName?: string;
59
- /**
60
- * This configuration option allows you to specify a custom entryPoint for your Cloudflare Worker.
61
- * The entry point is the file that will be executed when your Worker is invoked.
62
- * By default, this is set to `@astrojs/cloudflare/entrypoints/server.js` and `['default']`.
63
- * @docs https://docs.astro.build/en/guides/integrations-guide/cloudflare/#workerEntryPoint
64
- */
65
- workerEntryPoint?: {
66
- /**
67
- * The path to the entry file. This should be a relative path from the root of your Astro project.
68
- * @example`'src/worker.ts'`
69
- * @docs https://docs.astro.build/en/guides/integrations-guide/cloudflare/#workerentrypointpath
70
- */
71
- path: string | URL;
72
- /**
73
- * Additional named exports to use for the entry file. Astro always includes the default export (`['default']`). If you need to have other top level named exports use this option.
74
- * @example ['MyDurableObject', 'namedExport']
75
- * @docs https://docs.astro.build/en/guides/integrations-guide/cloudflare/#workerentrypointnamedexports
76
- */
77
- namedExports?: string[];
78
- };
79
- };
80
- export default function createIntegration(args?: Options): AstroIntegration;
28
+ experimental?: Pick<NonNullable<PluginConfig['experimental']>, 'headersAndRedirectsDevModeSupport'>;
29
+ }
30
+ export default function createIntegration({ imageService, sessionKVBindingName, imagesBindingName, ...cloudflareOptions }?: Options): AstroIntegration;
package/dist/index.js CHANGED
@@ -1,40 +1,54 @@
1
1
  import { createReadStream, existsSync, readFileSync } from "node:fs";
2
- import { appendFile, stat } from "node:fs/promises";
3
- import { createRequire } from "node:module";
2
+ import { appendFile, rm, stat } from "node:fs/promises";
4
3
  import { createInterface } from "node:readline/promises";
5
- import { pathToFileURL } from "node:url";
6
4
  import { removeLeadingForwardSlash } from "@astrojs/internal-helpers/path";
7
5
  import { createRedirectsFromAstroRoutes, printAsRedirects } from "@astrojs/underscore-redirects";
8
6
  import { cloudflare as cfVitePlugin } from "@cloudflare/vite-plugin";
9
- import { cloudflareModuleLoader } from "./utils/cloudflare-module-loader.js";
10
- import { createRoutesFile, getParts } from "./utils/generate-routes-json.js";
11
- import { setImageConfig } from "./utils/image-config.js";
7
+ import { astroFrontmatterScanPlugin } from "./esbuild-plugin-astro-frontmatter.js";
8
+ import { getParts } from "./utils/generate-routes-json.js";
9
+ import {
10
+ normalizeImageServiceConfig,
11
+ setImageConfig
12
+ } from "./utils/image-config.js";
12
13
  import { createConfigPlugin } from "./vite-plugin-config.js";
13
14
  import {
14
15
  cloudflareConfigCustomizer,
15
16
  DEFAULT_SESSION_KV_BINDING_NAME,
16
17
  DEFAULT_IMAGES_BINDING_NAME
17
18
  } from "./wrangler.js";
18
- import { parse } from "dotenv";
19
+ import { parseEnv } from "node:util";
19
20
  import { sessionDrivers } from "astro/config";
20
- function createIntegration(args) {
21
+ import { createCloudflarePrerenderer } from "./prerenderer.js";
22
+ import { createRequire } from "node:module";
23
+ function createIntegration({
24
+ imageService,
25
+ sessionKVBindingName = DEFAULT_SESSION_KV_BINDING_NAME,
26
+ imagesBindingName = DEFAULT_IMAGES_BINDING_NAME,
27
+ ...cloudflareOptions
28
+ } = {}) {
21
29
  let _config;
22
- let finalBuildOutput;
23
- const cloudflareModulePlugin = cloudflareModuleLoader(
24
- args?.cloudflareModules ?? true
25
- );
26
30
  let _routes;
27
- const sessionKVBindingName = args?.sessionKVBindingName ?? DEFAULT_SESSION_KV_BINDING_NAME;
28
- const imagesBindingName = args?.imagesBindingName ?? DEFAULT_IMAGES_BINDING_NAME;
31
+ let _isFullyStatic = false;
32
+ let cfPluginConfig;
33
+ const { buildService, runtimeService } = normalizeImageServiceConfig(imageService);
34
+ const needsImagesBinding = runtimeService === "cloudflare-binding";
29
35
  return {
30
36
  name: "@astrojs/cloudflare",
31
37
  hooks: {
32
38
  "astro:config:setup": ({ command, config, updateConfig, logger, addWatchFile }) => {
39
+ if (!!process.versions.webcontainer) {
40
+ throw new Error("`workerd` does not run on Stackblitz.");
41
+ }
33
42
  let session = config.session;
34
- if (args?.imageService === "cloudflare-binding") {
43
+ const isCompile = buildService === "compile";
44
+ if (needsImagesBinding) {
35
45
  logger.info(
36
46
  `Enabling image processing with Cloudflare Images for production with the "${imagesBindingName}" Images binding.`
37
47
  );
48
+ } else if (isCompile) {
49
+ logger.info(
50
+ `Enabling compile-time image optimization. Images will be pre-optimized at build time.`
51
+ );
38
52
  }
39
53
  if (!session?.driver) {
40
54
  logger.info(
@@ -48,27 +62,37 @@ function createIntegration(args) {
48
62
  ttl: session?.ttl
49
63
  };
50
64
  }
51
- const cfPluginConfig = {
52
- viteEnvironment: { name: "ssr" },
65
+ const needsImagesBindingForDev = isCompile && command === "dev";
66
+ cfPluginConfig = {
53
67
  config: cloudflareConfigCustomizer({
54
- sessionKVBindingName: args?.sessionKVBindingName,
55
- imagesBindingName: args?.imageService === "cloudflare-binding" ? args?.imagesBindingName : false
56
- })
68
+ sessionKVBindingName,
69
+ imagesBindingName: needsImagesBinding || needsImagesBindingForDev ? imagesBindingName : false
70
+ }),
71
+ experimental: {
72
+ prerenderWorker: {
73
+ config(_, { entryWorkerConfig }) {
74
+ return {
75
+ ...entryWorkerConfig,
76
+ name: "prerender",
77
+ ...needsImagesBinding && !entryWorkerConfig.images && {
78
+ images: { binding: imagesBindingName }
79
+ }
80
+ };
81
+ }
82
+ }
83
+ }
57
84
  };
85
+ if (command === "preview") {
86
+ globalThis.astroCloudflareOptions = cfPluginConfig;
87
+ }
58
88
  updateConfig({
59
89
  build: {
60
- client: new URL(`./client/`, config.outDir),
61
- server: new URL("./_worker.js/", config.outDir),
62
- serverEntry: config.build.serverEntry ?? "index.js",
63
90
  redirects: false
64
91
  },
65
92
  session,
66
93
  vite: {
67
94
  plugins: [
68
- cfVitePlugin(cfPluginConfig),
69
- // https://developers.cloudflare.com/pages/functions/module-support/
70
- // Allows imports of '.wasm', '.bin', and '.txt' file types
71
- cloudflareModulePlugin,
95
+ cfVitePlugin({ ...cfPluginConfig, viteEnvironment: { name: "ssr" } }),
72
96
  {
73
97
  name: "@astrojs/cloudflare:cf-imports",
74
98
  enforce: "pre",
@@ -84,8 +108,10 @@ function createIntegration(args) {
84
108
  {
85
109
  name: "@astrojs/cloudflare:environment",
86
110
  configEnvironment(environmentName, _options) {
87
- const isServerEnvironment = ["ssr", "prerender"].includes(environmentName);
88
- if (isServerEnvironment && _options.optimizeDeps?.noDiscovery === false) {
111
+ const isServerEnvironment = ["astro", "ssr", "prerender"].includes(
112
+ environmentName
113
+ );
114
+ if (isServerEnvironment && !_options.optimizeDeps?.noDiscovery) {
89
115
  return {
90
116
  optimizeDeps: {
91
117
  include: [
@@ -96,7 +122,6 @@ function createIntegration(args) {
96
122
  "astro > zod/v4",
97
123
  "astro > zod/v4/core",
98
124
  "astro > clsx",
99
- "astro > cssesc",
100
125
  "astro > cookie",
101
126
  "astro > devalue",
102
127
  "astro > @oslojs/encoding",
@@ -105,6 +130,7 @@ function createIntegration(args) {
105
130
  "astro > neotraverse/modern",
106
131
  "astro > piccolore",
107
132
  "astro/app",
133
+ "astro/assets",
108
134
  "astro/compiler-runtime"
109
135
  ],
110
136
  exclude: [
@@ -113,13 +139,21 @@ function createIntegration(args) {
113
139
  "virtual:astro:*",
114
140
  "virtual:astro-cloudflare:*",
115
141
  "virtual:@astrojs/*"
116
- ]
142
+ ],
143
+ esbuildOptions: {
144
+ plugins: [astroFrontmatterScanPlugin()]
145
+ }
117
146
  }
118
147
  };
119
148
  } else if (environmentName === "client") {
120
149
  return {
121
150
  optimizeDeps: {
122
- include: ["astro/runtime/client/dev-toolbar/entrypoint.js"]
151
+ include: ["astro/runtime/client/dev-toolbar/entrypoint.js"],
152
+ // Workaround for https://github.com/vitejs/vite/issues/20867
153
+ // When dependencies are discovered mid-request (e.g. a linked package
154
+ // used with client:only), concurrent requests can fail with 504 because
155
+ // the dep optimizer's metadata object gets replaced during `await info.processing`.
156
+ ignoreOutdatedRequests: true
123
157
  }
124
158
  };
125
159
  }
@@ -137,56 +171,54 @@ function createIntegration(args) {
137
171
  }
138
172
  },
139
173
  createConfigPlugin({
140
- sessionKVBindingName
174
+ sessionKVBindingName,
175
+ compileImageConfig: isCompile && command !== "dev" ? {
176
+ base: config.base,
177
+ assetsPrefix: typeof config.build.assetsPrefix === "string" ? config.build.assetsPrefix : void 0,
178
+ imageServiceEntrypoint: "@astrojs/cloudflare/image-service-workerd",
179
+ buildAssets: config.build.assets ?? "_astro"
180
+ } : null
141
181
  })
142
182
  ]
143
183
  },
144
- image: setImageConfig(args?.imageService ?? "compile", config.image, command, logger)
184
+ image: setImageConfig(imageService, config.image, command, logger)
145
185
  });
186
+ if (cloudflareOptions.configPath) {
187
+ addWatchFile(createRequire(import.meta.url).resolve(cloudflareOptions.configPath));
188
+ }
146
189
  addWatchFile(new URL("./wrangler.toml", config.root));
147
190
  addWatchFile(new URL("./wrangler.json", config.root));
148
191
  addWatchFile(new URL("./wrangler.jsonc", config.root));
149
192
  },
150
193
  "astro:routes:resolved": ({ routes }) => {
151
194
  _routes = routes;
195
+ const nonInternalRoutes = routes.filter((route) => route.origin !== "internal");
196
+ _isFullyStatic = nonInternalRoutes.length > 0 && nonInternalRoutes.every((route) => route.isPrerendered);
152
197
  },
153
- "astro:config:done": ({ setAdapter, config, buildOutput, injectTypes, logger }) => {
198
+ "astro:config:done": ({ setAdapter, config, injectTypes, logger }) => {
154
199
  _config = config;
155
- finalBuildOutput = buildOutput;
156
200
  injectTypes({
157
201
  filename: "cloudflare.d.ts",
158
202
  content: '/// <reference types="@astrojs/cloudflare/types.d.ts" />'
159
203
  });
160
- let customWorkerEntryPoint;
161
- if (args?.workerEntryPoint && typeof args.workerEntryPoint.path === "string") {
162
- const require2 = createRequire(config.root);
163
- try {
164
- customWorkerEntryPoint = pathToFileURL(require2.resolve(args.workerEntryPoint.path));
165
- } catch {
166
- customWorkerEntryPoint = new URL(args.workerEntryPoint.path, config.root);
167
- }
168
- }
169
204
  setAdapter({
170
205
  name: "@astrojs/cloudflare",
171
- serverEntrypoint: customWorkerEntryPoint ?? "@astrojs/cloudflare/entrypoints/server.js",
172
- exports: [.../* @__PURE__ */ new Set(["default", ...args?.workerEntryPoint?.namedExports ?? []])],
173
206
  adapterFeatures: {
174
- edgeMiddleware: false,
175
- buildOutput: "server"
207
+ buildOutput: "server",
208
+ middlewareMode: "classic"
176
209
  },
177
- entryType: "self",
210
+ entrypointResolution: "auto",
178
211
  previewEntrypoint: "@astrojs/cloudflare/entrypoints/preview",
179
212
  supportedAstroFeatures: {
180
213
  serverOutput: "stable",
181
214
  hybridOutput: "stable",
182
- staticOutput: "unsupported",
215
+ staticOutput: "stable",
183
216
  i18nDomains: "experimental",
184
217
  sharpImageService: {
185
218
  support: "limited",
186
- message: 'Cloudflare does not support sharp at runtime. However, you can configure `imageService: "compile"` to optimize images with sharp on prerendered pages during build time.',
187
- // For explicitly set image services, we suppress the warning about sharp not being supported at runtime,
188
- // inferring the user is aware of the limitations.
189
- suppress: args?.imageService ? "all" : "default"
219
+ message: "When using a custom image service, ensure it is compatible with the Cloudflare Workers runtime.",
220
+ // Only 'custom' could potentially use sharp at runtime.
221
+ suppress: buildService === "custom" ? "default" : "all"
190
222
  },
191
223
  envGetSecret: "stable"
192
224
  }
@@ -195,7 +227,7 @@ function createIntegration(args) {
195
227
  if (existsSync(devVarsPath)) {
196
228
  try {
197
229
  const data = readFileSync(devVarsPath, "utf-8");
198
- const parsed = parse(data);
230
+ const parsed = parseEnv(data);
199
231
  Object.assign(process.env, parsed);
200
232
  } catch {
201
233
  logger.error(
@@ -204,6 +236,19 @@ function createIntegration(args) {
204
236
  }
205
237
  }
206
238
  },
239
+ "astro:build:start": ({ setPrerenderer }) => {
240
+ setPrerenderer(
241
+ createCloudflarePrerenderer({
242
+ root: _config.root,
243
+ serverDir: _config.build.server,
244
+ clientDir: _config.build.client,
245
+ base: _config.base,
246
+ trailingSlash: _config.trailingSlash,
247
+ cfPluginConfig,
248
+ hasCompileImageService: buildService === "compile"
249
+ })
250
+ );
251
+ },
207
252
  "astro:build:setup": ({ vite, target }) => {
208
253
  if (target === "server") {
209
254
  vite.resolve ||= {};
@@ -217,14 +262,12 @@ function createIntegration(args) {
217
262
  vite.build.rollupOptions.output.banner ||= "globalThis.process ??= {}; globalThis.process.env ??= {};";
218
263
  vite.define = {
219
264
  "process.env": "process.env",
220
- "globalThis.__ASTRO_IMAGES_BINDING_NAME": JSON.stringify(
221
- args?.imagesBindingName ?? "IMAGES"
222
- ),
265
+ "globalThis.__ASTRO_IMAGES_BINDING_NAME": JSON.stringify(imagesBindingName),
223
266
  ...vite.define
224
267
  };
225
268
  }
226
269
  },
227
- "astro:build:done": async ({ pages, dir, logger, assets }) => {
270
+ "astro:build:done": async ({ dir, logger, assets }) => {
228
271
  let redirectsExists = false;
229
272
  try {
230
273
  const redirectsStat = await stat(new URL("./_redirects", _config.build.client));
@@ -251,26 +294,6 @@ function createIntegration(args) {
251
294
  }
252
295
  }
253
296
  }
254
- let routesExists = false;
255
- try {
256
- const routesStat = await stat(new URL("./_routes.json", _config.build.client));
257
- if (routesStat.isFile()) {
258
- routesExists = true;
259
- }
260
- } catch (_error) {
261
- routesExists = false;
262
- }
263
- if (!routesExists) {
264
- await createRoutesFile(
265
- _config,
266
- logger,
267
- _routes,
268
- pages,
269
- redirects,
270
- args?.routes?.extend?.include,
271
- args?.routes?.extend?.exclude
272
- );
273
- }
274
297
  const trueRedirects = createRedirectsFromAstroRoutes({
275
298
  config: _config,
276
299
  routeToDynamicTargetMap: new Map(
@@ -279,7 +302,7 @@ function createIntegration(args) {
279
302
  )
280
303
  ),
281
304
  dir,
282
- buildOutput: finalBuildOutput,
305
+ buildOutput: _isFullyStatic ? "static" : "server",
283
306
  assets
284
307
  });
285
308
  if (!trueRedirects.empty()) {
@@ -292,6 +315,10 @@ function createIntegration(args) {
292
315
  logger.error("Failed to write _redirects file");
293
316
  }
294
317
  }
318
+ if (_isFullyStatic) {
319
+ await rm(_config.build.server, { recursive: true, force: true });
320
+ }
321
+ delete process.env.CLOUDFLARE_VITE_BUILD;
295
322
  }
296
323
  }
297
324
  };
package/dist/info.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Re-exports utilities for use by astro add CLI.
3
+ * This provides a resolvable path from the user's project.
4
+ */
5
+ export { getLocalWorkerdCompatibilityDate } from '@cloudflare/vite-plugin';
package/dist/info.js ADDED
@@ -0,0 +1,4 @@
1
+ import { getLocalWorkerdCompatibilityDate } from "@cloudflare/vite-plugin";
2
+ export {
3
+ getLocalWorkerdCompatibilityDate
4
+ };
@@ -0,0 +1,32 @@
1
+ import type { SerializedRouteData } from 'astro/app/manifest';
2
+ /**
3
+ * A pathname with its serialized route data, used for prerendering over HTTP.
4
+ */
5
+ interface SerializedPathWithRoute {
6
+ pathname: string;
7
+ route: SerializedRouteData;
8
+ }
9
+ /**
10
+ * Response from the /__astro_static_paths endpoint.
11
+ */
12
+ export interface StaticPathsResponse {
13
+ paths: SerializedPathWithRoute[];
14
+ }
15
+ /**
16
+ * Request body for the /__astro_prerender endpoint.
17
+ */
18
+ export interface PrerenderRequest {
19
+ url: string;
20
+ routeData: SerializedRouteData;
21
+ }
22
+ export interface SerializedStaticImageEntry {
23
+ originalPath: string;
24
+ originalSrcPath: string | undefined;
25
+ transforms: Array<{
26
+ hash: string;
27
+ finalPath: string;
28
+ transform: Record<string, any>;
29
+ }>;
30
+ }
31
+ export type StaticImagesResponse = SerializedStaticImageEntry[];
32
+ export {};
File without changes
@@ -0,0 +1,17 @@
1
+ import type { AstroConfig, AstroPrerenderer } from 'astro';
2
+ import { type PluginConfig } from '@cloudflare/vite-plugin';
3
+ interface CloudflarePrerendererOptions {
4
+ root: AstroConfig['root'];
5
+ serverDir: AstroConfig['build']['server'];
6
+ clientDir: AstroConfig['build']['client'];
7
+ base: AstroConfig['base'];
8
+ trailingSlash: AstroConfig['trailingSlash'];
9
+ cfPluginConfig: PluginConfig;
10
+ hasCompileImageService: boolean;
11
+ }
12
+ /**
13
+ * Creates a prerenderer that uses Cloudflare's workerd runtime via a preview server.
14
+ * This allows prerendering to happen in the same runtime that will serve the pages.
15
+ */
16
+ export declare function createCloudflarePrerenderer({ root, serverDir, clientDir, base, trailingSlash, cfPluginConfig, hasCompileImageService, }: CloudflarePrerendererOptions): AstroPrerenderer;
17
+ export {};