@astrojs/cloudflare 13.0.0-beta.7 → 13.0.0-beta.8

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.
@@ -83,7 +83,7 @@ function serverStart({
83
83
  host,
84
84
  base
85
85
  }) {
86
- const version = "13.0.0-beta.7";
86
+ const version = "13.0.0-beta.8";
87
87
  const localPrefix = `${colors.dim("\u2503")} Local `;
88
88
  const networkPrefix = `${colors.dim("\u2503")} Network `;
89
89
  const emptyPrefix = " ".repeat(11);
package/dist/index.d.ts CHANGED
@@ -4,30 +4,6 @@ export type { Runtime } from './utils/handler.js';
4
4
  export type Options = {
5
5
  /** Options for handling images. */
6
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
7
  /**
32
8
  * By default, Astro will be configured to use Cloudflare KV to store session data. The KV namespace
33
9
  * will be automatically provisioned when you deploy.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { createReadStream, existsSync, readFileSync } from "node:fs";
2
- import { appendFile, stat } from "node:fs/promises";
2
+ import { appendFile, rm, stat } from "node:fs/promises";
3
3
  import { createInterface } from "node:readline/promises";
4
4
  import { removeLeadingForwardSlash } from "@astrojs/internal-helpers/path";
5
5
  import { createRedirectsFromAstroRoutes, printAsRedirects } from "@astrojs/underscore-redirects";
6
6
  import { cloudflare as cfVitePlugin } from "@cloudflare/vite-plugin";
7
7
  import { astroFrontmatterScanPlugin } from "./esbuild-plugin-astro-frontmatter.js";
8
- import { createRoutesFile, getParts } from "./utils/generate-routes-json.js";
8
+ import { getParts } from "./utils/generate-routes-json.js";
9
9
  import { setImageConfig } from "./utils/image-config.js";
10
10
  import { createConfigPlugin } from "./vite-plugin-config.js";
11
11
  import {
@@ -18,8 +18,8 @@ import { sessionDrivers } from "astro/config";
18
18
  import { createCloudflarePrerenderer } from "./prerenderer.js";
19
19
  function createIntegration(args) {
20
20
  let _config;
21
- let finalBuildOutput;
22
21
  let _routes;
22
+ let _isFullyStatic = false;
23
23
  const sessionKVBindingName = args?.sessionKVBindingName ?? DEFAULT_SESSION_KV_BINDING_NAME;
24
24
  const imagesBindingName = args?.imagesBindingName ?? DEFAULT_IMAGES_BINDING_NAME;
25
25
  return {
@@ -64,8 +64,6 @@ function createIntegration(args) {
64
64
  };
65
65
  updateConfig({
66
66
  build: {
67
- client: new URL(`./client/`, config.outDir),
68
- server: new URL("./_worker.js/", config.outDir),
69
67
  redirects: false
70
68
  },
71
69
  session,
@@ -162,10 +160,11 @@ function createIntegration(args) {
162
160
  },
163
161
  "astro:routes:resolved": ({ routes }) => {
164
162
  _routes = routes;
163
+ const nonInternalRoutes = routes.filter((route) => route.origin !== "internal");
164
+ _isFullyStatic = nonInternalRoutes.length > 0 && nonInternalRoutes.every((route) => route.isPrerendered);
165
165
  },
166
- "astro:config:done": ({ setAdapter, config, buildOutput, injectTypes, logger }) => {
166
+ "astro:config:done": ({ setAdapter, config, injectTypes, logger }) => {
167
167
  _config = config;
168
- finalBuildOutput = buildOutput;
169
168
  injectTypes({
170
169
  filename: "cloudflare.d.ts",
171
170
  content: '/// <reference types="@astrojs/cloudflare/types.d.ts" />'
@@ -176,12 +175,12 @@ function createIntegration(args) {
176
175
  edgeMiddleware: false,
177
176
  buildOutput: "server"
178
177
  },
179
- entryType: "self",
178
+ entrypointResolution: "auto",
180
179
  previewEntrypoint: "@astrojs/cloudflare/entrypoints/preview",
181
180
  supportedAstroFeatures: {
182
181
  serverOutput: "stable",
183
182
  hybridOutput: "stable",
184
- staticOutput: "unsupported",
183
+ staticOutput: "stable",
185
184
  i18nDomains: "experimental",
186
185
  sharpImageService: {
187
186
  support: "limited",
@@ -236,7 +235,7 @@ function createIntegration(args) {
236
235
  };
237
236
  }
238
237
  },
239
- "astro:build:done": async ({ pages, dir, logger, assets }) => {
238
+ "astro:build:done": async ({ dir, logger, assets }) => {
240
239
  let redirectsExists = false;
241
240
  try {
242
241
  const redirectsStat = await stat(new URL("./_redirects", _config.build.client));
@@ -263,26 +262,6 @@ function createIntegration(args) {
263
262
  }
264
263
  }
265
264
  }
266
- let routesExists = false;
267
- try {
268
- const routesStat = await stat(new URL("./_routes.json", _config.build.client));
269
- if (routesStat.isFile()) {
270
- routesExists = true;
271
- }
272
- } catch (_error) {
273
- routesExists = false;
274
- }
275
- if (!routesExists) {
276
- await createRoutesFile(
277
- _config,
278
- logger,
279
- _routes,
280
- pages,
281
- redirects,
282
- args?.routes?.extend?.include,
283
- args?.routes?.extend?.exclude
284
- );
285
- }
286
265
  const trueRedirects = createRedirectsFromAstroRoutes({
287
266
  config: _config,
288
267
  routeToDynamicTargetMap: new Map(
@@ -291,7 +270,7 @@ function createIntegration(args) {
291
270
  )
292
271
  ),
293
272
  dir,
294
- buildOutput: finalBuildOutput,
273
+ buildOutput: _isFullyStatic ? "static" : "server",
295
274
  assets
296
275
  });
297
276
  if (!trueRedirects.empty()) {
@@ -304,6 +283,9 @@ function createIntegration(args) {
304
283
  logger.error("Failed to write _redirects file");
305
284
  }
306
285
  }
286
+ if (_isFullyStatic) {
287
+ await rm(_config.build.server, { recursive: true, force: true });
288
+ }
307
289
  delete process.env.CLOUDFLARE_VITE_BUILD;
308
290
  }
309
291
  }
@@ -1,9 +1,2 @@
1
- import type { AstroConfig, AstroIntegrationLogger, IntegrationResolvedRoute, RoutePart } from 'astro';
1
+ import type { RoutePart } from 'astro';
2
2
  export declare function getParts(part: string): RoutePart[];
3
- export declare function createRoutesFile(_config: AstroConfig, logger: AstroIntegrationLogger, routes: IntegrationResolvedRoute[], pages: {
4
- pathname: string;
5
- }[], redirects: IntegrationResolvedRoute['segments'][], includeExtends: {
6
- pattern: string;
7
- }[] | undefined, excludeExtends: {
8
- pattern: string;
9
- }[] | undefined): Promise<void>;
@@ -1,13 +1,3 @@
1
- import { existsSync } from "node:fs";
2
- import { writeFile } from "node:fs/promises";
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import {
6
- prependForwardSlash,
7
- removeLeadingForwardSlash,
8
- removeTrailingForwardSlash
9
- } from "@astrojs/internal-helpers/path";
10
- import { glob } from "tinyglobby";
11
1
  const ROUTE_DYNAMIC_SPLIT = /\[(.+?\(.+?\)|.+?)\]/;
12
2
  const ROUTE_SPREAD = /^\.{3}.+$/;
13
3
  function getParts(part) {
@@ -27,199 +17,6 @@ function getParts(part) {
27
17
  });
28
18
  return result;
29
19
  }
30
- async function writeRoutesFileToOutDir(_config, logger, include, exclude) {
31
- try {
32
- await writeFile(
33
- new URL("./_routes.json", _config.outDir),
34
- JSON.stringify(
35
- {
36
- version: 1,
37
- include,
38
- exclude
39
- },
40
- null,
41
- 2
42
- ),
43
- "utf-8"
44
- );
45
- } catch (_error) {
46
- logger.error("There was an error writing the '_routes.json' file to the output directory.");
47
- }
48
- }
49
- function segmentsToCfSyntax(segments, _config) {
50
- const pathSegments = [];
51
- if (removeLeadingForwardSlash(removeTrailingForwardSlash(_config.base)).length > 0) {
52
- pathSegments.push(removeLeadingForwardSlash(removeTrailingForwardSlash(_config.base)));
53
- }
54
- for (const segment of segments.flat()) {
55
- if (segment.dynamic) pathSegments.push("*");
56
- else pathSegments.push(segment.content);
57
- }
58
- return pathSegments;
59
- }
60
- class TrieNode {
61
- children = /* @__PURE__ */ new Map();
62
- isEndOfPath = false;
63
- hasWildcardChild = false;
64
- }
65
- class PathTrie {
66
- root;
67
- returnHasWildcard = false;
68
- constructor() {
69
- this.root = new TrieNode();
70
- }
71
- insert(thisPath) {
72
- let node = this.root;
73
- for (const segment of thisPath) {
74
- if (segment === "*") {
75
- node.hasWildcardChild = true;
76
- break;
77
- }
78
- if (!node.children.has(segment)) {
79
- node.children.set(segment, new TrieNode());
80
- }
81
- node = node.children.get(segment);
82
- }
83
- node.isEndOfPath = true;
84
- }
85
- /**
86
- * Depth-first search (dfs), traverses the "graph" segment by segment until the end or wildcard (*).
87
- * It makes sure that all necessary paths are returned, but not paths with an existing wildcard prefix.
88
- * e.g. if we have a path like /foo/* and /foo/bar, we only want to return /foo/*
89
- */
90
- dfs(node, thisPath, allPaths) {
91
- if (node.hasWildcardChild) {
92
- this.returnHasWildcard = true;
93
- allPaths.push([...thisPath, "*"]);
94
- return;
95
- }
96
- if (node.isEndOfPath) {
97
- allPaths.push([...thisPath]);
98
- }
99
- for (const [segment, childNode] of node.children) {
100
- this.dfs(childNode, [...thisPath, segment], allPaths);
101
- }
102
- }
103
- /**
104
- * The reduce function is used to remove unnecessary paths from the trie.
105
- * It receives a trie node to compare with the current node.
106
- */
107
- reduce(compNode, node) {
108
- if (node.hasWildcardChild || compNode.hasWildcardChild) return;
109
- for (const [segment, childNode] of node.children) {
110
- if (childNode.children.size === 0) continue;
111
- const compChildNode = compNode.children.get(segment);
112
- if (compChildNode === void 0) {
113
- childNode.hasWildcardChild = true;
114
- continue;
115
- }
116
- this.reduce(compChildNode, childNode);
117
- }
118
- }
119
- reduceAllPaths(compTrie) {
120
- this.reduce(compTrie.root, this.root);
121
- return this;
122
- }
123
- getAllPaths() {
124
- const allPaths = [];
125
- this.dfs(this.root, [], allPaths);
126
- return [allPaths, this.returnHasWildcard];
127
- }
128
- }
129
- async function createRoutesFile(_config, logger, routes, pages, redirects, includeExtends, excludeExtends) {
130
- const includePaths = [];
131
- const excludePaths = [];
132
- const assetsPath = segmentsToCfSyntax(
133
- [
134
- [{ content: _config.build.assets, dynamic: false, spread: false }],
135
- [{ content: "", dynamic: true, spread: false }]
136
- ],
137
- _config
138
- );
139
- excludePaths.push(assetsPath);
140
- for (const redirect of redirects) {
141
- excludePaths.push(segmentsToCfSyntax(redirect, _config));
142
- }
143
- if (existsSync(fileURLToPath(_config.publicDir))) {
144
- const staticFiles = await glob(`**/*`, {
145
- cwd: fileURLToPath(_config.publicDir),
146
- dot: true
147
- });
148
- for (const staticFile of staticFiles) {
149
- if (["_headers", "_redirects", "_routes.json"].includes(staticFile)) continue;
150
- const staticPath = staticFile;
151
- const segments = removeLeadingForwardSlash(staticPath).split(path.sep).filter(Boolean).map((s) => {
152
- return getParts(s);
153
- });
154
- excludePaths.push(segmentsToCfSyntax(segments, _config));
155
- }
156
- }
157
- let hasPrerendered404 = false;
158
- for (const route of routes) {
159
- const convertedPath = segmentsToCfSyntax(route.segments, _config);
160
- if (route.pathname === "/404" && route.isPrerendered === true) hasPrerendered404 = true;
161
- switch (route.type) {
162
- case "page":
163
- if (route.isPrerendered === false) includePaths.push(convertedPath);
164
- break;
165
- case "endpoint":
166
- if (route.isPrerendered === false) includePaths.push(convertedPath);
167
- else excludePaths.push(convertedPath);
168
- break;
169
- case "redirect":
170
- excludePaths.push(convertedPath);
171
- break;
172
- default:
173
- includePaths.push(convertedPath);
174
- break;
175
- }
176
- }
177
- for (const page of pages) {
178
- if (page.pathname === "404") hasPrerendered404 = true;
179
- const pageSegments = removeLeadingForwardSlash(page.pathname).split(path.posix.sep).filter(Boolean).map((s) => {
180
- return getParts(s);
181
- });
182
- excludePaths.push(segmentsToCfSyntax(pageSegments, _config));
183
- }
184
- const includeTrie = new PathTrie();
185
- for (const includePath of includePaths) {
186
- includeTrie.insert(includePath);
187
- }
188
- const excludeTrie = new PathTrie();
189
- for (const excludePath of excludePaths) {
190
- if (excludePath[0] === "*") continue;
191
- excludeTrie.insert(excludePath);
192
- }
193
- const [deduplicatedIncludePaths, includedPathsHaveWildcard] = includeTrie.reduceAllPaths(excludeTrie).getAllPaths();
194
- const [deduplicatedExcludePaths, _excludedPathsHaveWildcard] = excludeTrie.reduceAllPaths(includeTrie).getAllPaths();
195
- const CLOUDFLARE_COMBINED_LIMIT = 100;
196
- const AUTOMATIC_INCLUDE_RULES_COUNT = deduplicatedIncludePaths.length;
197
- const EXTENDED_INCLUDE_RULES_COUNT = includeExtends?.length ?? 0;
198
- const INCLUDE_RULES_COUNT = AUTOMATIC_INCLUDE_RULES_COUNT + EXTENDED_INCLUDE_RULES_COUNT;
199
- const AUTOMATIC_EXCLUDE_RULES_COUNT = deduplicatedExcludePaths.length;
200
- const EXTENDED_EXCLUDE_RULES_COUNT = excludeExtends?.length ?? 0;
201
- const EXCLUDE_RULES_COUNT = AUTOMATIC_EXCLUDE_RULES_COUNT + EXTENDED_EXCLUDE_RULES_COUNT;
202
- const OPTION2_TOTAL_COUNT = INCLUDE_RULES_COUNT + (includedPathsHaveWildcard ? EXCLUDE_RULES_COUNT : 0);
203
- if (!hasPrerendered404 || OPTION2_TOTAL_COUNT > CLOUDFLARE_COMBINED_LIMIT) {
204
- await writeRoutesFileToOutDir(
205
- _config,
206
- logger,
207
- ["/*"].concat(includeExtends?.map((entry) => entry.pattern) ?? []),
208
- deduplicatedExcludePaths.map((thisPath) => `${prependForwardSlash(thisPath.join("/"))}`).slice(
209
- 0,
210
- CLOUDFLARE_COMBINED_LIMIT - EXTENDED_INCLUDE_RULES_COUNT - EXTENDED_EXCLUDE_RULES_COUNT - 1
211
- ).concat(excludeExtends?.map((entry) => entry.pattern) ?? [])
212
- );
213
- } else {
214
- await writeRoutesFileToOutDir(
215
- _config,
216
- logger,
217
- deduplicatedIncludePaths.map((thisPath) => `${prependForwardSlash(thisPath.join("/"))}`).concat(includeExtends?.map((entry) => entry.pattern) ?? []),
218
- includedPathsHaveWildcard ? deduplicatedExcludePaths.map((thisPath) => `${prependForwardSlash(thisPath.join("/"))}`).concat(excludeExtends?.map((entry) => entry.pattern) ?? []) : []
219
- );
220
- }
221
- }
222
20
  export {
223
- createRoutesFile,
224
21
  getParts
225
22
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrojs/cloudflare",
3
- "description": "Deploy your site to Cloudflare Workers/Pages",
4
- "version": "13.0.0-beta.7",
3
+ "description": "Deploy your site to Cloudflare Workers",
4
+ "version": "13.0.0-beta.8",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
7
7
  "author": "withastro",
@@ -35,7 +35,7 @@
35
35
  "types.d.ts"
36
36
  ],
37
37
  "dependencies": {
38
- "@cloudflare/vite-plugin": "^1.23.0",
38
+ "@cloudflare/vite-plugin": "^1.25.0",
39
39
  "piccolore": "^0.1.3",
40
40
  "tinyglobby": "^0.2.15",
41
41
  "vite": "^7.3.1",
@@ -47,11 +47,11 @@
47
47
  "wrangler": "^4.61.1"
48
48
  },
49
49
  "devDependencies": {
50
- "@cloudflare/workers-types": "^4.20260131.0",
50
+ "@cloudflare/workers-types": "^4.20260213.0",
51
51
  "@types/node": "^25.2.2",
52
52
  "cheerio": "1.2.0",
53
53
  "devalue": "^5.6.2",
54
- "astro": "6.0.0-beta.11",
54
+ "astro": "6.0.0-beta.12",
55
55
  "astro-scripts": "0.0.14"
56
56
  },
57
57
  "publishConfig": {