@vinext/cloudflare 1.0.0-beta.9 → 1.0.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 +165 -37
- package/dist/cache/cdn-adapter-config.d.ts +2 -1
- package/dist/cache/cdn-adapter-config.js +13 -5
- package/dist/cache/cdn-adapter.d.ts +5 -56
- package/dist/cache/cdn-adapter.js +3 -61
- package/dist/cache/cdn-adapter.runtime.d.ts +1 -0
- package/dist/cache/cdn-adapter.runtime.js +17 -3
- package/dist/cache/cdn-build-id.d.ts +1 -1
- package/dist/cache/cdn-build-id.js +1 -1
- package/dist/cache/config.d.ts +137 -0
- package/dist/cache/config.js +87 -0
- package/dist/cache/kv-data-adapter.d.ts +1 -1
- package/dist/cache/kv-data-adapter.js +1 -1
- package/dist/cache/kv-data-adapter.runtime.js +13 -9
- package/dist/cache/kv-key.d.ts +7 -4
- package/dist/cache/kv-key.js +16 -5
- package/dist/cache/response-store-adapter.d.ts +9 -6
- package/dist/cache/response-store-adapter.js +20 -1
- package/dist/cache/response-store-adapter.worker.js +100 -43
- package/dist/cache/response-store-cdn.runtime.js +1 -0
- package/dist/cache/response-store-data.runtime.js +53 -31
- package/dist/cache/static-assets-adapter.build.d.ts +6 -0
- package/dist/cache/static-assets-adapter.build.js +65 -0
- package/dist/cache/static-assets-adapter.d.ts +27 -0
- package/dist/cache/static-assets-adapter.js +26 -0
- package/dist/cache/static-assets-adapter.runtime.d.ts +26 -0
- package/dist/cache/static-assets-adapter.runtime.js +77 -0
- package/dist/cache/static-assets-adapter.shared.d.ts +12 -0
- package/dist/cache/static-assets-adapter.shared.js +4 -0
- package/dist/cache/workers-cache-cdn-adapter.d.ts +58 -0
- package/dist/cache/workers-cache-cdn-adapter.js +65 -0
- package/dist/cacheability-artifact.d.ts +7 -1
- package/dist/cacheability-artifact.js +60 -21
- package/dist/cacheability-probe.d.ts +2 -0
- package/dist/cacheability-probe.js +107 -13
- package/dist/cdn-warm.d.ts +1 -0
- package/dist/cdn-warm.js +2 -1
- package/dist/deploy-config.d.ts +3 -8
- package/dist/deploy-config.js +5 -23
- package/dist/deploy-help.js +47 -42
- package/dist/deploy.d.ts +18 -16
- package/dist/deploy.js +355 -216
- package/dist/tpr.d.ts +4 -0
- package/dist/tpr.js +16 -7
- package/dist/version-deploy.d.ts +27 -0
- package/dist/version-deploy.js +121 -3
- package/dist/wrangler-version-metadata.js +1 -1
- package/package.json +16 -5
- package/dist/prerender-kv-populate.d.ts +0 -24
- package/dist/prerender-kv-populate.js +0 -153
package/dist/deploy.js
CHANGED
|
@@ -4,11 +4,10 @@ import { CdnOperationProgress, createCdnWarmTargets, createPrerenderWarmPlan, wa
|
|
|
4
4
|
import { parseWranglerConfig } from "./wrangler-config.js";
|
|
5
5
|
import { resolveTPRRoutes, selectRoutes } from "./tpr.js";
|
|
6
6
|
import { VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "./version-headers.js";
|
|
7
|
-
import { formatImageOptimizationHint, formatMissingCacheAdapterError, resolveCdnAdapterConfig,
|
|
7
|
+
import { formatImageOptimizationHint, formatMissingCacheAdapterError, resolveCdnAdapterConfig, viteConfigHasCacheAdapter, viteConfigHasCloudflarePlugin, viteConfigHasImageAdapter, workerEntryHasCacheHandler } from "./deploy-config.js";
|
|
8
8
|
import { assertCdnVersionMetadataConfig } from "./wrangler-version-metadata.js";
|
|
9
9
|
import { parseWorkerDeploymentUrl } from "./worker-deployment-url.js";
|
|
10
|
-
import { runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload } from "./version-deploy.js";
|
|
11
|
-
import { buildPrerenderKVPairs } from "./prerender-kv-populate.js";
|
|
10
|
+
import { readBuildOutputWorkerName, runCfDeploymentStatus, runCfTriggersDeploy, runCfVersionDeploy, runCfVersionUpload, runWranglerDeploymentStatus, runWranglerTriggersDeploy, runWranglerVersionDeploy, runWranglerVersionUpload } from "./version-deploy.js";
|
|
12
11
|
import { createRequire } from "node:module";
|
|
13
12
|
import fs from "node:fs";
|
|
14
13
|
import path from "node:path";
|
|
@@ -16,14 +15,15 @@ import { cacheabilityRoutePathname } from "vinext/internal/server/cacheability-m
|
|
|
16
15
|
import { setTimeout } from "node:timers/promises";
|
|
17
16
|
import { DEFAULT_REMOTE_PATH_DISCOVERY_PHASE_TIMEOUT_MS, DEFAULT_REMOTE_PATH_DISCOVERY_RETRY_DELAY_MS, discoverPrerenderPathManifest, emitPrerenderPathManifest } from "vinext/internal/build/prerender-paths";
|
|
18
17
|
import { normalizePathTrailingSlash } from "vinext/shims/url-utils";
|
|
19
|
-
import os from "node:os";
|
|
20
18
|
import { spawn } from "node:child_process";
|
|
21
19
|
import { parseArgs } from "node:util";
|
|
22
20
|
import { pathToFileURL } from "node:url";
|
|
21
|
+
import { VINEXT_BUILD_LIFECYCLE_CONFIG } from "vinext/internal/build/lifecycle";
|
|
23
22
|
import { runPrerender } from "vinext/internal/build/run-prerender";
|
|
23
|
+
import { printBuildReport } from "vinext/internal/build/report";
|
|
24
24
|
import { loadDotenv } from "vinext/internal/config/dotenv";
|
|
25
25
|
import { findVinextNextConfigInPlugins, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "vinext/internal/config/next-config";
|
|
26
|
-
import { cacheWarmupStatusSource, findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision, supportsCanonicalRscWarmup } from "vinext/internal/config/prerender";
|
|
26
|
+
import { cacheWarmupStatusSource, finalizeCacheAdapterPrerenderOutput, findVinextCacheConfigInPlugins, findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, hasBuildIdentityResponseHeader, hasCacheAdapterPrerenderOutput, hasUncachedRequestRouting, hasVerbatimResponseVary, isConfiguredCdnResponsePolicyHeader, requiresRouteCacheabilityProbeManifest, resolveVinextPrerenderDecision, supportsCanonicalRscWarmup } from "vinext/internal/config/prerender";
|
|
27
27
|
import { detectProject, findInNodeModules, formatMissingCloudflarePluginError, getMissingDeps } from "vinext/internal/utils/project";
|
|
28
28
|
import { PHASE_PRODUCTION_BUILD } from "vinext/shims/constants";
|
|
29
29
|
//#region src/deploy.ts
|
|
@@ -37,6 +37,17 @@ import { PHASE_PRODUCTION_BUILD } from "vinext/shims/constants";
|
|
|
37
37
|
* 3. Deploys to Cloudflare Workers via Wrangler
|
|
38
38
|
*/
|
|
39
39
|
const DEFAULT_CDN_WARM_PROMOTION_DELAY_MS = 15e3;
|
|
40
|
+
/** The typed cf Vite plugin emits Worker and asset bundles into Build Output. */
|
|
41
|
+
function resolvePrerenderOutputDirs(root, deploymentTool, configured) {
|
|
42
|
+
if (deploymentTool !== "cf") return configured;
|
|
43
|
+
const workerDir = path.join(root, ".cloudflare", "output", "v0", "workers", "default");
|
|
44
|
+
if (!fs.existsSync(path.join(workerDir, "worker.config.json"))) return configured;
|
|
45
|
+
return {
|
|
46
|
+
...configured,
|
|
47
|
+
rscOutDir: path.join(workerDir, "bundle"),
|
|
48
|
+
clientOutDir: path.join(workerDir, "assets")
|
|
49
|
+
};
|
|
50
|
+
}
|
|
40
51
|
function parsePositiveIntegerArg(raw, flag) {
|
|
41
52
|
if (raw === "") throw new Error(`${flag} requires a value, but none was provided.`);
|
|
42
53
|
const parsed = Number(raw);
|
|
@@ -56,7 +67,7 @@ function validateTimerDelay(value, flag, raw = String(value)) {
|
|
|
56
67
|
return value;
|
|
57
68
|
}
|
|
58
69
|
function validatePromotionDelay(value, raw = String(value)) {
|
|
59
|
-
return validateTimerDelay(value, "--warm-
|
|
70
|
+
return validateTimerDelay(value, "--warm-cache-promotion-delay", raw);
|
|
60
71
|
}
|
|
61
72
|
function validateCdnWarmTarget(raw) {
|
|
62
73
|
const value = raw.trim();
|
|
@@ -64,9 +75,9 @@ function validateCdnWarmTarget(raw) {
|
|
|
64
75
|
try {
|
|
65
76
|
url = new URL(value);
|
|
66
77
|
} catch {
|
|
67
|
-
throw new Error(`--warm-
|
|
78
|
+
throw new Error(`--warm-cache-target expects an HTTPS origin, but got "${raw}".`);
|
|
68
79
|
}
|
|
69
|
-
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") throw new Error(`--warm-
|
|
80
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") throw new Error(`--warm-cache-target expects an HTTPS origin without a path, query, credentials, or port, but got "${raw}".`);
|
|
70
81
|
return url.origin;
|
|
71
82
|
}
|
|
72
83
|
function formatUnknownError(error) {
|
|
@@ -105,6 +116,54 @@ const deployArgOptions = {
|
|
|
105
116
|
default: false
|
|
106
117
|
},
|
|
107
118
|
"prerender-concurrency": { type: "string" },
|
|
119
|
+
"warm-cache": {
|
|
120
|
+
type: "boolean",
|
|
121
|
+
default: false
|
|
122
|
+
},
|
|
123
|
+
"warm-cache-target": { type: "string" },
|
|
124
|
+
"warm-cache-concurrency": { type: "string" },
|
|
125
|
+
"warm-cache-timeout": { type: "string" },
|
|
126
|
+
"warm-cache-retries": { type: "string" },
|
|
127
|
+
"warm-cache-discovery-timeout": { type: "string" },
|
|
128
|
+
"warm-cache-discovery-retries": { type: "string" },
|
|
129
|
+
"warm-cache-probe-timeout": { type: "string" },
|
|
130
|
+
"warm-cache-probe-retries": { type: "string" },
|
|
131
|
+
"warm-cache-certify": {
|
|
132
|
+
type: "boolean",
|
|
133
|
+
default: false
|
|
134
|
+
},
|
|
135
|
+
"warm-cache-readiness-timeout": { type: "string" },
|
|
136
|
+
"warm-cache-readiness-retries": { type: "string" },
|
|
137
|
+
"warm-cache-readiness-probes": { type: "string" },
|
|
138
|
+
"warm-cache-readiness-probe-delay": { type: "string" },
|
|
139
|
+
"dangerously-promote-on-warm-cache-error": {
|
|
140
|
+
type: "boolean",
|
|
141
|
+
default: false
|
|
142
|
+
},
|
|
143
|
+
"no-promote": {
|
|
144
|
+
type: "boolean",
|
|
145
|
+
default: false
|
|
146
|
+
},
|
|
147
|
+
"warm-cache-no-promote": {
|
|
148
|
+
type: "boolean",
|
|
149
|
+
default: false
|
|
150
|
+
},
|
|
151
|
+
"warm-cache-promotion-delay": { type: "string" },
|
|
152
|
+
"warm-cache-include-fallbacks": {
|
|
153
|
+
type: "boolean",
|
|
154
|
+
default: false
|
|
155
|
+
},
|
|
156
|
+
"traffic-aware-warm-cache": {
|
|
157
|
+
type: "boolean",
|
|
158
|
+
default: false
|
|
159
|
+
},
|
|
160
|
+
"traffic-aware-coverage": { type: "string" },
|
|
161
|
+
"traffic-aware-limit": { type: "string" },
|
|
162
|
+
"traffic-aware-window": { type: "string" },
|
|
163
|
+
"dangerously-promote-on-cdn-warm-error": {
|
|
164
|
+
type: "boolean",
|
|
165
|
+
default: false
|
|
166
|
+
},
|
|
108
167
|
"experimental-warm-cdn-cache": {
|
|
109
168
|
type: "boolean",
|
|
110
169
|
default: false
|
|
@@ -125,14 +184,6 @@ const deployArgOptions = {
|
|
|
125
184
|
"warm-cdn-readiness-retries": { type: "string" },
|
|
126
185
|
"warm-cdn-readiness-probes": { type: "string" },
|
|
127
186
|
"warm-cdn-readiness-probe-delay": { type: "string" },
|
|
128
|
-
"dangerously-promote-on-cdn-warm-error": {
|
|
129
|
-
type: "boolean",
|
|
130
|
-
default: false
|
|
131
|
-
},
|
|
132
|
-
"no-promote": {
|
|
133
|
-
type: "boolean",
|
|
134
|
-
default: false
|
|
135
|
-
},
|
|
136
187
|
"warm-cdn-no-promote": {
|
|
137
188
|
type: "boolean",
|
|
138
189
|
default: false
|
|
@@ -146,9 +197,6 @@ const deployArgOptions = {
|
|
|
146
197
|
type: "boolean",
|
|
147
198
|
default: false
|
|
148
199
|
},
|
|
149
|
-
"traffic-aware-coverage": { type: "string" },
|
|
150
|
-
"traffic-aware-limit": { type: "string" },
|
|
151
|
-
"traffic-aware-window": { type: "string" },
|
|
152
200
|
"experimental-tpr": {
|
|
153
201
|
type: "boolean",
|
|
154
202
|
default: false
|
|
@@ -163,8 +211,29 @@ function parseDeployArgs(args) {
|
|
|
163
211
|
options: deployArgOptions,
|
|
164
212
|
strict: true
|
|
165
213
|
});
|
|
166
|
-
|
|
167
|
-
|
|
214
|
+
values["dangerously-promote-on-warm-cache-error"] ||= values["dangerously-promote-on-cdn-warm-error"];
|
|
215
|
+
values["warm-cache"] ||= values["experimental-warm-cdn-cache"];
|
|
216
|
+
values["warm-cache-target"] ??= values["warm-cdn-target"];
|
|
217
|
+
values["warm-cache-concurrency"] ??= values["warm-cdn-concurrency"];
|
|
218
|
+
values["warm-cache-timeout"] ??= values["warm-cdn-timeout"];
|
|
219
|
+
values["warm-cache-retries"] ??= values["warm-cdn-retries"];
|
|
220
|
+
values["warm-cache-discovery-timeout"] ??= values["warm-cdn-discovery-timeout"];
|
|
221
|
+
values["warm-cache-discovery-retries"] ??= values["warm-cdn-discovery-retries"];
|
|
222
|
+
values["warm-cache-probe-timeout"] ??= values["warm-cdn-probe-timeout"];
|
|
223
|
+
values["warm-cache-probe-retries"] ??= values["warm-cdn-probe-retries"];
|
|
224
|
+
values["warm-cache-certify"] ||= values["warm-cdn-certify"];
|
|
225
|
+
values["warm-cache-readiness-timeout"] ??= values["warm-cdn-readiness-timeout"];
|
|
226
|
+
values["warm-cache-readiness-retries"] ??= values["warm-cdn-readiness-retries"];
|
|
227
|
+
values["warm-cache-readiness-probes"] ??= values["warm-cdn-readiness-probes"];
|
|
228
|
+
values["warm-cache-readiness-probe-delay"] ??= values["warm-cdn-readiness-probe-delay"];
|
|
229
|
+
values["warm-cache-no-promote"] ||= values["warm-cdn-no-promote"];
|
|
230
|
+
values["warm-cache-promotion-delay"] ??= values["warm-cdn-promotion-delay"];
|
|
231
|
+
values["warm-cache-include-fallbacks"] ||= values["warm-cdn-include-fallbacks"];
|
|
232
|
+
values["traffic-aware-warm-cache"] ||= values["experimental-traffic-aware-warm-cache"];
|
|
233
|
+
const trafficAwareWarmCache = values["traffic-aware-warm-cache"] || values["experimental-tpr"];
|
|
234
|
+
const warming = values["warm-cache"] || trafficAwareWarmCache;
|
|
235
|
+
if (values["warm-cache-certify"] && !warming) throw new Error("--warm-cache-certify requires --warm-cache or --traffic-aware-warm-cache.");
|
|
236
|
+
if (values["warm-cache-target"] && !warming) throw new Error("--warm-cache-target requires --warm-cache or --traffic-aware-warm-cache.");
|
|
168
237
|
function parseIntArg(name, raw) {
|
|
169
238
|
if (!raw) return void 0;
|
|
170
239
|
const n = parseInt(raw, 10);
|
|
@@ -185,25 +254,25 @@ function parseDeployArgs(args) {
|
|
|
185
254
|
verbose: values.verbose,
|
|
186
255
|
prerenderAll: values["prerender-all"],
|
|
187
256
|
prerenderConcurrency: values["prerender-concurrency"] === void 0 ? void 0 : parsePositiveIntegerArg(values["prerender-concurrency"], "--prerender-concurrency"),
|
|
188
|
-
warmCdnCache: values["
|
|
189
|
-
warmCdnTarget: values["warm-
|
|
190
|
-
warmCdnConcurrency: values["warm-
|
|
191
|
-
warmCdnTimeout: values["warm-
|
|
192
|
-
warmCdnRetries: values["warm-
|
|
193
|
-
warmCdnDiscoveryTimeout: values["warm-
|
|
194
|
-
warmCdnDiscoveryRetries: values["warm-
|
|
195
|
-
warmCdnProbeTimeout: values["warm-
|
|
196
|
-
warmCdnProbeRetries: values["warm-
|
|
197
|
-
warmCdnCertify: values["warm-
|
|
198
|
-
warmCdnReadinessTimeout: values["warm-
|
|
199
|
-
warmCdnReadinessRetries: values["warm-
|
|
200
|
-
warmCdnReadinessProbes: values["warm-
|
|
201
|
-
warmCdnReadinessProbeDelay: values["warm-
|
|
202
|
-
dangerouslyPromoteOnCdnWarmError: values["dangerously-promote-on-
|
|
203
|
-
warmCdnPromote: !values["no-promote"] && !values["warm-
|
|
204
|
-
warmCdnPromotionDelay: values["warm-
|
|
205
|
-
warmCdnIncludeFallbacks: values["warm-
|
|
206
|
-
experimentalTPR:
|
|
257
|
+
warmCdnCache: values["warm-cache"],
|
|
258
|
+
warmCdnTarget: values["warm-cache-target"] === void 0 ? void 0 : validateCdnWarmTarget(values["warm-cache-target"]),
|
|
259
|
+
warmCdnConcurrency: values["warm-cache-concurrency"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-concurrency"], "--warm-cache-concurrency"),
|
|
260
|
+
warmCdnTimeout: values["warm-cache-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-timeout"], "--warm-cache-timeout"),
|
|
261
|
+
warmCdnRetries: values["warm-cache-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-retries"], "--warm-cache-retries"),
|
|
262
|
+
warmCdnDiscoveryTimeout: values["warm-cache-discovery-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-discovery-timeout"], "--warm-cache-discovery-timeout"),
|
|
263
|
+
warmCdnDiscoveryRetries: values["warm-cache-discovery-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-discovery-retries"], "--warm-cache-discovery-retries"),
|
|
264
|
+
warmCdnProbeTimeout: values["warm-cache-probe-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-probe-timeout"], "--warm-cache-probe-timeout"),
|
|
265
|
+
warmCdnProbeRetries: values["warm-cache-probe-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-probe-retries"], "--warm-cache-probe-retries"),
|
|
266
|
+
warmCdnCertify: values["warm-cache-certify"],
|
|
267
|
+
warmCdnReadinessTimeout: values["warm-cache-readiness-timeout"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-readiness-timeout"], "--warm-cache-readiness-timeout"),
|
|
268
|
+
warmCdnReadinessRetries: values["warm-cache-readiness-retries"] === void 0 ? void 0 : parseNonNegativeIntegerArg(values["warm-cache-readiness-retries"], "--warm-cache-readiness-retries"),
|
|
269
|
+
warmCdnReadinessProbes: values["warm-cache-readiness-probes"] === void 0 ? void 0 : parsePositiveIntegerArg(values["warm-cache-readiness-probes"], "--warm-cache-readiness-probes"),
|
|
270
|
+
warmCdnReadinessProbeDelay: values["warm-cache-readiness-probe-delay"] === void 0 ? void 0 : validateTimerDelay(parseNonNegativeIntegerArg(values["warm-cache-readiness-probe-delay"], "--warm-cache-readiness-probe-delay"), "--warm-cache-readiness-probe-delay", values["warm-cache-readiness-probe-delay"]),
|
|
271
|
+
dangerouslyPromoteOnCdnWarmError: values["dangerously-promote-on-warm-cache-error"],
|
|
272
|
+
warmCdnPromote: !values["no-promote"] && !values["warm-cache-no-promote"],
|
|
273
|
+
warmCdnPromotionDelay: values["warm-cache-promotion-delay"] === void 0 ? void 0 : validatePromotionDelay(parseNonNegativeIntegerArg(values["warm-cache-promotion-delay"], "--warm-cache-promotion-delay"), values["warm-cache-promotion-delay"]),
|
|
274
|
+
warmCdnIncludeFallbacks: values["warm-cache-include-fallbacks"],
|
|
275
|
+
experimentalTPR: trafficAwareWarmCache,
|
|
207
276
|
tprCoverage: parseIntArg("traffic-aware-coverage", values["traffic-aware-coverage"] ?? values["tpr-coverage"]),
|
|
208
277
|
tprLimit: parseIntArg("traffic-aware-limit", values["traffic-aware-limit"] ?? values["tpr-limit"]),
|
|
209
278
|
tprWindow: parseIntArg("traffic-aware-window", values["traffic-aware-window"] ?? values["tpr-window"])
|
|
@@ -256,10 +325,13 @@ async function loadProjectWranglerApi(root) {
|
|
|
256
325
|
pathToFileURL(wranglerPath).href
|
|
257
326
|
);
|
|
258
327
|
}
|
|
259
|
-
|
|
328
|
+
function resolveViteBuildMode(deploymentTool, env) {
|
|
329
|
+
return deploymentTool === "cf" ? env ?? "production" : "production";
|
|
330
|
+
}
|
|
331
|
+
async function loadDeployViteConfigMetadata(root, mode) {
|
|
260
332
|
const plugins = (await (await loadProjectViteApi(root)).loadConfigFromFile({
|
|
261
333
|
command: "build",
|
|
262
|
-
mode
|
|
334
|
+
mode
|
|
263
335
|
}, void 0, root))?.config.plugins;
|
|
264
336
|
return {
|
|
265
337
|
cacheConfig: await findVinextCacheConfigInPlugins(plugins),
|
|
@@ -268,32 +340,22 @@ async function loadDeployViteConfigMetadata(root) {
|
|
|
268
340
|
routeRootConfig: await findVinextRouteRootConfigInPlugins(plugins)
|
|
269
341
|
};
|
|
270
342
|
}
|
|
271
|
-
async function runBuild(info, env) {
|
|
343
|
+
async function runBuild(info, env, mode) {
|
|
272
344
|
console.log("\n Building for Cloudflare Workers...\n");
|
|
273
345
|
const { createBuilder } = await loadProjectViteApi(info.root);
|
|
346
|
+
let completed = false;
|
|
274
347
|
await withCloudflareEnv(env, async () => {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
ttlSeconds: kvConfig.ttlSeconds
|
|
284
|
-
});
|
|
285
|
-
if (pairs.length === 0) {
|
|
286
|
-
console.log(" KV cache: Skipping prerender upload (no App Router prerendered cache entries found).");
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
await runWranglerKVBulkPut(root, {
|
|
290
|
-
binding: kvConfig.binding,
|
|
291
|
-
env: wranglerEnv,
|
|
292
|
-
pairs
|
|
348
|
+
const invocation = { onComplete() {
|
|
349
|
+
completed = true;
|
|
350
|
+
} };
|
|
351
|
+
await (await createBuilder({
|
|
352
|
+
root: info.root,
|
|
353
|
+
mode,
|
|
354
|
+
[VINEXT_BUILD_LIFECYCLE_CONFIG]: invocation
|
|
355
|
+
})).buildApp();
|
|
293
356
|
});
|
|
294
|
-
|
|
357
|
+
if (!completed) throw new Error("[vinext] The Cloudflare build lifecycle did not complete.");
|
|
295
358
|
}
|
|
296
|
-
const KV_BULK_PUT_CHUNK_SIZE = 25;
|
|
297
359
|
function validateWranglerEnvName(env) {
|
|
298
360
|
if (env.includes("\0")) throw new Error("Wrangler environment names cannot contain null bytes.");
|
|
299
361
|
return env;
|
|
@@ -309,21 +371,25 @@ function buildWranglerDeployArgs(options) {
|
|
|
309
371
|
env
|
|
310
372
|
};
|
|
311
373
|
}
|
|
312
|
-
function
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
"
|
|
318
|
-
|
|
319
|
-
"
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
374
|
+
function resolveDeploymentTool(root) {
|
|
375
|
+
return fs.existsSync(path.join(root, "cloudflare.config.ts")) ? "cf" : "wrangler";
|
|
376
|
+
}
|
|
377
|
+
function isCfCliInstalled(root, resolvePackageJson = (projectRoot) => {
|
|
378
|
+
try {
|
|
379
|
+
return createRequire(path.join(projectRoot, "package.json")).resolve("cf/package.json");
|
|
380
|
+
} catch {
|
|
381
|
+
return findInNodeModules(projectRoot, "cf/package.json");
|
|
382
|
+
}
|
|
383
|
+
}) {
|
|
384
|
+
return resolvePackageJson(root) !== null;
|
|
385
|
+
}
|
|
386
|
+
function buildCfDeployArgs(options) {
|
|
387
|
+
const mode = options.env || (options.preview ? "preview" : void 0);
|
|
388
|
+
const args = ["deploy", "--prebuilt"];
|
|
389
|
+
if (mode) args.push("--mode", validateWranglerEnvName(mode));
|
|
324
390
|
return {
|
|
325
391
|
args,
|
|
326
|
-
|
|
392
|
+
mode
|
|
327
393
|
};
|
|
328
394
|
}
|
|
329
395
|
/**
|
|
@@ -347,6 +413,21 @@ function resolveWranglerBin(root, resolvePackageJson = (projectRoot) => {
|
|
|
347
413
|
}
|
|
348
414
|
return path.join(root, "node_modules", "wrangler", "bin", "wrangler.js");
|
|
349
415
|
}
|
|
416
|
+
function resolveCfBin(root, resolvePackageJson = (projectRoot) => {
|
|
417
|
+
try {
|
|
418
|
+
return createRequire(path.join(projectRoot, "package.json")).resolve("cf/package.json");
|
|
419
|
+
} catch {
|
|
420
|
+
return findInNodeModules(projectRoot, "cf/package.json");
|
|
421
|
+
}
|
|
422
|
+
}) {
|
|
423
|
+
const packageJsonPath = resolvePackageJson(root);
|
|
424
|
+
if (packageJsonPath) {
|
|
425
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
426
|
+
const bin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.cf;
|
|
427
|
+
if (bin) return path.resolve(path.dirname(packageJsonPath), bin);
|
|
428
|
+
}
|
|
429
|
+
return path.join(root, "node_modules", "cf", "bin", "cf");
|
|
430
|
+
}
|
|
350
431
|
function buildNodeCliInvocation(scriptPath, args, nodeExecutable = process.execPath) {
|
|
351
432
|
return {
|
|
352
433
|
file: nodeExecutable,
|
|
@@ -361,45 +442,6 @@ function buildWranglerInvocation(root, options, nodeExecutable = process.execPat
|
|
|
361
442
|
env
|
|
362
443
|
};
|
|
363
444
|
}
|
|
364
|
-
async function runWranglerKVBulkPut(root, options, execute = spawn, nodeExecutable = process.execPath) {
|
|
365
|
-
const tempDir = fs.mkdtempSync(path.join(options.tempDir ?? os.tmpdir(), "vinext-kv-bulk-"));
|
|
366
|
-
try {
|
|
367
|
-
const wranglerBin = resolveWranglerBin(root);
|
|
368
|
-
const totalChunks = Math.ceil(options.pairs.length / KV_BULK_PUT_CHUNK_SIZE);
|
|
369
|
-
for (let i = 0; i < totalChunks; i++) {
|
|
370
|
-
const filePath = path.join(tempDir, `prerender-kv-${i}.json`);
|
|
371
|
-
const chunk = options.pairs.slice(i * KV_BULK_PUT_CHUNK_SIZE, (i + 1) * KV_BULK_PUT_CHUNK_SIZE);
|
|
372
|
-
fs.writeFileSync(filePath, JSON.stringify(chunk), "utf-8");
|
|
373
|
-
const { args } = buildWranglerKVBulkPutArgs({
|
|
374
|
-
binding: options.binding,
|
|
375
|
-
env: options.env,
|
|
376
|
-
filePath
|
|
377
|
-
});
|
|
378
|
-
const invocation = buildNodeCliInvocation(wranglerBin, args, nodeExecutable);
|
|
379
|
-
const child = execute(invocation.file, invocation.args, {
|
|
380
|
-
cwd: root,
|
|
381
|
-
stdio: "inherit",
|
|
382
|
-
shell: false
|
|
383
|
-
});
|
|
384
|
-
await new Promise((resolve, reject) => {
|
|
385
|
-
child.once("error", reject);
|
|
386
|
-
child.once("close", (code, signal) => {
|
|
387
|
-
if (code === 0) {
|
|
388
|
-
resolve();
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
const exitReason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
392
|
-
reject(/* @__PURE__ */ new Error(`Wrangler KV bulk put failed with ${exitReason}.`));
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
} finally {
|
|
397
|
-
fs.rmSync(tempDir, {
|
|
398
|
-
recursive: true,
|
|
399
|
-
force: true
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
445
|
async function runWranglerDeploy(root, options, execute = spawn) {
|
|
404
446
|
if (options.promote === false) return runWranglerVersionUpload(root, options).previewUrl ?? "(Preview URL not detected in wrangler output)";
|
|
405
447
|
const spawnOptions = {
|
|
@@ -439,6 +481,38 @@ async function runWranglerDeploy(root, options, execute = spawn) {
|
|
|
439
481
|
});
|
|
440
482
|
return parseWorkerDeploymentUrl(output) ?? "(URL not detected in wrangler output)";
|
|
441
483
|
}
|
|
484
|
+
async function runCfDeploy(root, options, execute = spawn) {
|
|
485
|
+
const { args, mode } = buildCfDeployArgs(options);
|
|
486
|
+
console.log(mode ? `\n Deploying Build Output in mode: ${mode}...` : "\n Deploying Build Output...");
|
|
487
|
+
const child = execute(process.execPath, [resolveCfBin(root), ...args], {
|
|
488
|
+
cwd: root,
|
|
489
|
+
stdio: [
|
|
490
|
+
"inherit",
|
|
491
|
+
"pipe",
|
|
492
|
+
"pipe"
|
|
493
|
+
],
|
|
494
|
+
shell: false
|
|
495
|
+
});
|
|
496
|
+
let output = "";
|
|
497
|
+
child.stdout?.on("data", (chunk) => {
|
|
498
|
+
const text = chunk.toString();
|
|
499
|
+
output += text;
|
|
500
|
+
process.stdout.write(text);
|
|
501
|
+
});
|
|
502
|
+
child.stderr?.on("data", (chunk) => {
|
|
503
|
+
const text = chunk.toString();
|
|
504
|
+
output += text;
|
|
505
|
+
process.stderr.write(text);
|
|
506
|
+
});
|
|
507
|
+
await new Promise((resolve, reject) => {
|
|
508
|
+
child.once("error", reject);
|
|
509
|
+
child.once("close", (code, signal) => {
|
|
510
|
+
if (code === 0) resolve();
|
|
511
|
+
else reject(/* @__PURE__ */ new Error(`cf deploy failed with ${signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`}.`));
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
return parseWorkerDeploymentUrl(output) ?? "(URL not detected in cf output)";
|
|
515
|
+
}
|
|
442
516
|
function hasCdnWarmRequests(plan) {
|
|
443
517
|
return plan.paths.length + (plan.pagesDataPaths?.length ?? 0) + (plan.routeHandlerPaths?.length ?? 0) + plan.rscPaths.length + plan.loadingShellPaths.length > 0;
|
|
444
518
|
}
|
|
@@ -472,6 +546,30 @@ function selectTPRWarmPlan(plan, traffic, coverage, limit) {
|
|
|
472
546
|
function projectRequiresRouteCacheabilityProbeManifest(project, cacheConfig) {
|
|
473
547
|
return (project.isAppRouter || project.isPagesRouter) && requiresRouteCacheabilityProbeManifest(cacheConfig);
|
|
474
548
|
}
|
|
549
|
+
function deploymentWorkerName(options) {
|
|
550
|
+
if (!options.name) throw new Error("Could not detect the Worker name for its deployment.");
|
|
551
|
+
return options.name;
|
|
552
|
+
}
|
|
553
|
+
function runDeploymentStatus(root, options) {
|
|
554
|
+
return options.deploymentTool === "cf" ? runCfDeploymentStatus(root, {
|
|
555
|
+
name: deploymentWorkerName(options),
|
|
556
|
+
env: options.env,
|
|
557
|
+
verbose: options.verbose
|
|
558
|
+
}) : runWranglerDeploymentStatus(root, options);
|
|
559
|
+
}
|
|
560
|
+
function runVersionDeploy(root, traffic, options, phase) {
|
|
561
|
+
return options.deploymentTool === "cf" ? runCfVersionDeploy(root, traffic, {
|
|
562
|
+
name: deploymentWorkerName(options),
|
|
563
|
+
env: options.env,
|
|
564
|
+
verbose: options.verbose
|
|
565
|
+
}, phase) : runWranglerVersionDeploy(root, traffic, options, phase);
|
|
566
|
+
}
|
|
567
|
+
function runTriggersDeploy(root, options) {
|
|
568
|
+
return options.deploymentTool === "cf" ? runCfTriggersDeploy(root, options) : runWranglerTriggersDeploy(root, options);
|
|
569
|
+
}
|
|
570
|
+
function runVersionUpload(root, options) {
|
|
571
|
+
return options.deploymentTool === "cf" ? runCfVersionUpload(root, options) : runWranglerVersionUpload(root, options);
|
|
572
|
+
}
|
|
475
573
|
function cdnWarmTargetKey(target) {
|
|
476
574
|
return `${target.kind}\0${target.sourcePathname}`;
|
|
477
575
|
}
|
|
@@ -491,14 +589,14 @@ async function deployWithCdnWarmup(root, paths, options) {
|
|
|
491
589
|
...options,
|
|
492
590
|
warmCdnTarget: validateCdnWarmTarget(options.warmCdnTarget)
|
|
493
591
|
};
|
|
494
|
-
if (options.warmCdnDiscoveryTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnDiscoveryTimeout), "--warm-
|
|
495
|
-
if (options.warmCdnDiscoveryRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnDiscoveryRetries), "--warm-
|
|
496
|
-
if (options.warmCdnProbeTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnProbeTimeout), "--warm-
|
|
497
|
-
if (options.warmCdnProbeRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnProbeRetries), "--warm-
|
|
498
|
-
if (options.warmCdnReadinessTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessTimeout), "--warm-
|
|
499
|
-
if (options.warmCdnReadinessRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnReadinessRetries), "--warm-
|
|
500
|
-
if (options.warmCdnReadinessProbes !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessProbes), "--warm-
|
|
501
|
-
if (options.warmCdnReadinessProbeDelay !== void 0) validateTimerDelay(options.warmCdnReadinessProbeDelay, "--warm-
|
|
592
|
+
if (options.warmCdnDiscoveryTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnDiscoveryTimeout), "--warm-cache-discovery-timeout");
|
|
593
|
+
if (options.warmCdnDiscoveryRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnDiscoveryRetries), "--warm-cache-discovery-retries");
|
|
594
|
+
if (options.warmCdnProbeTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnProbeTimeout), "--warm-cache-probe-timeout");
|
|
595
|
+
if (options.warmCdnProbeRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnProbeRetries), "--warm-cache-probe-retries");
|
|
596
|
+
if (options.warmCdnReadinessTimeout !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessTimeout), "--warm-cache-readiness-timeout");
|
|
597
|
+
if (options.warmCdnReadinessRetries !== void 0) parseNonNegativeIntegerArg(String(options.warmCdnReadinessRetries), "--warm-cache-readiness-retries");
|
|
598
|
+
if (options.warmCdnReadinessProbes !== void 0) parsePositiveIntegerArg(String(options.warmCdnReadinessProbes), "--warm-cache-readiness-probes");
|
|
599
|
+
if (options.warmCdnReadinessProbeDelay !== void 0) validateTimerDelay(options.warmCdnReadinessProbeDelay, "--warm-cache-readiness-probe-delay");
|
|
502
600
|
if (options.warmCdnPromotionDelay !== void 0) validatePromotionDelay(options.warmCdnPromotionDelay);
|
|
503
601
|
if (options.cacheabilityProbe) return deployWithCacheabilityProbe(root, options);
|
|
504
602
|
return deployUploadedVersionWithCdnWarmup(root, paths, options);
|
|
@@ -523,7 +621,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
523
621
|
if (plan.paths.length === 0 && plan.pagesDataPaths.length === 0 && (plan.routeHandlerPaths?.length ?? 0) === 0 || expectedBuildId !== void 0) return plan;
|
|
524
622
|
if (!allowUnverifiedPromotion) {
|
|
525
623
|
const warmupKind = plan.paths.length > 0 ? "CDN HTML warmup" : plan.pagesDataPaths.length > 0 ? "CDN Pages data warmup" : "CDN Route Handler warmup";
|
|
526
|
-
throw new Error(`${warmupKind} requires a CDN adapter that declares build-identity response headers. Configure that adapter capability or deploy without --
|
|
624
|
+
throw new Error(`${warmupKind} requires a CDN adapter that declares build-identity response headers. Configure that adapter capability or deploy without --warm-cache.`);
|
|
527
625
|
}
|
|
528
626
|
console.warn(` CDN warmup: skipping ${plan.paths.length} HTML, ${plan.pagesDataPaths.length} Pages data, and ${plan.routeHandlerPaths?.length ?? 0} Route Handler request(s) because the CDN adapter does not declare build-identity response headers.`);
|
|
529
627
|
return {
|
|
@@ -555,7 +653,8 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
555
653
|
warmPlanDiscovered = true;
|
|
556
654
|
};
|
|
557
655
|
if (!options.discoverWarmPlan || hasPreparedWarmPlan) remainingWarmPlan = prepareWarmPlan(remainingWarmPlan);
|
|
558
|
-
const upload = options.uploadedVersion ??
|
|
656
|
+
const upload = options.uploadedVersion ?? runVersionUpload(root, options);
|
|
657
|
+
const wranglerOptions = resolveDeploymentControlPlaneOptions(options, upload);
|
|
559
658
|
const warmUploadedVersion = (targetUrl, headers, propagatingTarget = false, plan = {
|
|
560
659
|
loadingShellPaths: remainingWarmPlan.loadingShellPaths,
|
|
561
660
|
pagesDataPaths: remainingWarmPlan.pagesDataPaths,
|
|
@@ -584,10 +683,10 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
584
683
|
strict: requireCacheHit || !allowUnverifiedPromotion,
|
|
585
684
|
statusSource: options.statusSource
|
|
586
685
|
});
|
|
587
|
-
const wranglerConfig = parseWranglerConfig(root, options.config);
|
|
686
|
+
const wranglerConfig = options.deploymentTool === "cf" ? null : parseWranglerConfig(root, options.config);
|
|
588
687
|
let deploymentStatus;
|
|
589
688
|
try {
|
|
590
|
-
deploymentStatus =
|
|
689
|
+
deploymentStatus = runDeploymentStatus(root, wranglerOptions);
|
|
591
690
|
} catch (error) {
|
|
592
691
|
if (!hasPreparedWarmPlan) throw error;
|
|
593
692
|
throw new StagedWarmupError(formatUnknownError(error), { cause: error });
|
|
@@ -603,14 +702,14 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
603
702
|
let triggersApplied = options.triggersAlreadyApplied === true;
|
|
604
703
|
function applyTriggers() {
|
|
605
704
|
if (triggersApplied) return;
|
|
606
|
-
triggersDeployedUrl =
|
|
705
|
+
triggersDeployedUrl = runTriggersDeploy(root, wranglerOptions).deployedUrl;
|
|
607
706
|
triggersApplied = true;
|
|
608
707
|
}
|
|
609
708
|
if (stagingTraffic) {
|
|
610
709
|
try {
|
|
611
|
-
staged =
|
|
710
|
+
staged = runVersionDeploy(root, stagingTraffic, wranglerOptions, "stage");
|
|
612
711
|
} catch (error) {
|
|
613
|
-
throw reconcileVersionDeployFailure(root,
|
|
712
|
+
throw reconcileVersionDeployFailure(root, wranglerOptions, error, {
|
|
614
713
|
desiredTraffic: stagingTraffic,
|
|
615
714
|
desiredDescription: "The uploaded version is staged at 0% with the previous version still serving 100% traffic; Worker triggers/routes were not changed.",
|
|
616
715
|
priorState: deploymentStatus,
|
|
@@ -619,7 +718,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
619
718
|
}
|
|
620
719
|
try {
|
|
621
720
|
if (hasPreparedWarmPlan) {
|
|
622
|
-
stagedDeploymentState =
|
|
721
|
+
stagedDeploymentState = runDeploymentStatus(root, wranglerOptions);
|
|
623
722
|
if (!deploymentTrafficEquals(stagedDeploymentState.versions, stagingTraffic)) throw new Error("Two-stage CDN warming stopped because Worker deployment traffic changed before production triggers could be applied. No final version was promoted.");
|
|
624
723
|
}
|
|
625
724
|
applyTriggers();
|
|
@@ -627,7 +726,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
627
726
|
throw withStagedVersionCleanupNote(error);
|
|
628
727
|
}
|
|
629
728
|
const targetUrl = resolveCdnWarmupTargetUrl(root, triggersDeployedUrl, options) ?? staged.deployedUrl;
|
|
630
|
-
const headers = buildVersionOverrideHeaders(options.name ?? upload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig,
|
|
729
|
+
const headers = buildVersionOverrideHeaders(options.name ?? upload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig, wranglerOptions), upload.versionId);
|
|
631
730
|
if (targetUrl && headers) try {
|
|
632
731
|
if (!warmPlanDiscovered) {
|
|
633
732
|
console.log(" CDN warmup: discovering paths from the staged Worker version...");
|
|
@@ -669,7 +768,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
669
768
|
console.log(" CDN warmup: staged Worker version is stable.");
|
|
670
769
|
const warmResult = await warmUploadedVersion(targetUrl, headers, true, stagedWarmPlan);
|
|
671
770
|
const optionalSkipped = options.optionalWarmTargetKeys ? warmResult.skippedTargets.filter((target) => options.optionalWarmTargetKeys.has(cdnWarmTargetKey(target))).length : 0;
|
|
672
|
-
if (hasPreparedWarmPlan && options.warmCdnCertify) {
|
|
771
|
+
if ((hasPreparedWarmPlan || options.selectWarmPlan) && options.warmCdnCertify) {
|
|
673
772
|
if (warmResult.warmed + optionalSkipped !== stagedWarmRequests) throw new Error(`CDN warmup cannot certify the staged cache because only ${warmResult.warmed}/${stagedWarmRequests - optionalSkipped} cacheable entries completed their initial fill.`);
|
|
674
773
|
}
|
|
675
774
|
const requiredSkipped = warmResult.skipped - optionalSkipped;
|
|
@@ -698,7 +797,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
698
797
|
throw withStagedVersionCleanupNote(error);
|
|
699
798
|
}
|
|
700
799
|
else if (initialWarmRequests > 0) {
|
|
701
|
-
const message = "CDN warmup failed: pre-traffic warmup needs a production URL and Worker name for version overrides. Configure a route/custom domain and Worker name, or deploy without --
|
|
800
|
+
const message = "CDN warmup failed: pre-traffic warmup needs a production URL and Worker name for version overrides. Configure a route/custom domain and Worker name, or deploy without --warm-cache.";
|
|
702
801
|
if (!allowUnverifiedPromotion) throw new StagedWarmupError(`${message} ${getStagedVersionCleanupNote()}`);
|
|
703
802
|
console.warn(` ${message} Promoting because the dangerous override is enabled.`);
|
|
704
803
|
}
|
|
@@ -710,6 +809,10 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
710
809
|
}
|
|
711
810
|
console.warn(" CDN warmup: pre-traffic version override skipped because the current deployment is not one version serving 100% traffic.");
|
|
712
811
|
}
|
|
812
|
+
if (options.selectWarmPlan && options.warmCdnCertify && !stagedCacheFilled) {
|
|
813
|
+
const error = /* @__PURE__ */ new Error("CDN warmup cannot succeed because no cache entries were certified.");
|
|
814
|
+
throw staged ? withStagedVersionCleanupNote(error) : error;
|
|
815
|
+
}
|
|
713
816
|
const countRemainingWarmRequests = () => remainingWarmPlan.paths.length + remainingWarmPlan.pagesDataPaths.length + (remainingWarmPlan.routeHandlerPaths?.length ?? 0) + remainingWarmPlan.rscPaths.length + remainingWarmPlan.loadingShellPaths.length;
|
|
714
817
|
if (options.warmCdnPromote === false) {
|
|
715
818
|
if (!staged) throw new Error("CDN warmup cannot skip promotion because the uploaded Worker version could not be staged at 0% traffic. The current deployment must have exactly one version serving 100% traffic.");
|
|
@@ -719,9 +822,9 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
719
822
|
if (hasPreparedWarmPlan && stagedDeploymentState) {
|
|
720
823
|
let currentDeployment;
|
|
721
824
|
try {
|
|
722
|
-
currentDeployment =
|
|
825
|
+
currentDeployment = runDeploymentStatus(root, wranglerOptions);
|
|
723
826
|
} catch (error) {
|
|
724
|
-
throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} CDN warmup cannot confirm that the uploaded Worker remains staged at 0% traffic; production Worker triggers/routes remain applied. Inspect
|
|
827
|
+
throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} CDN warmup cannot confirm that the uploaded Worker remains staged at 0% traffic; production Worker triggers/routes remain applied. Inspect the active Worker deployment before continuing.`, { cause: error });
|
|
725
828
|
}
|
|
726
829
|
if (!deploymentStateEquals(currentDeployment, stagedDeploymentState)) throw new StagedWarmupError("Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed before the no-promote handoff. The uploaded Worker is not confirmed staged at 0% traffic; production Worker triggers/routes remain applied.");
|
|
727
830
|
}
|
|
@@ -744,13 +847,13 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
744
847
|
}
|
|
745
848
|
}
|
|
746
849
|
if (hasPreparedWarmPlan && stagingTraffic) {
|
|
747
|
-
prePromotionState =
|
|
850
|
+
prePromotionState = runDeploymentStatus(root, wranglerOptions);
|
|
748
851
|
if (!deploymentTrafficEquals(prePromotionState.versions, stagingTraffic) || stagedDeploymentState && !deploymentStateEquals(prePromotionState, stagedDeploymentState)) throw new Error("Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed before the final version could be promoted. No final version was promoted.");
|
|
749
852
|
}
|
|
750
853
|
promotionAttempted = true;
|
|
751
|
-
deployed =
|
|
854
|
+
deployed = runVersionDeploy(root, promotionTraffic, wranglerOptions, stagedCacheFilled ? "promote-warmed" : "promote-uploaded");
|
|
752
855
|
} catch (error) {
|
|
753
|
-
if (promotionAttempted) throw reconcileVersionDeployFailure(root,
|
|
856
|
+
if (promotionAttempted) throw reconcileVersionDeployFailure(root, wranglerOptions, error, {
|
|
754
857
|
desiredTraffic: promotionTraffic,
|
|
755
858
|
desiredDescription: "The uploaded version is already promoted to 100%; Worker triggers/routes may already have changed.",
|
|
756
859
|
priorState: prePromotionState ?? (stagingTraffic ? {
|
|
@@ -782,7 +885,7 @@ async function deployUploadedVersionWithCdnWarmup(root, paths, options) {
|
|
|
782
885
|
} catch (error) {
|
|
783
886
|
throw withPromotedVersionWarmupNote(error);
|
|
784
887
|
}
|
|
785
|
-
else if (!allowUnverifiedPromotion) throw withPromotedVersionWarmupNote(/* @__PURE__ */ new Error("CDN warmup failed: no production URL could be inferred from wrangler config or output. Configure a route/custom domain, ensure Wrangler prints a workers.dev URL, or deploy without --
|
|
888
|
+
else if (!allowUnverifiedPromotion) throw withPromotedVersionWarmupNote(/* @__PURE__ */ new Error("CDN warmup failed: no production URL could be inferred from wrangler config or output. Configure a route/custom domain, ensure Wrangler prints a workers.dev URL, or deploy without --warm-cache."));
|
|
786
889
|
else console.warn(" CDN warmup skipped: no production URL could be inferred after promotion; the dangerous override was enabled.");
|
|
787
890
|
}
|
|
788
891
|
return deployed.deployedUrl ?? triggersDeployedUrl ?? staged?.deployedUrl ?? upload.previewUrl ?? "(URL not detected in wrangler output)";
|
|
@@ -802,7 +905,7 @@ function reconcileVersionDeployFailure(root, options, error, expected) {
|
|
|
802
905
|
let reconciliation;
|
|
803
906
|
let mayNeedCleanup = true;
|
|
804
907
|
try {
|
|
805
|
-
const current =
|
|
908
|
+
const current = runDeploymentStatus(root, options);
|
|
806
909
|
if (deploymentTrafficEquals(current.versions, expected.desiredTraffic)) reconciliation = expected.desiredDescription;
|
|
807
910
|
else if (deploymentStateEquals(current, expected.priorState)) {
|
|
808
911
|
reconciliation = expected.priorDescription;
|
|
@@ -815,20 +918,21 @@ function reconcileVersionDeployFailure(root, options, error, expected) {
|
|
|
815
918
|
return mayNeedCleanup ? new StagedWarmupError(detail, { cause: error }) : new Error(detail, { cause: error });
|
|
816
919
|
}
|
|
817
920
|
function assertDeploymentStateUnchanged(root, options, expected, message) {
|
|
818
|
-
if (!deploymentStateEquals(
|
|
921
|
+
if (!deploymentStateEquals(runDeploymentStatus(root, options), expected)) throw new Error(message);
|
|
819
922
|
}
|
|
820
923
|
async function deployWithCacheabilityProbe(root, options) {
|
|
821
924
|
if (!options.discoverWarmPlan) throw new Error("Two-stage CDN warming requires staged Worker route discovery before cacheability probing.");
|
|
822
925
|
const prerenderSecret = readPrerenderSecret(root);
|
|
823
|
-
const probeUpload =
|
|
824
|
-
const
|
|
926
|
+
const probeUpload = runVersionUpload(root, options);
|
|
927
|
+
const wranglerOptions = resolveDeploymentControlPlaneOptions(options, probeUpload);
|
|
928
|
+
const initialDeployment = runDeploymentStatus(root, wranglerOptions);
|
|
825
929
|
const probeTraffic = getZeroPercentStagingTraffic(initialDeployment, probeUpload.versionId);
|
|
826
930
|
if (!probeTraffic) throw new Error("Two-stage CDN warming cannot stage the probe Worker at 0% because the current deployment is not exactly one version serving 100% traffic. No traffic or triggers were changed.");
|
|
827
931
|
let stagedProbe;
|
|
828
932
|
try {
|
|
829
|
-
stagedProbe =
|
|
933
|
+
stagedProbe = runVersionDeploy(root, probeTraffic, wranglerOptions, "stage");
|
|
830
934
|
} catch (error) {
|
|
831
|
-
throw reconcileVersionDeployFailure(root,
|
|
935
|
+
throw reconcileVersionDeployFailure(root, wranglerOptions, error, {
|
|
832
936
|
desiredTraffic: probeTraffic,
|
|
833
937
|
desiredDescription: "The probe version is staged at 0% with the previous version still serving 100% traffic; production Worker triggers/routes were not changed.",
|
|
834
938
|
priorState: initialDeployment,
|
|
@@ -837,16 +941,16 @@ async function deployWithCacheabilityProbe(root, options) {
|
|
|
837
941
|
}
|
|
838
942
|
let stagedProbeDeployment;
|
|
839
943
|
try {
|
|
840
|
-
stagedProbeDeployment =
|
|
944
|
+
stagedProbeDeployment = runDeploymentStatus(root, wranglerOptions);
|
|
841
945
|
if (!deploymentTrafficEquals(stagedProbeDeployment.versions, probeTraffic)) throw new Error("Two-stage CDN warming stopped because Worker deployment traffic changed immediately after the probe version was staged.");
|
|
842
946
|
} catch (error) {
|
|
843
|
-
throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe staging command completed, but its current deployment state could not be confirmed; production Worker triggers/routes were not changed. Inspect
|
|
947
|
+
throw new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe staging command completed, but its current deployment state could not be confirmed; production Worker triggers/routes were not changed. Inspect the active Worker deployment and remove the staged probe version if necessary.`, { cause: error });
|
|
844
948
|
}
|
|
845
949
|
let prepared;
|
|
846
950
|
try {
|
|
847
951
|
const targetUrl = resolveCdnWarmupTargetUrl(root, stagedProbe.deployedUrl ?? probeUpload.previewUrl, options);
|
|
848
|
-
const wranglerConfig = parseWranglerConfig(root,
|
|
849
|
-
const headers = buildVersionOverrideHeaders(options.name ?? probeUpload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig,
|
|
952
|
+
const wranglerConfig = options.deploymentTool === "cf" ? null : parseWranglerConfig(root, wranglerOptions.config);
|
|
953
|
+
const headers = buildVersionOverrideHeaders(options.name ?? probeUpload.workerName ?? resolveWorkerNameForVersionOverride(wranglerConfig, wranglerOptions), probeUpload.versionId);
|
|
850
954
|
if (!targetUrl || !headers) throw new Error("Two-stage CDN warming needs a production URL and Worker name for version-overridden cacheability probes.");
|
|
851
955
|
console.log(" CDN warmup: discovering paths from the staged probe Worker...");
|
|
852
956
|
const discovered = await options.discoverWarmPlan({
|
|
@@ -912,6 +1016,7 @@ async function deployWithCacheabilityProbe(root, options) {
|
|
|
912
1016
|
concurrency: options.warmCdnConcurrency,
|
|
913
1017
|
expectedResponseBuildId: plan.buildIdentity,
|
|
914
1018
|
fallbackRoutePatterns: plan.fallbackRoutePatterns,
|
|
1019
|
+
loadingBoundaryRoutePatterns: plan.loadingBoundaryRoutePatterns,
|
|
915
1020
|
phaseTimeoutMs: options.warmCdnProbeTimeout ?? 12e4,
|
|
916
1021
|
retries: options.warmCdnProbeRetries ?? options.warmCdnRetries ?? 2,
|
|
917
1022
|
retryDelayMs: DEFAULT_CACHEABILITY_PROBE_RETRY_DELAY_MS,
|
|
@@ -937,14 +1042,11 @@ async function deployWithCacheabilityProbe(root, options) {
|
|
|
937
1042
|
rscPaths: probe.cacheableTargets.filter((target) => target.kind === "rsc-full").map((target) => target.sourcePathname)
|
|
938
1043
|
};
|
|
939
1044
|
const selectedFinalPlan = options.selectWarmPlan?.(finalPlan) ?? finalPlan;
|
|
940
|
-
assertDeploymentStateUnchanged(root,
|
|
941
|
-
const finalConfig = writeCacheabilityManifestArtifact(root, options.config, probe.manifest);
|
|
942
|
-
const finalUpload =
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
name: options.name,
|
|
946
|
-
preview: options.preview,
|
|
947
|
-
verbose: options.verbose
|
|
1045
|
+
assertDeploymentStateUnchanged(root, wranglerOptions, stagedProbeDeployment, "Two-stage CDN warming stopped because Worker deployment traffic or deployment identity changed while cacheability was being probed. No final version was promoted.");
|
|
1046
|
+
const finalConfig = writeCacheabilityManifestArtifact(root, options.config, probe.manifest, options.deploymentTool);
|
|
1047
|
+
const finalUpload = runVersionUpload(root, {
|
|
1048
|
+
...options,
|
|
1049
|
+
config: options.deploymentTool === "cf" ? options.config : finalConfig
|
|
948
1050
|
});
|
|
949
1051
|
prepared = {
|
|
950
1052
|
optionalWarmTargetKeys: new Set(probe.speculativeTargets.map(cdnWarmTargetKey)),
|
|
@@ -986,6 +1088,15 @@ function getZeroPercentStagingTraffic(deployment, versionId) {
|
|
|
986
1088
|
function getWranglerTargetEnv(options) {
|
|
987
1089
|
return options.env || (options.preview ? "preview" : void 0);
|
|
988
1090
|
}
|
|
1091
|
+
function resolveDeploymentControlPlaneOptions(options, upload) {
|
|
1092
|
+
if (options.deploymentTool !== "cf") return options;
|
|
1093
|
+
const name = upload.workerName ?? options.name;
|
|
1094
|
+
if (!name) throw new Error("Could not detect the uploaded Worker name needed for staged CDN warming.");
|
|
1095
|
+
return {
|
|
1096
|
+
...options,
|
|
1097
|
+
name
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
989
1100
|
function resolveWorkerNameForVersionOverride(config, options) {
|
|
990
1101
|
if (options.name) return options.name;
|
|
991
1102
|
const env = getWranglerTargetEnv(options);
|
|
@@ -1010,24 +1121,29 @@ function withStagedProbeVersionCleanupNote(error) {
|
|
|
1010
1121
|
return new StagedWarmupError(`${error instanceof Error ? error.message : String(error)} The probe version may remain staged at 0% with the previous version still serving 100% traffic; production Worker triggers/routes were not changed.`, { cause: error });
|
|
1011
1122
|
}
|
|
1012
1123
|
function getStagedVersionCleanupNote() {
|
|
1013
|
-
return "The uploaded version may remain staged at 0% with the previous version still serving 100% traffic; Worker triggers/routes may also have changed because trigger deployment runs before warming. Rerun deploy to promote it or
|
|
1124
|
+
return "The uploaded version may remain staged at 0% with the previous version still serving 100% traffic; Worker triggers/routes may also have changed because trigger deployment runs before warming. Rerun deploy to promote it or create a deployment with the desired version split.";
|
|
1014
1125
|
}
|
|
1015
1126
|
function withPromotedVersionTriggerNote(error) {
|
|
1016
1127
|
const message = error instanceof Error ? error.message : String(error);
|
|
1017
|
-
return new Error(`${message} The uploaded version may already be promoted to 100%, but Worker triggers/routes may not be updated; rerun deploy or
|
|
1128
|
+
return new Error(`${message} The uploaded version may already be promoted to 100%, but Worker triggers/routes may not be updated; rerun deploy or apply the Worker triggers after fixing the trigger error.`, { cause: error });
|
|
1018
1129
|
}
|
|
1019
1130
|
function withPromotedVersionWarmupNote(error) {
|
|
1020
1131
|
const message = error instanceof Error ? error.message : String(error);
|
|
1021
|
-
return new Error(`${message} The uploaded version is already promoted to 100% and its Worker triggers/routes were updated; rerun deploy to retry cache warming or
|
|
1132
|
+
return new Error(`${message} The uploaded version is already promoted to 100% and its Worker triggers/routes were updated; rerun deploy to retry cache warming or create a deployment for the previous version.`, { cause: error });
|
|
1022
1133
|
}
|
|
1023
1134
|
async function deploy(options) {
|
|
1024
|
-
if (options.warmCdnTarget !== void 0 && !options.warmCdnCache) throw new Error("--warm-
|
|
1135
|
+
if (options.warmCdnTarget !== void 0 && !options.warmCdnCache && !options.experimentalTPR) throw new Error("--warm-cache-target requires --warm-cache or --traffic-aware-warm-cache.");
|
|
1025
1136
|
const warmCdnTarget = options.warmCdnTarget === void 0 ? void 0 : validateCdnWarmTarget(options.warmCdnTarget);
|
|
1026
|
-
const deployEnv =
|
|
1137
|
+
const deployEnv = options.env || (options.preview ? "preview" : void 0);
|
|
1138
|
+
if (deployEnv) validateWranglerEnvName(deployEnv);
|
|
1027
1139
|
const root = path.resolve(options.root);
|
|
1140
|
+
const deploymentTool = resolveDeploymentTool(root);
|
|
1141
|
+
if (deploymentTool === "cf" && options.name) throw new Error("--name is not supported for cloudflare.config.ts projects. Set `name` in cloudflare.config.ts instead.");
|
|
1142
|
+
const viteMode = resolveViteBuildMode(deploymentTool, deployEnv);
|
|
1143
|
+
const wranglerFallbackEnv = deploymentTool === "cf" ? void 0 : deployEnv;
|
|
1028
1144
|
loadDotenv({
|
|
1029
1145
|
root,
|
|
1030
|
-
mode:
|
|
1146
|
+
mode: viteMode
|
|
1031
1147
|
});
|
|
1032
1148
|
console.log("\n vinext-cloudflare deploy\n");
|
|
1033
1149
|
const info = detectProject(root);
|
|
@@ -1045,20 +1161,20 @@ async function deploy(options) {
|
|
|
1045
1161
|
if (missingScaffolding.length > 0) throw new Error(`Missing Cloudflare deployment setup: ${missingScaffolding.join(", ")}. Run \`vinext init --platform=cloudflare\` first.`);
|
|
1046
1162
|
const missingDeps = getMissingDeps(info);
|
|
1047
1163
|
if (missingDeps.length > 0) throw new Error(`Missing deployment dependencies: ${missingDeps.map((dependency) => dependency.name).join(", ")}. Run \`vinext init --platform=cloudflare\` first.`);
|
|
1164
|
+
if (deploymentTool === "cf" && !isCfCliInstalled(root)) throw new Error("Missing deployment dependencies: cf. Run `vinext init --platform=cloudflare` first.");
|
|
1048
1165
|
if (info.hasViteConfig && !viteConfigHasCloudflarePlugin(root)) throw new Error(formatMissingCloudflarePluginError({ isAppRouter: info.isAppRouter }));
|
|
1049
|
-
if (info.hasISR && !viteConfigHasCacheAdapter(root) && !workerEntryHasCacheHandler(root)) throw new Error(formatMissingCacheAdapterError({}));
|
|
1166
|
+
if (info.hasISR && !viteConfigHasCacheAdapter(root) && !workerEntryHasCacheHandler(root)) throw new Error(formatMissingCacheAdapterError({ typedConfig: deploymentTool === "cf" }));
|
|
1050
1167
|
if (!viteConfigHasImageAdapter(root)) {
|
|
1051
1168
|
console.log();
|
|
1052
|
-
console.log(formatImageOptimizationHint());
|
|
1169
|
+
console.log(formatImageOptimizationHint(deploymentTool === "cf"));
|
|
1053
1170
|
}
|
|
1054
1171
|
if (options.dryRun) {
|
|
1055
1172
|
console.log("\n Dry run complete. No build or deploy performed.\n");
|
|
1056
1173
|
return;
|
|
1057
1174
|
}
|
|
1058
|
-
const
|
|
1059
|
-
const viteConfigMetadata = await withCloudflareEnv(buildEnv, () => loadDeployViteConfigMetadata(info.root));
|
|
1175
|
+
const viteConfigMetadata = await withCloudflareEnv(deployEnv, () => loadDeployViteConfigMetadata(info.root, viteMode));
|
|
1060
1176
|
const cdnAdapterConfig = resolveCdnAdapterConfig(viteConfigMetadata.cacheConfig);
|
|
1061
|
-
const nextConfig = await withCloudflareEnv(
|
|
1177
|
+
const nextConfig = await withCloudflareEnv(deployEnv, async () => {
|
|
1062
1178
|
const inlineNextConfig = viteConfigMetadata.nextConfig;
|
|
1063
1179
|
const rawNextConfig = inlineNextConfig ? await resolveNextConfigInput(inlineNextConfig, PHASE_PRODUCTION_BUILD) : await loadNextConfig(info.root, PHASE_PRODUCTION_BUILD);
|
|
1064
1180
|
return resolveNextConfig(rawNextConfig, info.root);
|
|
@@ -1069,66 +1185,82 @@ async function deploy(options) {
|
|
|
1069
1185
|
vinextPrerenderConfig,
|
|
1070
1186
|
nextOutput: nextConfig.output
|
|
1071
1187
|
});
|
|
1188
|
+
const shouldPrerenderLocally = Boolean(prerenderDecision && (nextConfig.output === "export" || hasCacheAdapterPrerenderOutput(viteConfigMetadata.cacheConfig)));
|
|
1072
1189
|
const hasStrictResponseVary = hasVerbatimResponseVary(viteConfigMetadata.cacheConfig);
|
|
1073
1190
|
const warmupStatusSource = cacheWarmupStatusSource(viteConfigMetadata.cacheConfig);
|
|
1074
1191
|
const hasStagedRequestRouting = hasUncachedRequestRouting(viteConfigMetadata.cacheConfig) || warmupStatusSource === "data-cache";
|
|
1075
1192
|
const hasBuildIdentityHeader = hasBuildIdentityResponseHeader(viteConfigMetadata.cacheConfig);
|
|
1076
1193
|
const hasCanonicalRscWarmup = supportsCanonicalRscWarmup(viteConfigMetadata.cacheConfig);
|
|
1077
1194
|
const needsCacheabilityProbeManifest = projectRequiresRouteCacheabilityProbeManifest(info, viteConfigMetadata.cacheConfig);
|
|
1078
|
-
const shouldEmitPrerenderPathManifest = !options.skipBuild &&
|
|
1079
|
-
if (!
|
|
1195
|
+
const shouldEmitPrerenderPathManifest = !options.skipBuild && shouldPrerenderLocally;
|
|
1196
|
+
if (prerenderDecision && !shouldPrerenderLocally) {
|
|
1197
|
+
const trigger = prerenderDecision.reason === "flag" ? "--prerender-all" : "vinext prerender config";
|
|
1198
|
+
const replacement = options.warmCdnCache ? "Routes will be rendered and warmed through the staged Worker instead." : "Use --warm-cache to render and warm routes through the deployed Worker instead.";
|
|
1199
|
+
console.warn(`\n Warning: ${trigger} is ignored by Cloudflare deploy. ${replacement}`);
|
|
1200
|
+
}
|
|
1201
|
+
if (!options.skipBuild) await runBuild(info, deployEnv, viteMode);
|
|
1080
1202
|
else console.log("\n Skipping build (--skip-build)");
|
|
1081
|
-
const
|
|
1082
|
-
|
|
1203
|
+
const prerenderOutputDirs = resolvePrerenderOutputDirs(info.root, deploymentTool, viteConfigMetadata.routeRootConfig);
|
|
1204
|
+
const canWarmTpr = options.experimentalTPR && !shouldPrerenderLocally && hasBuildIdentityHeader;
|
|
1205
|
+
if (options.experimentalTPR && shouldPrerenderLocally) console.log(" TPR: Skipping route selection (all-route prerendering configured)");
|
|
1083
1206
|
else if (options.experimentalTPR && !hasBuildIdentityHeader) console.log(workerEntryHasCacheHandler(root) ? " TPR: Skipping pre-warm (legacy imperative cache handlers must migrate to declarative vinext({ cache }) for standard warming)" : " TPR: Skipping pre-warm (configured cache does not expose build identity)");
|
|
1084
1207
|
const tpr = canWarmTpr ? await resolveTPRRoutes({
|
|
1085
1208
|
root,
|
|
1086
1209
|
config: options.config,
|
|
1087
|
-
env:
|
|
1210
|
+
env: wranglerFallbackEnv,
|
|
1088
1211
|
hostname: warmCdnTarget ? new URL(warmCdnTarget).hostname : void 0,
|
|
1212
|
+
typedConfig: deploymentTool === "cf",
|
|
1089
1213
|
window: Math.max(1, options.tprWindow ?? 24)
|
|
1090
1214
|
}) : null;
|
|
1091
1215
|
if (tpr?.skipped) console.log(` TPR: Skipped (${tpr.skipped})`);
|
|
1092
1216
|
const tprRoutes = tpr?.routes ?? [];
|
|
1093
1217
|
const wranglerOptions = {
|
|
1094
|
-
env:
|
|
1095
|
-
name: options.name,
|
|
1218
|
+
env: deploymentTool === "cf" ? viteMode : deployEnv,
|
|
1219
|
+
name: deploymentTool === "cf" ? readBuildOutputWorkerName(root) : options.name,
|
|
1096
1220
|
config: options.config,
|
|
1097
|
-
verbose: options.verbose
|
|
1221
|
+
verbose: options.verbose,
|
|
1222
|
+
deploymentTool
|
|
1098
1223
|
};
|
|
1099
1224
|
let shouldWarmTpr = tprRoutes.length > 0;
|
|
1100
1225
|
if (shouldWarmTpr && !options.warmCdnCache) {
|
|
1101
1226
|
try {
|
|
1102
|
-
shouldWarmTpr = getZeroPercentStagingTraffic(
|
|
1227
|
+
shouldWarmTpr = getZeroPercentStagingTraffic(runDeploymentStatus(root, wranglerOptions), "tpr-preflight") !== null;
|
|
1103
1228
|
} catch {
|
|
1104
1229
|
shouldWarmTpr = false;
|
|
1105
1230
|
}
|
|
1106
1231
|
if (!shouldWarmTpr) console.log(" TPR: Skipping pre-warm (current deployment cannot be staged safely)");
|
|
1107
1232
|
}
|
|
1108
1233
|
const shouldWarmCdnCache = options.warmCdnCache || shouldWarmTpr;
|
|
1234
|
+
if (options.warmCdnCertify && !shouldWarmCdnCache) throw new Error("Cannot certify traffic-aware warming because pre-warming was skipped.");
|
|
1109
1235
|
const shouldSelectTpr = shouldWarmTpr && !options.warmCdnCache;
|
|
1110
1236
|
const candidatePathsOnly = shouldSelectTpr && !needsCacheabilityProbeManifest;
|
|
1111
|
-
const shouldPrerenderLocally = prerenderDecision && (!shouldWarmCdnCache || prerenderDecision.reason === "next-export");
|
|
1112
1237
|
if (shouldWarmCdnCache && cdnAdapterConfig) {
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1238
|
+
if (deploymentTool === "cf") {
|
|
1239
|
+
const configPath = path.join(root, ".cloudflare/output/v0/workers/default/worker.config.json");
|
|
1240
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
1241
|
+
const binding = cdnAdapterConfig.versionMetadataBinding;
|
|
1242
|
+
if (config.env?.[binding]?.type !== "version-metadata") throw new Error(`[vinext] Cloudflare CDN warmup requires version metadata binding ${JSON.stringify(binding)} in the generated Build Output Worker config ${configPath}.`);
|
|
1243
|
+
} else {
|
|
1244
|
+
const wrangler = await loadProjectWranglerApi(info.root);
|
|
1245
|
+
const previousCwd = process.cwd();
|
|
1246
|
+
try {
|
|
1247
|
+
process.chdir(info.root);
|
|
1248
|
+
const config = wrangler.unstable_readConfig({
|
|
1249
|
+
config: options.config,
|
|
1250
|
+
env: wranglerFallbackEnv
|
|
1251
|
+
}, {
|
|
1252
|
+
hideWarnings: true,
|
|
1253
|
+
preserveOriginalMain: true,
|
|
1254
|
+
useRedirectIfAvailable: true
|
|
1255
|
+
});
|
|
1256
|
+
assertCdnVersionMetadataConfig({
|
|
1257
|
+
binding: cdnAdapterConfig.versionMetadataBinding,
|
|
1258
|
+
configuredBinding: config.version_metadata?.binding,
|
|
1259
|
+
configPath: config.configPath
|
|
1260
|
+
});
|
|
1261
|
+
} finally {
|
|
1262
|
+
process.chdir(previousCwd);
|
|
1263
|
+
}
|
|
1132
1264
|
}
|
|
1133
1265
|
}
|
|
1134
1266
|
if (shouldEmitPrerenderPathManifest) await emitPrerenderPathManifest({
|
|
@@ -1138,27 +1270,30 @@ async function deploy(options) {
|
|
|
1138
1270
|
requestRouting: hasStagedRequestRouting ? "uncached-stage" : void 0,
|
|
1139
1271
|
responseVary: hasStrictResponseVary ? "verbatim" : void 0,
|
|
1140
1272
|
isResponsePolicyHeader: (name) => isConfiguredCdnResponsePolicyHeader(viteConfigMetadata.cacheConfig, name),
|
|
1141
|
-
routeRootConfig:
|
|
1273
|
+
routeRootConfig: prerenderOutputDirs
|
|
1142
1274
|
});
|
|
1143
|
-
let
|
|
1144
|
-
if (shouldPrerenderLocally) {
|
|
1275
|
+
let prerenderResult = void 0;
|
|
1276
|
+
if (shouldPrerenderLocally && prerenderDecision) {
|
|
1145
1277
|
console.log(`\n ${formatVinextPrerenderLabel(prerenderDecision)}`);
|
|
1146
1278
|
if (nextConfig.enablePrerenderSourceMaps) {
|
|
1147
1279
|
process.setSourceMapsEnabled(true);
|
|
1148
1280
|
Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 50);
|
|
1149
1281
|
}
|
|
1150
|
-
await runPrerender({
|
|
1282
|
+
prerenderResult = await runPrerender({
|
|
1151
1283
|
root: info.root,
|
|
1152
|
-
concurrency: options.prerenderConcurrency,
|
|
1284
|
+
concurrency: options.prerenderConcurrency ?? viteConfigMetadata.prerenderConfig?.concurrency,
|
|
1153
1285
|
nextConfig,
|
|
1154
|
-
routeRootConfig:
|
|
1286
|
+
routeRootConfig: prerenderOutputDirs
|
|
1155
1287
|
});
|
|
1156
|
-
|
|
1288
|
+
if (nextConfig.output !== "export") await finalizeCacheAdapterPrerenderOutput(viteConfigMetadata.cacheConfig, info.root, { clientOutDir: prerenderOutputDirs?.clientOutDir });
|
|
1157
1289
|
}
|
|
1158
|
-
if (
|
|
1159
|
-
await
|
|
1160
|
-
|
|
1161
|
-
|
|
1290
|
+
if (!options.skipBuild) {
|
|
1291
|
+
await printBuildReport({
|
|
1292
|
+
root: info.root,
|
|
1293
|
+
pageExtensions: nextConfig.pageExtensions,
|
|
1294
|
+
prerenderResult: prerenderResult ?? void 0
|
|
1295
|
+
});
|
|
1296
|
+
console.log("\n Build complete.\n");
|
|
1162
1297
|
}
|
|
1163
1298
|
let url;
|
|
1164
1299
|
if (shouldWarmCdnCache) try {
|
|
@@ -1200,7 +1335,7 @@ async function deploy(options) {
|
|
|
1200
1335
|
selectWarmPlan: shouldSelectTpr ? (plan) => selectTPRWarmPlan(plan, tprRoutes, Math.max(1, Math.min(100, options.tprCoverage ?? 90)), Math.max(1, options.tprLimit ?? 1e3)) : void 0,
|
|
1201
1336
|
statusSource: warmupStatusSource,
|
|
1202
1337
|
warmCdnConcurrency: options.warmCdnConcurrency,
|
|
1203
|
-
warmCdnTarget,
|
|
1338
|
+
warmCdnTarget: warmCdnTarget ?? tpr?.targetUrl,
|
|
1204
1339
|
warmCdnTimeout: options.warmCdnTimeout,
|
|
1205
1340
|
warmCdnRetries: options.warmCdnRetries,
|
|
1206
1341
|
warmCdnDiscoveryTimeout: options.warmCdnDiscoveryTimeout,
|
|
@@ -1217,16 +1352,20 @@ async function deploy(options) {
|
|
|
1217
1352
|
warmCdnPromotionDelay: options.warmCdnPromotionDelay
|
|
1218
1353
|
});
|
|
1219
1354
|
} catch (error) {
|
|
1220
|
-
if (options.warmCdnCache || options.warmCdnPromote === false && error instanceof StagedWarmupError) throw error;
|
|
1355
|
+
if (options.warmCdnCache || options.warmCdnCertify || options.warmCdnPromote === false && error instanceof StagedWarmupError) throw error;
|
|
1221
1356
|
console.log(` TPR: Skipping pre-warm (${formatUnknownError(error)}). Continuing with deploy.`);
|
|
1222
1357
|
}
|
|
1223
|
-
if (url === void 0)
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1358
|
+
if (url === void 0) {
|
|
1359
|
+
if (deploymentTool === "cf" && options.warmCdnPromote === false) url = runCfVersionUpload(root, wranglerOptions).previewUrl ?? "(Preview URL not detected in cf output)";
|
|
1360
|
+
else if (deploymentTool === "cf") url = await runCfDeploy(root, wranglerOptions);
|
|
1361
|
+
else url = await runWranglerDeploy(root, {
|
|
1362
|
+
...wranglerOptions,
|
|
1363
|
+
promote: options.warmCdnPromote
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1227
1366
|
console.log("\n ─────────────────────────────────────────");
|
|
1228
1367
|
console.log(` ${options.warmCdnPromote === false ? "Version URL" : "Deployed to"}: ${url}`);
|
|
1229
1368
|
console.log(" ─────────────────────────────────────────\n");
|
|
1230
1369
|
}
|
|
1231
1370
|
//#endregion
|
|
1232
|
-
export { DEFAULT_CDN_WARM_PROMOTION_DELAY_MS, buildNodeCliInvocation, buildVersionOverrideHeaders, buildWranglerDeployArgs, buildWranglerInvocation,
|
|
1371
|
+
export { DEFAULT_CDN_WARM_PROMOTION_DELAY_MS, buildCfDeployArgs, buildNodeCliInvocation, buildVersionOverrideHeaders, buildWranglerDeployArgs, buildWranglerInvocation, deploy, deployWithCdnWarmup, getZeroPercentStagingTraffic, hasCdnWarmRequests, isCfCliInstalled, parseDeployArgs, projectRequiresRouteCacheabilityProbeManifest, resolveCdnWarmupTargetUrl, resolveCfBin, resolveDeploymentControlPlaneOptions, resolveDeploymentTool, resolvePrerenderOutputDirs, resolveViteBuildMode, resolveWorkerNameForVersionOverride, resolveWranglerBin, runCfDeploy, runWranglerDeploy, selectTPRWarmPlan, validateWranglerEnvName, withCloudflareEnv };
|