@astrojs/cloudflare 14.0.0-alpha.1 → 14.0.0-beta.2
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/dist/entrypoints/preview.js +1 -1
- package/dist/index.js +39 -2
- package/dist/utils/headers.d.ts +26 -0
- package/dist/utils/headers.js +63 -0
- package/package.json +2 -2
|
@@ -88,7 +88,7 @@ function serverStart({
|
|
|
88
88
|
host,
|
|
89
89
|
base
|
|
90
90
|
}) {
|
|
91
|
-
const version = "14.0.0-
|
|
91
|
+
const version = "14.0.0-beta.2";
|
|
92
92
|
const localPrefix = `${colors.dim("\u2503")} Local `;
|
|
93
93
|
const networkPrefix = `${colors.dim("\u2503")} Network `;
|
|
94
94
|
const emptyPrefix = " ".repeat(11);
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { createReadStream, existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { appendFile, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { appendFile, readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import { relative } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { normalizePath } from "vite";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
removeLeadingForwardSlash,
|
|
9
|
+
removeTrailingForwardSlash
|
|
10
|
+
} from "@astrojs/internal-helpers/path";
|
|
8
11
|
import { createRedirectsFromAstroRoutes, printAsRedirects } from "@astrojs/underscore-redirects";
|
|
9
12
|
import { cloudflare as cfVitePlugin } from "@cloudflare/vite-plugin";
|
|
10
13
|
import { astroFrontmatterScanPlugin } from "./esbuild-plugin-astro-frontmatter.js";
|
|
11
14
|
import { getParts } from "./utils/generate-routes-json.js";
|
|
15
|
+
import { buildAssetsHeadersContent } from "./utils/headers.js";
|
|
12
16
|
import {
|
|
13
17
|
normalizeImageServiceConfig,
|
|
14
18
|
setImageConfig
|
|
@@ -378,6 +382,39 @@ function createIntegration({
|
|
|
378
382
|
} catch {
|
|
379
383
|
}
|
|
380
384
|
}
|
|
385
|
+
if (_config.build.assetsPrefix) {
|
|
386
|
+
logger.debug(
|
|
387
|
+
"Skipping Cache-Control injection for assets \u2014 `build.assetsPrefix` is set, so assets are served from a different origin."
|
|
388
|
+
);
|
|
389
|
+
} else {
|
|
390
|
+
const headersPath = new URL("./_headers", _originalClientDir);
|
|
391
|
+
const result = await buildAssetsHeadersContent(
|
|
392
|
+
{
|
|
393
|
+
assetsDir: _config.build.assets,
|
|
394
|
+
basePrefix: removeTrailingForwardSlash(_config.base),
|
|
395
|
+
headersPath
|
|
396
|
+
},
|
|
397
|
+
(path) => readFile(path, "utf-8")
|
|
398
|
+
);
|
|
399
|
+
if (result === null) {
|
|
400
|
+
logger.debug(
|
|
401
|
+
`Skipping Cache-Control injection \u2014 _headers already sets Cache-Control on a matching rule.`
|
|
402
|
+
);
|
|
403
|
+
} else {
|
|
404
|
+
const tempPath = new URL("./_headers.tmp", _originalClientDir);
|
|
405
|
+
try {
|
|
406
|
+
await writeFile(tempPath, result.content);
|
|
407
|
+
await rename(tempPath, headersPath);
|
|
408
|
+
} catch (err) {
|
|
409
|
+
await unlink(tempPath).catch(() => {
|
|
410
|
+
});
|
|
411
|
+
throw err;
|
|
412
|
+
}
|
|
413
|
+
logger.info(
|
|
414
|
+
`Injected immutable Cache-Control for ${result.assetsPattern} into _headers.`
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
381
418
|
let redirectsExists = false;
|
|
382
419
|
try {
|
|
383
420
|
const redirectsStat = await stat(new URL("./_redirects", _originalClientDir));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true if the given `_headers` content already declares (or detaches)
|
|
3
|
+
* a `Cache-Control` directive on any rule whose URL pattern matches `path`.
|
|
4
|
+
*
|
|
5
|
+
* Used to avoid emitting a second `Cache-Control` rule for hashed assets when
|
|
6
|
+
* the user already has one — Cloudflare merges duplicate header values across
|
|
7
|
+
* matching rules with a comma, which produces contradictory cache directives.
|
|
8
|
+
*/
|
|
9
|
+
export declare function headersFileHasCacheControlForPath(content: string, path: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Computes the content to write to `_headers` to inject an immutable
|
|
12
|
+
* Cache-Control rule for the hashed assets directory.
|
|
13
|
+
*
|
|
14
|
+
* Returns `null` when injection should be skipped because the existing
|
|
15
|
+
* `_headers` already declares `Cache-Control` on a rule matching the assets
|
|
16
|
+
* path — Cloudflare merges duplicate header values with a comma, which would
|
|
17
|
+
* produce contradictory directives.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildAssetsHeadersContent(opts: {
|
|
20
|
+
assetsDir: string;
|
|
21
|
+
basePrefix: string;
|
|
22
|
+
headersPath: URL;
|
|
23
|
+
}, readFile: (path: URL) => Promise<string>): Promise<{
|
|
24
|
+
content: string;
|
|
25
|
+
assetsPattern: string;
|
|
26
|
+
} | null>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
function cfHeadersPatternToRegex(pattern) {
|
|
2
|
+
let regexStr = "";
|
|
3
|
+
let i = 0;
|
|
4
|
+
while (i < pattern.length) {
|
|
5
|
+
const ch = pattern[i];
|
|
6
|
+
if (ch === "*") {
|
|
7
|
+
regexStr += ".*";
|
|
8
|
+
i++;
|
|
9
|
+
} else if (ch === ":" && /[A-Za-z]/.test(pattern[i + 1] ?? "")) {
|
|
10
|
+
i++;
|
|
11
|
+
while (i < pattern.length && /\w/.test(pattern[i])) i++;
|
|
12
|
+
regexStr += "[^/]+";
|
|
13
|
+
} else {
|
|
14
|
+
regexStr += ch.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
15
|
+
i++;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return new RegExp(`^${regexStr}$`);
|
|
19
|
+
}
|
|
20
|
+
function headersFileHasCacheControlForPath(content, path) {
|
|
21
|
+
let matchesCurrentSection = false;
|
|
22
|
+
for (const rawLine of content.split("\n")) {
|
|
23
|
+
const trimmed = rawLine.trim();
|
|
24
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
25
|
+
const isSectionHeader = !/^\s/.test(rawLine);
|
|
26
|
+
if (isSectionHeader) {
|
|
27
|
+
const pathOnly = trimmed.replace(/^https?:\/\/[^/]+/, "");
|
|
28
|
+
try {
|
|
29
|
+
matchesCurrentSection = cfHeadersPatternToRegex(pathOnly).test(path);
|
|
30
|
+
} catch {
|
|
31
|
+
matchesCurrentSection = false;
|
|
32
|
+
}
|
|
33
|
+
} else if (matchesCurrentSection && // Either `Cache-Control: value` (set) or `! Cache-Control` (detach).
|
|
34
|
+
/^\s+(?:!\s+cache-control\s*$|cache-control\s*:)/i.test(rawLine)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
async function buildAssetsHeadersContent(opts, readFile) {
|
|
41
|
+
const { assetsDir, basePrefix, headersPath } = opts;
|
|
42
|
+
const assetsPattern = `${basePrefix}/${assetsDir}/*`;
|
|
43
|
+
const probePath = `${basePrefix}/${assetsDir}/probe`;
|
|
44
|
+
let existingHeaders = "";
|
|
45
|
+
try {
|
|
46
|
+
existingHeaders = await readFile(headersPath);
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
if (headersFileHasCacheControlForPath(existingHeaders, probePath)) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const cacheBlock = `${assetsPattern}
|
|
53
|
+
Cache-Control: public, max-age=31536000, immutable
|
|
54
|
+
`;
|
|
55
|
+
const normalizedExisting = existingHeaders && !existingHeaders.endsWith("\n") ? existingHeaders + "\n" : existingHeaders;
|
|
56
|
+
const content = normalizedExisting ? `${cacheBlock}
|
|
57
|
+
${normalizedExisting}` : cacheBlock;
|
|
58
|
+
return { content, assetsPattern };
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
buildAssetsHeadersContent,
|
|
62
|
+
headersFileHasCacheControlForPath
|
|
63
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/cloudflare",
|
|
3
3
|
"description": "Deploy your site to Cloudflare Workers",
|
|
4
|
-
"version": "14.0.0-
|
|
4
|
+
"version": "14.0.0-beta.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"cheerio": "1.2.0",
|
|
56
56
|
"devalue": "^5.8.1",
|
|
57
57
|
"prismjs": "^1.30.0",
|
|
58
|
-
"astro": "7.0.0-
|
|
58
|
+
"astro": "7.0.0-beta.3",
|
|
59
59
|
"astro-scripts": "0.0.14"
|
|
60
60
|
},
|
|
61
61
|
"publishConfig": {
|