@astrojs/cloudflare 6.6.1 → 6.7.0

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.
package/README.md CHANGED
@@ -106,7 +106,10 @@ Cloudflare has support for adding custom [headers](https://developers.cloudflare
106
106
 
107
107
  ### Custom `_routes.json`
108
108
 
109
- By default, `@astrojs/cloudflare` will generate a `_routes.json` file that lists all files from your `dist/` folder and redirects from the `_redirects` file in the `exclude` array. This will enable Cloudflare to serve files and process static redirects without a function invocation. Creating a custom `_routes.json` will override this automatic optimization and, if not configured manually, cause function invocations that will count against the request limits of your Cloudflare plan.
109
+ By default, `@astrojs/cloudflare` will generate a `_routes.json` file with `include` and `exclude` rules based on your applications's dynamic and static routes.
110
+ This will enable Cloudflare to serve files and process static redirects without a function invocation. Creating a custom `_routes.json` will override this automatic optimization and, if not configured manually, cause function invocations that will count against the request limits of your Cloudflare plan.
111
+
112
+ See [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/functions/routing/#create-a-_routesjson-file) for more details.
110
113
 
111
114
  ## Troubleshooting
112
115
 
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { createRedirectsFromAstroRoutes } from "@astrojs/underscore-redirects";
2
2
  import esbuild from "esbuild";
3
- import * as fs from "fs";
4
- import * as os from "os";
5
- import { dirname } from "path";
3
+ import * as fs from "node:fs";
4
+ import * as os from "node:os";
5
+ import { sep } from "node:path";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
6
7
  import glob from "tiny-glob";
7
- import { fileURLToPath, pathToFileURL } from "url";
8
8
  function getAdapter(isModeDirectory) {
9
9
  return isModeDirectory ? {
10
10
  name: "@astrojs/cloudflare",
@@ -21,6 +21,7 @@ const SHIM = `globalThis.process = {
21
21
  env: {},
22
22
  };`;
23
23
  const SERVER_BUILD_FOLDER = "/$server_build/";
24
+ const potentialFunctionRouteTypes = ["endpoint", "page"];
24
25
  function createIntegration(args) {
25
26
  let _config;
26
27
  let _buildConfig;
@@ -68,6 +69,10 @@ function createIntegration(args) {
68
69
  }
69
70
  vite.ssr ||= {};
70
71
  vite.ssr.target = "webworker";
72
+ vite.define = {
73
+ "process.env": "process.env",
74
+ ...vite.define
75
+ };
71
76
  }
72
77
  },
73
78
  "astro:build:ssr": ({ entryPoints }) => {
@@ -80,11 +85,11 @@ function createIntegration(args) {
80
85
  await fs.promises.mkdir(functionsUrl, { recursive: true });
81
86
  }
82
87
  if (isModeDirectory && _buildConfig.split) {
83
- const entryPointsRouteData = [..._entryPoints.keys()];
84
88
  const entryPointsURL = [..._entryPoints.values()];
85
89
  const entryPaths = entryPointsURL.map((entry) => fileURLToPath(entry));
86
- const outputDir = fileURLToPath(new URL(".astro", _buildConfig.server));
87
- const { outputFiles } = await esbuild.build({
90
+ const outputUrl = new URL("$astro", _buildConfig.server);
91
+ const outputDir = fileURLToPath(outputUrl);
92
+ await esbuild.build({
88
93
  target: "es2020",
89
94
  platform: "browser",
90
95
  conditions: ["workerd", "worker", "browser"],
@@ -99,19 +104,31 @@ function createIntegration(args) {
99
104
  },
100
105
  logOverride: {
101
106
  "ignored-bare-import": "silent"
102
- },
103
- write: false
107
+ }
108
+ });
109
+ const outputFiles = await glob(`**/*`, {
110
+ cwd: outputDir,
111
+ filesOnly: true
104
112
  });
105
- for (const [index, outputFile] of outputFiles.entries()) {
106
- const fileName = entryPointsRouteData[index].component.replace("src/pages/", "").replace(".astro", ".js").replace(/(\[\.\.\.)(\w+)(\])/g, (_match, _p1, p2) => {
107
- return `[[${p2}]]`;
113
+ for (const outputFile of outputFiles) {
114
+ const path = outputFile.split(sep);
115
+ const finalSegments = path.map(
116
+ (segment) => segment.replace(/(\_)(\w+)(\_)/g, (_, __, prop) => {
117
+ return `[${prop}]`;
118
+ }).replace(/(\_\-\-\-)(\w+)(\_)/g, (_, __, prop) => {
119
+ return `[[${prop}]]`;
120
+ })
121
+ );
122
+ finalSegments[finalSegments.length - 1] = finalSegments[finalSegments.length - 1].replace("entry.", "").replace(/(.*)\.(\w+)\.(\w+)$/g, (_, fileName, __, newExt) => {
123
+ return `${fileName}.${newExt}`;
108
124
  });
109
- const fileUrl = new URL(fileName, functionsUrl);
110
- const newFileDir = dirname(fileURLToPath(fileUrl));
111
- if (!fs.existsSync(newFileDir)) {
112
- fs.mkdirSync(newFileDir, { recursive: true });
113
- }
114
- await fs.promises.writeFile(fileUrl, outputFile.contents);
125
+ const finalDirPath = finalSegments.slice(0, -1).join(sep);
126
+ const finalPath = finalSegments.join(sep);
127
+ const newDirUrl = new URL(finalDirPath, functionsUrl);
128
+ await fs.promises.mkdir(newDirUrl, { recursive: true });
129
+ const oldFileUrl = new URL(`$astro/${outputFile}`, outputUrl);
130
+ const newFileUrl = new URL(finalPath, functionsUrl);
131
+ await fs.promises.rename(oldFileUrl, newFileUrl);
115
132
  }
116
133
  } else {
117
134
  const entryPath = fileURLToPath(new URL(_buildConfig.serverEntry, _buildConfig.server));
@@ -157,10 +174,20 @@ function createIntegration(args) {
157
174
  }
158
175
  const routesExists = await fs.promises.stat(new URL("./_routes.json", _config.outDir)).then((stat) => stat.isFile()).catch(() => false);
159
176
  if (!routesExists) {
177
+ const functionEndpoints = routes.filter((route) => potentialFunctionRouteTypes.includes(route.type) && !route.prerender).map((route) => {
178
+ const includePattern = "/" + route.segments.flat().map((segment) => segment.dynamic ? "*" : segment.content).join("/");
179
+ const regexp = new RegExp(
180
+ "^\\/" + route.segments.flat().map((segment) => segment.dynamic ? "(.*)" : segment.content).join("\\/") + "$"
181
+ );
182
+ return {
183
+ includePattern,
184
+ regexp
185
+ };
186
+ });
160
187
  const staticPathList = (await glob(`${fileURLToPath(_buildConfig.client)}/**/*`, {
161
188
  cwd: fileURLToPath(_config.outDir),
162
189
  filesOnly: true
163
- })).filter((file) => cloudflareSpecialFiles.indexOf(file) < 0).map((file) => `/${file}`);
190
+ })).filter((file) => cloudflareSpecialFiles.indexOf(file) < 0).map((file) => `/${file.replace(/\\/g, "/")}`);
164
191
  for (let page of pages) {
165
192
  let pagePath = prependForwardSlash(page.pathname);
166
193
  if (_config.base !== "/") {
@@ -199,13 +226,30 @@ function createIntegration(args) {
199
226
  trueRedirects.print()
200
227
  );
201
228
  }
229
+ staticPathList.push(...routes.filter((r) => r.type === "redirect").map((r) => r.route));
230
+ let include = deduplicatePatterns(
231
+ functionEndpoints.map((endpoint) => endpoint.includePattern)
232
+ );
233
+ let exclude = deduplicatePatterns(
234
+ staticPathList.filter(
235
+ (file) => functionEndpoints.some((endpoint) => endpoint.regexp.test(file))
236
+ )
237
+ );
238
+ if (include.length === 0) {
239
+ include = ["/"];
240
+ exclude = ["/"];
241
+ }
242
+ if (include.length + exclude.length > staticPathList.length) {
243
+ include = ["/*"];
244
+ exclude = deduplicatePatterns(staticPathList);
245
+ }
202
246
  await fs.promises.writeFile(
203
247
  new URL("./_routes.json", _config.outDir),
204
248
  JSON.stringify(
205
249
  {
206
250
  version: 1,
207
- include: ["/*"],
208
- exclude: staticPathList
251
+ include,
252
+ exclude
209
253
  },
210
254
  null,
211
255
  2
@@ -219,6 +263,18 @@ function createIntegration(args) {
219
263
  function prependForwardSlash(path) {
220
264
  return path[0] === "/" ? path : "/" + path;
221
265
  }
266
+ function deduplicatePatterns(patterns) {
267
+ const openPatterns = [];
268
+ return [...new Set(patterns)].sort((a, b) => a.length - b.length).filter((pattern) => {
269
+ if (openPatterns.some((p) => p.test(pattern))) {
270
+ return false;
271
+ }
272
+ if (pattern.endsWith("*")) {
273
+ openPatterns.push(new RegExp(`^${pattern.replace(/(\*\/)*\*$/g, ".*")}`));
274
+ }
275
+ return true;
276
+ });
277
+ }
222
278
  export {
223
279
  createIntegration as default,
224
280
  getAdapter
@@ -1,4 +1,4 @@
1
- import type { ExecutionContext, Request as CFRequest } from '@cloudflare/workers-types';
1
+ import type { Request as CFRequest, ExecutionContext } from '@cloudflare/workers-types';
2
2
  import type { SSRManifest } from 'astro';
3
3
  type Env = {
4
4
  ASSETS: {
@@ -1,10 +1,10 @@
1
- import type { EventContext, Request as CFRequest } from '@cloudflare/workers-types';
1
+ import type { Request as CFRequest, EventContext } from '@cloudflare/workers-types';
2
2
  import type { SSRManifest } from 'astro';
3
3
  export declare function createExports(manifest: SSRManifest): {
4
4
  onRequest: ({ request, next, ...runtimeEnv }: {
5
5
  request: Request & CFRequest;
6
6
  next: (request: Request) => void;
7
7
  waitUntil: EventContext<unknown, any, unknown>['waitUntil'];
8
- } & Record<string, unknown>) => Promise<void | Response>;
8
+ } & Record<string, unknown>) => Promise<import("@cloudflare/workers-types").Response | Response>;
9
9
  manifest: SSRManifest;
10
10
  };
@@ -13,7 +13,9 @@ function createExports(manifest) {
13
13
  process.env = runtimeEnv.env;
14
14
  const { pathname } = new URL(request.url);
15
15
  if (manifest.assets.has(pathname)) {
16
- return next(request);
16
+ return runtimeEnv.env.ASSETS.fetch(
17
+ request
18
+ );
17
19
  }
18
20
  let routeData = app.match(request, { matchNotFound: true });
19
21
  if (routeData) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrojs/cloudflare",
3
3
  "description": "Deploy your site to Cloudflare Workers/Pages",
4
- "version": "6.6.1",
4
+ "version": "6.7.0",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
7
7
  "author": "withastro",
@@ -38,14 +38,14 @@
38
38
  "tiny-glob": "^0.2.9"
39
39
  },
40
40
  "peerDependencies": {
41
- "astro": "^2.8.2"
41
+ "astro": "^2.10.5"
42
42
  },
43
43
  "devDependencies": {
44
44
  "chai": "^4.3.7",
45
45
  "cheerio": "1.0.0-rc.12",
46
46
  "mocha": "^9.2.2",
47
47
  "wrangler": "^2.0.23",
48
- "astro": "2.8.2",
48
+ "astro": "2.10.5",
49
49
  "astro-scripts": "0.0.14"
50
50
  },
51
51
  "scripts": {