@vinext/cloudflare 0.1.2 → 0.2.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 +19 -4
- package/dist/cache/kv-data-adapter.runtime.js +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +73 -0
- package/dist/deploy-config.d.ts +47 -0
- package/dist/deploy-config.js +150 -0
- package/dist/deploy-help.d.ts +5 -0
- package/dist/deploy-help.js +55 -0
- package/dist/deploy.d.ts +70 -0
- package/dist/deploy.js +276 -0
- package/dist/images/images-optimizer.d.ts +28 -0
- package/dist/images/images-optimizer.js +28 -0
- package/dist/images/images-optimizer.runtime.d.ts +16 -0
- package/dist/images/images-optimizer.runtime.js +16 -0
- package/dist/tpr.d.ts +83 -0
- package/dist/tpr.js +561 -0
- package/package.json +28 -4
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# @vinext/cloudflare
|
|
2
2
|
|
|
3
|
-
Cloudflare
|
|
3
|
+
Cloudflare deployment tools and runtime adapters for
|
|
4
|
+
[vinext](https://www.npmjs.com/package/vinext).
|
|
4
5
|
|
|
5
|
-
This package provides
|
|
6
|
-
ISR and the `"use cache"` data cache when deploying to Cloudflare Workers:
|
|
6
|
+
This package provides Cloudflare-specific cache and image backends for vinext:
|
|
7
7
|
|
|
8
8
|
- **`kvDataAdapter()`** (`@vinext/cloudflare/cache/kv-data-adapter`) — backs the
|
|
9
9
|
data cache (`fetch`, `"use cache"`, `unstable_cache`) with a Workers KV
|
|
10
|
-
namespace. Also used for ISR in the absence of a
|
|
10
|
+
namespace. Also used for ISR in the absence of a CDN adapter.
|
|
11
|
+
- **`imagesOptimizer()`** (`@vinext/cloudflare/images/images-optimizer`) — backs
|
|
12
|
+
`next/image` transformations with a Cloudflare Images binding.
|
|
11
13
|
|
|
12
14
|
## Usage
|
|
13
15
|
|
|
@@ -15,6 +17,7 @@ Declare the adapters on the `vinext()` plugin in your Vite config:
|
|
|
15
17
|
|
|
16
18
|
```ts
|
|
17
19
|
import { kvDataAdapter } from "@vinext/cloudflare/cache/kv-data-adapter";
|
|
20
|
+
import { imagesOptimizer } from "@vinext/cloudflare/images/images-optimizer";
|
|
18
21
|
|
|
19
22
|
export default defineConfig({
|
|
20
23
|
plugins: [
|
|
@@ -22,8 +25,20 @@ export default defineConfig({
|
|
|
22
25
|
cache: {
|
|
23
26
|
data: kvDataAdapter(), // KV-backed data cache (binding: VINEXT_KV_CACHE)
|
|
24
27
|
},
|
|
28
|
+
images: { optimizer: imagesOptimizer() }, // Cloudflare Images binding: IMAGES
|
|
25
29
|
}),
|
|
26
30
|
cloudflare(),
|
|
27
31
|
],
|
|
28
32
|
});
|
|
29
33
|
```
|
|
34
|
+
|
|
35
|
+
## Deploy
|
|
36
|
+
|
|
37
|
+
Deploy Cloudflare Workers projects with the package CLI:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
npx @vinext/cloudflare deploy
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
With Vite+, use `vpx @vinext/cloudflare deploy`, or
|
|
44
|
+
`vp exec vinext-cloudflare deploy` when running the locally installed bin.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isUnknownRecord, readCacheControlNumberField } from "../utils/cache-control-metadata.js";
|
|
2
|
-
import { getRequestExecutionContext } from "vinext/shims/request-context";
|
|
3
2
|
import { Buffer } from "node:buffer";
|
|
3
|
+
import { getRequestExecutionContext } from "vinext/shims/request-context";
|
|
4
4
|
//#region src/cache/kv-data-adapter.runtime.ts
|
|
5
5
|
/**
|
|
6
6
|
* Cloudflare KV data cache — implementation + runtime factory.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { deploy, parseDeployArgs } from "./deploy.js";
|
|
3
|
+
import { printDeployHelp } from "./deploy-help.js";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
//#region src/cli.ts
|
|
6
|
+
const VERSION = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf-8")).version;
|
|
7
|
+
const command = process.argv[2];
|
|
8
|
+
const rawArgs = process.argv.slice(3);
|
|
9
|
+
function printHelp(commandName) {
|
|
10
|
+
if (commandName === "deploy") {
|
|
11
|
+
printDeployHelp();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
console.log(`
|
|
15
|
+
vinext-cloudflare v${VERSION}
|
|
16
|
+
|
|
17
|
+
Usage: vinext-cloudflare <command> [options]
|
|
18
|
+
|
|
19
|
+
Vite+:
|
|
20
|
+
vpx @vinext/cloudflare <command> Run by package name
|
|
21
|
+
vp exec vinext-cloudflare <command> Run the locally installed bin
|
|
22
|
+
|
|
23
|
+
Commands:
|
|
24
|
+
deploy Deploy to Cloudflare Workers
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
-h, --help Show this help
|
|
28
|
+
--version Show version
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
async function deployCommand() {
|
|
32
|
+
const parsed = parseDeployArgs(rawArgs);
|
|
33
|
+
if (parsed.help) {
|
|
34
|
+
printHelp("deploy");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
await deploy({
|
|
38
|
+
root: process.cwd(),
|
|
39
|
+
preview: parsed.preview,
|
|
40
|
+
env: parsed.env,
|
|
41
|
+
skipBuild: parsed.skipBuild,
|
|
42
|
+
dryRun: parsed.dryRun,
|
|
43
|
+
name: parsed.name,
|
|
44
|
+
prerenderAll: parsed.prerenderAll,
|
|
45
|
+
prerenderConcurrency: parsed.prerenderConcurrency,
|
|
46
|
+
experimentalTPR: parsed.experimentalTPR,
|
|
47
|
+
tprCoverage: parsed.tprCoverage,
|
|
48
|
+
tprLimit: parsed.tprLimit,
|
|
49
|
+
tprWindow: parsed.tprWindow
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (command === "--version" || command === "-v") {
|
|
53
|
+
console.log(`vinext-cloudflare v${VERSION}`);
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
if (command === "--help" || command === "-h" || !command) {
|
|
57
|
+
printHelp();
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
switch (command) {
|
|
61
|
+
case "deploy":
|
|
62
|
+
deployCommand().catch((error) => {
|
|
63
|
+
console.error(error);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
});
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
console.error(`Unknown command: ${command}`);
|
|
69
|
+
printHelp();
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/deploy-config.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Check whether an existing vite.config file already imports and uses the
|
|
4
|
+
* Cloudflare Vite plugin. This is a heuristic text scan — it doesn't execute
|
|
5
|
+
* the config — so it may produce false negatives for unusual configurations.
|
|
6
|
+
*
|
|
7
|
+
* Returns true when the config both imports the package and invokes
|
|
8
|
+
* `cloudflare(...)` in the plugin list.
|
|
9
|
+
*/
|
|
10
|
+
declare function viteConfigHasCloudflarePlugin(root: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Detect whether the Vite config assigns a CDN or data cache adapter — i.e. the
|
|
13
|
+
* `cdn` or `data` field of the `vinext({ cache })` option is given a value.
|
|
14
|
+
* This is a source-level check on those exact object fields, not a fuzzy scan
|
|
15
|
+
* for adapter names. Mirrors {@link viteConfigHasCloudflarePlugin}'s leniency:
|
|
16
|
+
* an unreadable or absent config is treated as configured so a deploy is never
|
|
17
|
+
* blocked on a false negative.
|
|
18
|
+
*/
|
|
19
|
+
declare function viteConfigHasCacheAdapter(root: string): boolean;
|
|
20
|
+
declare function viteConfigHasImageAdapter(root: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Detect whether an existing user-authored Worker entry wires up a cache
|
|
23
|
+
* backend imperatively via one of the `setCacheHandler` / `setDataCacheHandler`
|
|
24
|
+
* / `setCdnCacheAdapter` setters. These setters are deprecated in favour of the
|
|
25
|
+
* declarative `vinext({ cache })` option, but older apps that scaffolded a KV
|
|
26
|
+
* cache handler into their Worker entry must keep working — so a deploy should
|
|
27
|
+
* not be blocked when the Worker entry already configures a backend.
|
|
28
|
+
*
|
|
29
|
+
* This is a heuristic text scan (it doesn't execute the entry), mirroring
|
|
30
|
+
* {@link viteConfigHasCacheAdapter}'s leniency: an unreadable Worker entry is
|
|
31
|
+
* treated as configured so a deploy is never blocked on a false negative. A
|
|
32
|
+
* missing Worker entry returns false (nothing to inspect — defer to other
|
|
33
|
+
* checks).
|
|
34
|
+
*/
|
|
35
|
+
declare function workerEntryHasCacheHandler(root: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Build the error thrown when an ISR/cached app is deployed without a cache
|
|
38
|
+
* adapter configured in the Vite config. Production deployments need a
|
|
39
|
+
* persistent cache backend; vinext no longer scaffolds one into the Worker
|
|
40
|
+
* entry, so it must be declared via `vinext({ cache })`.
|
|
41
|
+
*/
|
|
42
|
+
declare function formatMissingCacheAdapterError(options: {
|
|
43
|
+
configFile?: string;
|
|
44
|
+
}): string;
|
|
45
|
+
declare function formatImageOptimizationHint(): string;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { formatImageOptimizationHint, formatMissingCacheAdapterError, viteConfigHasCacheAdapter, viteConfigHasCloudflarePlugin, viteConfigHasImageAdapter, workerEntryHasCacheHandler };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { findViteConfigPath } from "vinext/internal/utils/project";
|
|
4
|
+
//#region src/deploy-config.ts
|
|
5
|
+
function escapeRegExp(value) {
|
|
6
|
+
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Check whether an existing vite.config file already imports and uses the
|
|
10
|
+
* Cloudflare Vite plugin. This is a heuristic text scan — it doesn't execute
|
|
11
|
+
* the config — so it may produce false negatives for unusual configurations.
|
|
12
|
+
*
|
|
13
|
+
* Returns true when the config both imports the package and invokes
|
|
14
|
+
* `cloudflare(...)` in the plugin list.
|
|
15
|
+
*/
|
|
16
|
+
function viteConfigHasCloudflarePlugin(root) {
|
|
17
|
+
const configPath = findViteConfigPath(root);
|
|
18
|
+
if (!configPath) return false;
|
|
19
|
+
try {
|
|
20
|
+
const content = fs.readFileSync(configPath, "utf-8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
21
|
+
const requireBinding = content.match(/(?:const|let|var)\s*{([^}]*)}\s*=\s*require\s*\(\s*["']@cloudflare\/vite-plugin["']\s*\)/)?.[1];
|
|
22
|
+
if (requireBinding) {
|
|
23
|
+
const requireMatch = requireBinding.match(/(?:^|,)\s*cloudflare\s*(?::\s*([A-Za-z_$][\w$]*))?\s*(?:,|$)/);
|
|
24
|
+
if (requireMatch) {
|
|
25
|
+
const binding = requireMatch[1] ?? "cloudflare";
|
|
26
|
+
return new RegExp(`\\b${escapeRegExp(binding)}\\s*\\(`).test(content);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const namedImports = content.match(/import\s*{([^}]*)}\s*from\s*["']@cloudflare\/vite-plugin["']/)?.[1];
|
|
30
|
+
if (!namedImports) return false;
|
|
31
|
+
const importMatch = namedImports.match(/(?:^|,)\s*cloudflare\s*(?:as\s+([A-Za-z_$][\w$]*))?\s*(?:,|$)/);
|
|
32
|
+
if (!importMatch) return false;
|
|
33
|
+
const binding = importMatch[1] ?? "cloudflare";
|
|
34
|
+
return new RegExp(`\\b${escapeRegExp(binding)}\\s*\\(`).test(content);
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Extract the object-literal text of the `cache:` key (the `{ ... }` passed as
|
|
41
|
+
* `vinext({ cache })`) from a Vite config source, via brace matching. Returns
|
|
42
|
+
* null if there is no `cache:` object literal.
|
|
43
|
+
*/
|
|
44
|
+
function extractCacheBlock(content) {
|
|
45
|
+
const m = /\bcache\s*:\s*\{/.exec(content);
|
|
46
|
+
if (!m) return null;
|
|
47
|
+
const open = m.index + m[0].length - 1;
|
|
48
|
+
let depth = 0;
|
|
49
|
+
for (let i = open; i < content.length; i++) {
|
|
50
|
+
const ch = content[i];
|
|
51
|
+
if (ch === "{") depth++;
|
|
52
|
+
else if (ch === "}" && --depth === 0) return content.slice(open, i + 1);
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether a `cdn` / `data` field inside the cache object is assigned a real
|
|
58
|
+
* value (not absent, `undefined`, or `null`). Reads the value up to the next
|
|
59
|
+
* comma / closing brace / newline, which is enough to tell an assignment like
|
|
60
|
+
* `data: kvDataAdapter()` from `data: undefined`.
|
|
61
|
+
*/
|
|
62
|
+
function cacheFieldAssigned(cacheBlock, field) {
|
|
63
|
+
const m = new RegExp(`\\b${field}\\s*:\\s*([^,}\\n]+)`).exec(cacheBlock);
|
|
64
|
+
if (!m) return false;
|
|
65
|
+
const value = m[1].trim();
|
|
66
|
+
return value.length > 0 && value !== "undefined" && value !== "null";
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Detect whether the Vite config assigns a CDN or data cache adapter — i.e. the
|
|
70
|
+
* `cdn` or `data` field of the `vinext({ cache })` option is given a value.
|
|
71
|
+
* This is a source-level check on those exact object fields, not a fuzzy scan
|
|
72
|
+
* for adapter names. Mirrors {@link viteConfigHasCloudflarePlugin}'s leniency:
|
|
73
|
+
* an unreadable or absent config is treated as configured so a deploy is never
|
|
74
|
+
* blocked on a false negative.
|
|
75
|
+
*/
|
|
76
|
+
function viteConfigHasCacheAdapter(root) {
|
|
77
|
+
const configPath = findViteConfigPath(root);
|
|
78
|
+
if (!configPath) return true;
|
|
79
|
+
let content;
|
|
80
|
+
try {
|
|
81
|
+
content = fs.readFileSync(configPath, "utf-8");
|
|
82
|
+
} catch {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const block = extractCacheBlock(content);
|
|
86
|
+
if (!block) return false;
|
|
87
|
+
return cacheFieldAssigned(block, "cdn") || cacheFieldAssigned(block, "data");
|
|
88
|
+
}
|
|
89
|
+
function viteConfigHasImageAdapter(root) {
|
|
90
|
+
const configPath = findViteConfigPath(root);
|
|
91
|
+
if (!configPath) return true;
|
|
92
|
+
try {
|
|
93
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
94
|
+
const match = /\bimages\s*:\s*\{/.exec(content);
|
|
95
|
+
if (!match) return false;
|
|
96
|
+
const open = match.index + match[0].length - 1;
|
|
97
|
+
let depth = 0;
|
|
98
|
+
for (let index = open; index < content.length; index++) if (content[index] === "{") depth++;
|
|
99
|
+
else if (content[index] === "}" && --depth === 0) {
|
|
100
|
+
const optimizer = /\boptimizer\s*:\s*([^,}\n]+)/.exec(content.slice(open, index + 1))?.[1];
|
|
101
|
+
return Boolean(optimizer && !/^(?:undefined|null)$/.test(optimizer.trim()));
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
} catch {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Detect whether an existing user-authored Worker entry wires up a cache
|
|
110
|
+
* backend imperatively via one of the `setCacheHandler` / `setDataCacheHandler`
|
|
111
|
+
* / `setCdnCacheAdapter` setters. These setters are deprecated in favour of the
|
|
112
|
+
* declarative `vinext({ cache })` option, but older apps that scaffolded a KV
|
|
113
|
+
* cache handler into their Worker entry must keep working — so a deploy should
|
|
114
|
+
* not be blocked when the Worker entry already configures a backend.
|
|
115
|
+
*
|
|
116
|
+
* This is a heuristic text scan (it doesn't execute the entry), mirroring
|
|
117
|
+
* {@link viteConfigHasCacheAdapter}'s leniency: an unreadable Worker entry is
|
|
118
|
+
* treated as configured so a deploy is never blocked on a false negative. A
|
|
119
|
+
* missing Worker entry returns false (nothing to inspect — defer to other
|
|
120
|
+
* checks).
|
|
121
|
+
*/
|
|
122
|
+
function workerEntryHasCacheHandler(root) {
|
|
123
|
+
const candidates = [path.join(root, "worker", "index.ts"), path.join(root, "worker", "index.js")];
|
|
124
|
+
for (const candidate of candidates) {
|
|
125
|
+
if (!fs.existsSync(candidate)) continue;
|
|
126
|
+
let content;
|
|
127
|
+
try {
|
|
128
|
+
content = fs.readFileSync(candidate, "utf-8");
|
|
129
|
+
} catch {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
return /\b(?:setCacheHandler|setDataCacheHandler|setCdnCacheAdapter)\s*\(/.test(content);
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build the error thrown when an ISR/cached app is deployed without a cache
|
|
138
|
+
* adapter configured in the Vite config. Production deployments need a
|
|
139
|
+
* persistent cache backend; vinext no longer scaffolds one into the Worker
|
|
140
|
+
* entry, so it must be declared via `vinext({ cache })`.
|
|
141
|
+
*/
|
|
142
|
+
function formatMissingCacheAdapterError(options) {
|
|
143
|
+
const configRef = options.configFile ? options.configFile : "your Vite config";
|
|
144
|
+
return `[vinext] This app uses ISR / caching but no cache adapter is configured in ${configRef}.\n\n Production deployments need a persistent cache backend. Declare one on the\n vinext() plugin in ${configRef}:\n\n import { kvDataAdapter } from "@vinext/cloudflare/cache/kv-data-adapter";\n\n export default defineConfig({\n plugins: [\n vinext({\n cache: {\n data: kvDataAdapter(), // KV-backed data cache (binding: VINEXT_KV_CACHE)\n },\n }),\n cloudflare(),\n ],\n });\n\n The VINEXT_KV_CACHE namespace binding is added to wrangler.jsonc for you.\n Create the namespace with:\n\n npx wrangler kv namespace create VINEXT_KV_CACHE`;
|
|
145
|
+
}
|
|
146
|
+
function formatImageOptimizationHint() {
|
|
147
|
+
return " [vinext] next/image is served unoptimized. To enable edge image\n optimization via Cloudflare Images, run:\n\n vinext init --platform=cloudflare --image-optimization=cloudflare-images\n\n This adds the imagesOptimizer() option to your Vite config and the matching\n IMAGES binding to your Wrangler config without replacing existing settings.";
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
export { formatImageOptimizationHint, formatMissingCacheAdapterError, viteConfigHasCacheAdapter, viteConfigHasCloudflarePlugin, viteConfigHasImageAdapter, workerEntryHasCacheHandler };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/deploy-help.ts
|
|
2
|
+
function formatDeployHelp() {
|
|
3
|
+
return `
|
|
4
|
+
vinext-cloudflare deploy - Deploy to Cloudflare Workers
|
|
5
|
+
|
|
6
|
+
Usage: vinext-cloudflare deploy [options]
|
|
7
|
+
|
|
8
|
+
One-command deployment to Cloudflare Workers. Automatically:
|
|
9
|
+
- Detects App Router or Pages Router
|
|
10
|
+
- Validates setup from vinext init --platform=cloudflare
|
|
11
|
+
- Builds the project with Vite
|
|
12
|
+
- Deploys via wrangler
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--preview Deploy to preview environment (same as --env preview)
|
|
16
|
+
--env <name> Deploy using wrangler env.<name>
|
|
17
|
+
--name <name> Custom Worker name (default: from package.json)
|
|
18
|
+
--skip-build Skip the build step (use existing dist/)
|
|
19
|
+
--dry-run Validate setup without building or deploying
|
|
20
|
+
--prerender-all Pre-render discovered routes after building (future
|
|
21
|
+
releases will auto-populate the remote cache)
|
|
22
|
+
--prerender-concurrency <count>
|
|
23
|
+
Maximum number of routes to pre-render in parallel
|
|
24
|
+
-h, --help Show this help
|
|
25
|
+
|
|
26
|
+
Experimental:
|
|
27
|
+
--experimental-tpr Enable Traffic-aware Pre-Rendering
|
|
28
|
+
--tpr-coverage <pct> Traffic coverage target, 0-100 (default: 90)
|
|
29
|
+
--tpr-limit <count> Hard cap on pages to pre-render (default: 1000)
|
|
30
|
+
--tpr-window <hours> Analytics lookback window in hours (default: 24)
|
|
31
|
+
|
|
32
|
+
TPR (Traffic-aware Pre-Rendering) uses Cloudflare zone analytics to determine
|
|
33
|
+
which pages get the most traffic and pre-renders them into KV cache during
|
|
34
|
+
deploy. This feature is experimental and must be explicitly enabled. Requires
|
|
35
|
+
a custom domain (zone analytics are unavailable on *.workers.dev) and the
|
|
36
|
+
CLOUDFLARE_API_TOKEN environment variable with Zone.Analytics read permission.
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
npx @vinext/cloudflare deploy Build and deploy to production
|
|
40
|
+
vpx @vinext/cloudflare deploy Build and deploy with Vite+
|
|
41
|
+
vp exec vinext-cloudflare deploy Run the locally installed Vite+ bin
|
|
42
|
+
vinext-cloudflare deploy --preview Deploy to a preview URL
|
|
43
|
+
vinext-cloudflare deploy --env staging Deploy using wrangler env.staging
|
|
44
|
+
vinext-cloudflare deploy --dry-run Validate setup without building or deploying
|
|
45
|
+
vinext-cloudflare deploy --name my-app Deploy with a custom Worker name
|
|
46
|
+
vinext-cloudflare deploy --experimental-tpr Enable TPR during deploy
|
|
47
|
+
vinext-cloudflare deploy --experimental-tpr --tpr-coverage 95 Cover 95% of traffic
|
|
48
|
+
vinext-cloudflare deploy --experimental-tpr --tpr-limit 500 Cap at 500 pages
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
function printDeployHelp() {
|
|
52
|
+
console.log(formatDeployHelp());
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { formatDeployHelp, printDeployHelp };
|
package/dist/deploy.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
//#region src/deploy.d.ts
|
|
4
|
+
type DeployOptions = {
|
|
5
|
+
/** Project root directory */root: string; /** Deploy to preview environment (default: production) */
|
|
6
|
+
preview?: boolean; /** Wrangler environment name from wrangler.jsonc env.<name> */
|
|
7
|
+
env?: string; /** Custom project name for the Worker */
|
|
8
|
+
name?: string; /** Skip the build step (assume already built) */
|
|
9
|
+
skipBuild?: boolean; /** Dry run — validate setup but don't build or deploy */
|
|
10
|
+
dryRun?: boolean; /** Pre-render all discovered routes into the dist output after building */
|
|
11
|
+
prerenderAll?: boolean; /** Maximum number of routes to prerender in parallel */
|
|
12
|
+
prerenderConcurrency?: number; /** Enable experimental TPR (Traffic-aware Pre-Rendering) */
|
|
13
|
+
experimentalTPR?: boolean; /** TPR: traffic coverage percentage target (0–100, default: 90) */
|
|
14
|
+
tprCoverage?: number; /** TPR: hard cap on number of pages to pre-render (default: 1000) */
|
|
15
|
+
tprLimit?: number; /** TPR: analytics lookback window in hours (default: 24) */
|
|
16
|
+
tprWindow?: number;
|
|
17
|
+
};
|
|
18
|
+
declare function parseDeployArgs(args: string[]): {
|
|
19
|
+
help: boolean;
|
|
20
|
+
preview: boolean;
|
|
21
|
+
env: string | undefined;
|
|
22
|
+
name: string | undefined;
|
|
23
|
+
skipBuild: boolean;
|
|
24
|
+
dryRun: boolean;
|
|
25
|
+
prerenderAll: boolean;
|
|
26
|
+
prerenderConcurrency: number | undefined;
|
|
27
|
+
experimentalTPR: boolean;
|
|
28
|
+
tprCoverage: number | undefined;
|
|
29
|
+
tprLimit: number | undefined;
|
|
30
|
+
tprWindow: number | undefined;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Run a function with `process.env.CLOUDFLARE_ENV` set to the given value,
|
|
34
|
+
* restoring the previous state (whether set or absent) after the function
|
|
35
|
+
* resolves or throws.
|
|
36
|
+
*
|
|
37
|
+
* The `@cloudflare/vite-plugin` reads `CLOUDFLARE_ENV` from `process.env` to
|
|
38
|
+
* drive the multi-environment merge applied to the emitted `wrangler.json`.
|
|
39
|
+
* Without this propagation the `--env <name>` CLI flag is silently ignored at
|
|
40
|
+
* build time and the top-level config is emitted regardless. See issue #1210.
|
|
41
|
+
*
|
|
42
|
+
* Passing `undefined` is a no-op; the callback runs with `process.env` untouched.
|
|
43
|
+
*/
|
|
44
|
+
declare function withCloudflareEnv<T>(env: string | undefined, fn: () => Promise<T>): Promise<T>;
|
|
45
|
+
type WranglerDeployArgs = {
|
|
46
|
+
args: string[];
|
|
47
|
+
env: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
declare function validateWranglerEnvName(env: string): string;
|
|
50
|
+
declare function buildWranglerDeployArgs(options: Pick<DeployOptions, "preview" | "env">): WranglerDeployArgs;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve Wrangler's JavaScript CLI entrypoint in node_modules.
|
|
53
|
+
*
|
|
54
|
+
* Invoking the JavaScript file through `process.execPath` avoids the `.cmd`
|
|
55
|
+
* shim and command shell that package managers create on Windows.
|
|
56
|
+
*/
|
|
57
|
+
declare function resolveWranglerBin(root: string, resolvePackageJson?: (root: string) => string | null): string;
|
|
58
|
+
declare function buildNodeCliInvocation(scriptPath: string, args: string[], nodeExecutable?: string): {
|
|
59
|
+
file: string;
|
|
60
|
+
args: string[];
|
|
61
|
+
};
|
|
62
|
+
declare function buildWranglerInvocation(root: string, options: Pick<DeployOptions, "preview" | "env">, nodeExecutable?: string): {
|
|
63
|
+
file: string;
|
|
64
|
+
args: string[];
|
|
65
|
+
env: string | undefined;
|
|
66
|
+
};
|
|
67
|
+
declare function runWranglerDeploy(root: string, options: Pick<DeployOptions, "preview" | "env">, execute?: typeof execFileSync): string;
|
|
68
|
+
declare function deploy(options: DeployOptions): Promise<void>;
|
|
69
|
+
//#endregion
|
|
70
|
+
export { DeployOptions, buildNodeCliInvocation, buildWranglerDeployArgs, buildWranglerInvocation, deploy, parseDeployArgs, resolveWranglerBin, runWranglerDeploy, validateWranglerEnvName, withCloudflareEnv };
|