wrangler 2.0.23 → 2.0.24
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 +20 -2
- package/bin/wrangler.js +1 -1
- package/miniflare-dist/index.mjs +96 -34
- package/package.json +9 -4
- package/src/__tests__/configuration.test.ts +88 -16
- package/src/__tests__/dev.test.tsx +3 -0
- package/src/__tests__/generate.test.ts +93 -0
- package/src/__tests__/helpers/mock-cfetch.ts +54 -2
- package/src/__tests__/index.test.ts +10 -27
- package/src/__tests__/jest.setup.ts +31 -1
- package/src/__tests__/kv.test.ts +2 -2
- package/src/__tests__/metrics.test.ts +5 -0
- package/src/__tests__/publish.test.ts +497 -254
- package/src/__tests__/r2.test.ts +155 -71
- package/src/__tests__/user.test.ts +1 -0
- package/src/__tests__/validate-dev-props.test.ts +56 -0
- package/src/__tests__/whoami.test.tsx +60 -1
- package/src/bundle.ts +278 -44
- package/src/cfetch/internal.ts +34 -2
- package/src/config/config.ts +7 -2
- package/src/config/environment.ts +40 -8
- package/src/config/index.ts +13 -0
- package/src/config/validation.ts +101 -7
- package/src/create-worker-upload-form.ts +25 -0
- package/src/dev/dev.tsx +107 -28
- package/src/dev/local.tsx +20 -10
- package/src/dev/remote.tsx +39 -8
- package/src/dev/use-esbuild.ts +25 -0
- package/src/dev/validate-dev-props.ts +31 -0
- package/src/dev-registry.tsx +157 -0
- package/src/dev.tsx +93 -75
- package/src/generate.ts +112 -14
- package/src/index.tsx +182 -4
- package/src/inspect.ts +93 -5
- package/src/metrics/index.ts +1 -0
- package/src/metrics/metrics-dispatcher.ts +1 -0
- package/src/metrics/metrics-usage-headers.ts +24 -0
- package/src/metrics/send-event.ts +2 -2
- package/src/module-collection.ts +3 -3
- package/src/pages/constants.ts +1 -0
- package/src/pages/deployments.tsx +1 -1
- package/src/pages/dev.tsx +6 -1
- package/src/pages/publish.tsx +1 -1
- package/src/pages/upload.tsx +32 -13
- package/src/publish.ts +126 -112
- package/src/r2.ts +68 -0
- package/src/user/user.tsx +20 -2
- package/src/whoami.tsx +79 -1
- package/src/worker.ts +12 -0
- package/templates/first-party-worker-module-facade.ts +18 -0
- package/templates/format-dev-errors.ts +32 -0
- package/templates/{static-asset-facade.js → serve-static-assets.ts} +21 -7
- package/templates/service-bindings-module-facade.js +51 -0
- package/templates/service-bindings-sw-facade.js +39 -0
- package/wrangler-dist/cli.js +40192 -15265
package/src/config/validation.ts
CHANGED
|
@@ -598,25 +598,68 @@ function normalizeAndValidateAssets(
|
|
|
598
598
|
diagnostics: Diagnostics,
|
|
599
599
|
configPath: string | undefined,
|
|
600
600
|
rawConfig: RawConfig
|
|
601
|
-
) {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
) {
|
|
606
|
-
return
|
|
601
|
+
): Config["assets"] {
|
|
602
|
+
// Even though the type doesn't say it,
|
|
603
|
+
// we allow for a string input in the config,
|
|
604
|
+
// so let's normalise it
|
|
605
|
+
if (typeof rawConfig?.assets === "string") {
|
|
606
|
+
return {
|
|
607
|
+
bucket: rawConfig.assets,
|
|
608
|
+
include: [],
|
|
609
|
+
exclude: [],
|
|
610
|
+
browser_TTL: undefined,
|
|
611
|
+
serve_single_page_app: false,
|
|
612
|
+
};
|
|
607
613
|
}
|
|
608
614
|
|
|
609
|
-
|
|
615
|
+
if (rawConfig?.assets === undefined) {
|
|
616
|
+
return undefined;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (typeof rawConfig.assets !== "object") {
|
|
620
|
+
diagnostics.errors.push(
|
|
621
|
+
`Expected the \`assets\` field to be a string or an object, but got ${typeof rawConfig.assets}.`
|
|
622
|
+
);
|
|
623
|
+
return undefined;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const {
|
|
627
|
+
bucket,
|
|
628
|
+
include = [],
|
|
629
|
+
exclude = [],
|
|
630
|
+
browser_TTL,
|
|
631
|
+
serve_single_page_app,
|
|
632
|
+
...rest
|
|
633
|
+
} = rawConfig.assets;
|
|
610
634
|
|
|
611
635
|
validateAdditionalProperties(diagnostics, "assets", Object.keys(rest), []);
|
|
636
|
+
|
|
612
637
|
validateRequiredProperty(diagnostics, "assets", "bucket", bucket, "string");
|
|
613
638
|
validateTypedArray(diagnostics, "assets.include", include, "string");
|
|
614
639
|
validateTypedArray(diagnostics, "assets.exclude", exclude, "string");
|
|
615
640
|
|
|
641
|
+
validateOptionalProperty(
|
|
642
|
+
diagnostics,
|
|
643
|
+
"assets",
|
|
644
|
+
"browser_TTL",
|
|
645
|
+
browser_TTL,
|
|
646
|
+
"number"
|
|
647
|
+
);
|
|
648
|
+
|
|
649
|
+
validateOptionalProperty(
|
|
650
|
+
diagnostics,
|
|
651
|
+
"assets",
|
|
652
|
+
"serve_single_page_app",
|
|
653
|
+
serve_single_page_app,
|
|
654
|
+
"boolean"
|
|
655
|
+
);
|
|
656
|
+
|
|
616
657
|
return {
|
|
617
658
|
bucket,
|
|
618
659
|
include,
|
|
619
660
|
exclude,
|
|
661
|
+
browser_TTL,
|
|
662
|
+
serve_single_page_app,
|
|
620
663
|
};
|
|
621
664
|
}
|
|
622
665
|
|
|
@@ -830,6 +873,13 @@ function normalizeAndValidateEnvironment(
|
|
|
830
873
|
isLegacyEnv?: boolean,
|
|
831
874
|
rawConfig?: RawConfig | undefined
|
|
832
875
|
): Environment {
|
|
876
|
+
deprecated(
|
|
877
|
+
diagnostics,
|
|
878
|
+
rawEnv,
|
|
879
|
+
"kv-namespaces",
|
|
880
|
+
`The "kv-namespaces" field is no longer supported, please rename to "kv_namespaces"`,
|
|
881
|
+
true
|
|
882
|
+
);
|
|
833
883
|
deprecated(
|
|
834
884
|
diagnostics,
|
|
835
885
|
rawEnv,
|
|
@@ -1045,6 +1095,17 @@ function normalizeAndValidateEnvironment(
|
|
|
1045
1095
|
validateBindingArray(envName, validateWorkerNamespaceBinding),
|
|
1046
1096
|
[]
|
|
1047
1097
|
),
|
|
1098
|
+
logfwdr: inheritable(
|
|
1099
|
+
diagnostics,
|
|
1100
|
+
topLevelEnv,
|
|
1101
|
+
rawEnv,
|
|
1102
|
+
"logfwdr",
|
|
1103
|
+
validateBindingsProperty(envName, validateCflogfwdrBinding),
|
|
1104
|
+
{
|
|
1105
|
+
schema: undefined,
|
|
1106
|
+
bindings: [],
|
|
1107
|
+
}
|
|
1108
|
+
),
|
|
1048
1109
|
unsafe: notInheritable(
|
|
1049
1110
|
diagnostics,
|
|
1050
1111
|
topLevelEnv,
|
|
@@ -1082,6 +1143,14 @@ function normalizeAndValidateEnvironment(
|
|
|
1082
1143
|
isBoolean,
|
|
1083
1144
|
undefined
|
|
1084
1145
|
),
|
|
1146
|
+
first_party_worker: inheritable(
|
|
1147
|
+
diagnostics,
|
|
1148
|
+
topLevelEnv,
|
|
1149
|
+
rawEnv,
|
|
1150
|
+
"first_party_worker",
|
|
1151
|
+
isBoolean,
|
|
1152
|
+
undefined
|
|
1153
|
+
),
|
|
1085
1154
|
};
|
|
1086
1155
|
|
|
1087
1156
|
return environment;
|
|
@@ -1418,6 +1487,30 @@ const validateDurableObjectBinding: ValidatorFn = (
|
|
|
1418
1487
|
return isValid;
|
|
1419
1488
|
};
|
|
1420
1489
|
|
|
1490
|
+
const validateCflogfwdrBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
1491
|
+
if (typeof value !== "object" || value === null) {
|
|
1492
|
+
diagnostics.errors.push(
|
|
1493
|
+
`Expected "${field}" to be an object but got ${JSON.stringify(value)}`
|
|
1494
|
+
);
|
|
1495
|
+
return false;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
let isValid = true;
|
|
1499
|
+
if (!isRequiredProperty(value, "name", "string")) {
|
|
1500
|
+
diagnostics.errors.push(`binding should have a string "name" field.`);
|
|
1501
|
+
isValid = false;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
if (!isRequiredProperty(value, "destination", "string")) {
|
|
1505
|
+
diagnostics.errors.push(
|
|
1506
|
+
`binding should have a string "destination" field.`
|
|
1507
|
+
);
|
|
1508
|
+
isValid = false;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
return isValid;
|
|
1512
|
+
};
|
|
1513
|
+
|
|
1421
1514
|
/**
|
|
1422
1515
|
* Check that the given field is a valid "unsafe" binding object.
|
|
1423
1516
|
*
|
|
@@ -1448,6 +1541,7 @@ const validateUnsafeBinding: ValidatorFn = (diagnostics, field, value) => {
|
|
|
1448
1541
|
"durable_object_namespace",
|
|
1449
1542
|
"r2_bucket",
|
|
1450
1543
|
"service",
|
|
1544
|
+
"logfwdr",
|
|
1451
1545
|
];
|
|
1452
1546
|
|
|
1453
1547
|
if (safeBindings.includes(value.type)) {
|
|
@@ -32,6 +32,7 @@ export interface WorkerMetadata {
|
|
|
32
32
|
compatibility_flags?: string[];
|
|
33
33
|
usage_model?: "bundled" | "unbound";
|
|
34
34
|
migrations?: CfDurableObjectMigrations;
|
|
35
|
+
capnp_schema?: string;
|
|
35
36
|
// If you add any new binding types here, also add it to safeBindings
|
|
36
37
|
// under validateUnsafeBinding in config/validation.ts
|
|
37
38
|
bindings: (
|
|
@@ -51,6 +52,11 @@ export interface WorkerMetadata {
|
|
|
51
52
|
| { type: "r2_bucket"; name: string; bucket_name: string }
|
|
52
53
|
| { type: "service"; name: string; service: string; environment?: string }
|
|
53
54
|
| { type: "namespace"; name: string; namespace: string }
|
|
55
|
+
| {
|
|
56
|
+
type: "logfwdr";
|
|
57
|
+
name: string;
|
|
58
|
+
destination: string;
|
|
59
|
+
}
|
|
54
60
|
)[];
|
|
55
61
|
}
|
|
56
62
|
|
|
@@ -125,6 +131,14 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
125
131
|
});
|
|
126
132
|
});
|
|
127
133
|
|
|
134
|
+
bindings.logfwdr?.bindings.forEach(({ name, destination }) => {
|
|
135
|
+
metadataBindings.push({
|
|
136
|
+
name: name,
|
|
137
|
+
type: "logfwdr",
|
|
138
|
+
destination,
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
128
142
|
for (const [name, filePath] of Object.entries(bindings.wasm_modules || {})) {
|
|
129
143
|
metadataBindings.push({
|
|
130
144
|
name,
|
|
@@ -240,6 +254,7 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
240
254
|
...(compatibility_flags && { compatibility_flags }),
|
|
241
255
|
...(usage_model && { usage_model }),
|
|
242
256
|
...(migrations && { migrations }),
|
|
257
|
+
capnp_schema: bindings.logfwdr?.schema,
|
|
243
258
|
};
|
|
244
259
|
|
|
245
260
|
formData.set("metadata", JSON.stringify(metadata));
|
|
@@ -259,5 +274,15 @@ export function createWorkerUploadForm(worker: CfWorkerInit): FormData {
|
|
|
259
274
|
);
|
|
260
275
|
}
|
|
261
276
|
|
|
277
|
+
if (bindings.logfwdr && bindings.logfwdr.schema) {
|
|
278
|
+
const filePath = bindings.logfwdr.schema;
|
|
279
|
+
formData.set(
|
|
280
|
+
filePath,
|
|
281
|
+
new File([readFileSync(filePath)], filePath, {
|
|
282
|
+
type: "application/octet-stream",
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
262
287
|
return formData;
|
|
263
288
|
}
|
package/src/dev/dev.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import * as util from "node:util";
|
|
3
4
|
import { watch } from "chokidar";
|
|
4
5
|
import clipboardy from "clipboardy";
|
|
5
6
|
import commandExists from "command-exists";
|
|
@@ -9,6 +10,12 @@ import { withErrorBoundary, useErrorHandler } from "react-error-boundary";
|
|
|
9
10
|
import onExit from "signal-exit";
|
|
10
11
|
import tmp from "tmp-promise";
|
|
11
12
|
import { fetch } from "undici";
|
|
13
|
+
import {
|
|
14
|
+
getRegisteredWorkers,
|
|
15
|
+
startWorkerRegistry,
|
|
16
|
+
stopWorkerRegistry,
|
|
17
|
+
unregisterWorker,
|
|
18
|
+
} from "../dev-registry";
|
|
12
19
|
import { runCustomBuild } from "../entry";
|
|
13
20
|
import { openInspector } from "../inspect";
|
|
14
21
|
import { logger } from "../logger";
|
|
@@ -16,13 +23,97 @@ import openInBrowser from "../open-in-browser";
|
|
|
16
23
|
import { Local } from "./local";
|
|
17
24
|
import { Remote } from "./remote";
|
|
18
25
|
import { useEsbuild } from "./use-esbuild";
|
|
26
|
+
import { validateDevProps } from "./validate-dev-props";
|
|
19
27
|
import type { Config } from "../config";
|
|
20
28
|
import type { Route } from "../config/environment";
|
|
29
|
+
import type { WorkerRegistry } from "../dev-registry";
|
|
21
30
|
import type { Entry } from "../entry";
|
|
22
31
|
import type { EnablePagesAssetsServiceBindingOptions } from "../miniflare-cli";
|
|
23
32
|
import type { AssetPaths } from "../sites";
|
|
24
33
|
import type { CfWorkerInit } from "../worker";
|
|
25
34
|
|
|
35
|
+
/**
|
|
36
|
+
* This hooks establishes a connection with the dev registry,
|
|
37
|
+
* and periodically updates itself with details of workers currently
|
|
38
|
+
* running a dev session on this system.
|
|
39
|
+
*/
|
|
40
|
+
function useDevRegistry(
|
|
41
|
+
name: string | undefined,
|
|
42
|
+
services: Config["services"] | undefined,
|
|
43
|
+
mode: "local" | "remote"
|
|
44
|
+
): WorkerRegistry {
|
|
45
|
+
const [workers, setWorkers] = useState<WorkerRegistry>({});
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
// Let's try to start registry
|
|
49
|
+
// TODO: we should probably call this in a loop
|
|
50
|
+
// in case the registry dies elsewhere
|
|
51
|
+
startWorkerRegistry().catch((err) => {
|
|
52
|
+
logger.error("failed to start worker registry", err);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const serviceNames = (services || []).map(
|
|
56
|
+
(serviceBinding) => serviceBinding.service
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const interval =
|
|
60
|
+
// TODO: enable this for remote mode as well
|
|
61
|
+
// https://github.com/cloudflare/wrangler2/issues/1182
|
|
62
|
+
mode === "local"
|
|
63
|
+
? setInterval(() => {
|
|
64
|
+
getRegisteredWorkers().then(
|
|
65
|
+
(workerDefinitions: WorkerRegistry | undefined) => {
|
|
66
|
+
// We only want the workers that we're bound to
|
|
67
|
+
// so let's filter out the others
|
|
68
|
+
const filteredWorkers = Object.fromEntries(
|
|
69
|
+
Object.entries(workerDefinitions || {}).filter(
|
|
70
|
+
([key, _value]) => serviceNames.includes(key)
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
setWorkers((prevWorkers) => {
|
|
74
|
+
if (!util.isDeepStrictEqual(filteredWorkers, prevWorkers)) {
|
|
75
|
+
return filteredWorkers;
|
|
76
|
+
}
|
|
77
|
+
return prevWorkers;
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
(err) => {
|
|
81
|
+
logger.warn("Failed to get worker definitions", err);
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}, 300)
|
|
85
|
+
: undefined;
|
|
86
|
+
|
|
87
|
+
return () => {
|
|
88
|
+
interval && clearInterval(interval);
|
|
89
|
+
Promise.allSettled([
|
|
90
|
+
name ? unregisterWorker(name) : Promise.resolve(),
|
|
91
|
+
stopWorkerRegistry(),
|
|
92
|
+
]).then(
|
|
93
|
+
([unregisterResult, stopRegistryResult]) => {
|
|
94
|
+
if (unregisterResult.status === "rejected") {
|
|
95
|
+
logger.error(
|
|
96
|
+
"Failed to unregister worker",
|
|
97
|
+
unregisterResult.reason
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (stopRegistryResult.status === "rejected") {
|
|
101
|
+
logger.error(
|
|
102
|
+
"Failed to stop worker registry",
|
|
103
|
+
stopRegistryResult.reason
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
(err) => {
|
|
108
|
+
logger.error("Failed to clear dev registry effect", err);
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
}, [name, services, mode]);
|
|
113
|
+
|
|
114
|
+
return workers;
|
|
115
|
+
}
|
|
116
|
+
|
|
26
117
|
export type DevProps = {
|
|
27
118
|
name: string | undefined;
|
|
28
119
|
noBundle: boolean;
|
|
@@ -46,6 +137,7 @@ export type DevProps = {
|
|
|
46
137
|
crons: Config["triggers"]["crons"];
|
|
47
138
|
isWorkersSite: boolean;
|
|
48
139
|
assetPaths: AssetPaths | undefined;
|
|
140
|
+
assetsConfig: Config["assets"];
|
|
49
141
|
compatibilityDate: string;
|
|
50
142
|
compatibilityFlags: string[] | undefined;
|
|
51
143
|
usageModel: "bundled" | "unbound" | undefined;
|
|
@@ -64,36 +156,12 @@ export type DevProps = {
|
|
|
64
156
|
showInteractiveDevSession: boolean | undefined;
|
|
65
157
|
forceLocal: boolean | undefined;
|
|
66
158
|
enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
|
|
159
|
+
firstPartyWorker: boolean | undefined;
|
|
160
|
+
sendMetrics: boolean | undefined;
|
|
67
161
|
};
|
|
68
162
|
|
|
69
163
|
export function DevImplementation(props: DevProps): JSX.Element {
|
|
70
|
-
|
|
71
|
-
!props.isWorkersSite &&
|
|
72
|
-
props.assetPaths &&
|
|
73
|
-
props.entry.format === "service-worker"
|
|
74
|
-
) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
"You cannot use the service-worker format with an `assets` directory yet. For information on how to migrate to the module-worker format, see: https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/"
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (props.bindings.wasm_modules && props.entry.format === "modules") {
|
|
81
|
-
throw new Error(
|
|
82
|
-
"You cannot configure [wasm_modules] with an ES module worker. Instead, import the .wasm module directly in your code"
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (props.bindings.text_blobs && props.entry.format === "modules") {
|
|
87
|
-
throw new Error(
|
|
88
|
-
"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (props.bindings.data_blobs && props.entry.format === "modules") {
|
|
93
|
-
throw new Error(
|
|
94
|
-
"You cannot configure [data_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[rules]` in your wrangler.toml"
|
|
95
|
-
);
|
|
96
|
-
}
|
|
164
|
+
validateDevProps(props);
|
|
97
165
|
|
|
98
166
|
// only load the UI if we're running in a supported environment
|
|
99
167
|
const { isRawModeSupported } = useStdin();
|
|
@@ -157,6 +225,12 @@ function DevSession(props: DevSessionProps) {
|
|
|
157
225
|
|
|
158
226
|
const directory = useTmpDir();
|
|
159
227
|
|
|
228
|
+
const workerDefinitions = useDevRegistry(
|
|
229
|
+
props.name,
|
|
230
|
+
props.bindings.services,
|
|
231
|
+
props.local ? "local" : "remote"
|
|
232
|
+
);
|
|
233
|
+
|
|
160
234
|
const bundle = useEsbuild({
|
|
161
235
|
entry: props.entry,
|
|
162
236
|
destination: directory,
|
|
@@ -171,6 +245,10 @@ function DevSession(props: DevSessionProps) {
|
|
|
171
245
|
nodeCompat: props.nodeCompat,
|
|
172
246
|
define: props.define,
|
|
173
247
|
noBundle: props.noBundle,
|
|
248
|
+
assets: props.assetsConfig,
|
|
249
|
+
workerDefinitions,
|
|
250
|
+
services: props.bindings.services,
|
|
251
|
+
firstPartyWorkerDevFacade: props.firstPartyWorker,
|
|
174
252
|
});
|
|
175
253
|
|
|
176
254
|
return props.local ? (
|
|
@@ -182,7 +260,6 @@ function DevSession(props: DevSessionProps) {
|
|
|
182
260
|
compatibilityFlags={props.compatibilityFlags}
|
|
183
261
|
bindings={props.bindings}
|
|
184
262
|
assetPaths={props.assetPaths}
|
|
185
|
-
isWorkersSite={props.isWorkersSite}
|
|
186
263
|
port={props.port}
|
|
187
264
|
ip={props.ip}
|
|
188
265
|
rules={props.rules}
|
|
@@ -223,6 +300,8 @@ function DevSession(props: DevSessionProps) {
|
|
|
223
300
|
host={props.host}
|
|
224
301
|
routes={props.routes}
|
|
225
302
|
onReady={props.onReady}
|
|
303
|
+
sourceMapPath={bundle?.sourceMapPath}
|
|
304
|
+
sendMetrics={props.sendMetrics}
|
|
226
305
|
/>
|
|
227
306
|
);
|
|
228
307
|
}
|
package/src/dev/local.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { writeFile } from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { useState, useEffect, useRef } from "react";
|
|
6
6
|
import onExit from "signal-exit";
|
|
7
|
+
import { registerWorker } from "../dev-registry";
|
|
7
8
|
import useInspector from "../inspect";
|
|
8
9
|
import { logger } from "../logger";
|
|
9
10
|
import { DEFAULT_MODULE_RULES } from "../module-collection";
|
|
@@ -23,7 +24,6 @@ interface LocalProps {
|
|
|
23
24
|
compatibilityFlags: string[] | undefined;
|
|
24
25
|
bindings: CfWorkerInit["bindings"];
|
|
25
26
|
assetPaths: AssetPaths | undefined;
|
|
26
|
-
isWorkersSite: boolean;
|
|
27
27
|
port: number;
|
|
28
28
|
ip: string;
|
|
29
29
|
rules: Config["rules"];
|
|
@@ -58,7 +58,6 @@ function useLocalWorker({
|
|
|
58
58
|
compatibilityFlags,
|
|
59
59
|
bindings,
|
|
60
60
|
assetPaths,
|
|
61
|
-
isWorkersSite,
|
|
62
61
|
port,
|
|
63
62
|
inspectorPort,
|
|
64
63
|
rules,
|
|
@@ -88,6 +87,15 @@ function useLocalWorker({
|
|
|
88
87
|
// so that it's persisted in the temp dir across a dev session
|
|
89
88
|
// even when we change source and reload
|
|
90
89
|
null;
|
|
90
|
+
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
if (bindings.services && bindings.services.length > 0) {
|
|
93
|
+
logger.warn(
|
|
94
|
+
"⎔ Support for service bindings in local mode is experimental and may change."
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}, [bindings.services]);
|
|
98
|
+
|
|
91
99
|
useEffect(() => {
|
|
92
100
|
const abortController = new AbortController();
|
|
93
101
|
async function startLocalWorker() {
|
|
@@ -100,12 +108,6 @@ function useLocalWorker({
|
|
|
100
108
|
abortSignal: abortController.signal,
|
|
101
109
|
});
|
|
102
110
|
|
|
103
|
-
if (bindings.services && bindings.services.length > 0) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
"⎔ Service bindings are not yet supported in local mode."
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
111
|
// In local mode, we want to copy all referenced modules into
|
|
110
112
|
// the output bundle directory before starting up
|
|
111
113
|
for (const module of bundle.modules) {
|
|
@@ -273,8 +275,17 @@ function useLocalWorker({
|
|
|
273
275
|
stdio: "pipe",
|
|
274
276
|
}));
|
|
275
277
|
|
|
276
|
-
child.on("message", (message) => {
|
|
278
|
+
child.on("message", async (message) => {
|
|
277
279
|
if (message === "ready") {
|
|
280
|
+
// Let's register our presence in the dev registry
|
|
281
|
+
if (workerName) {
|
|
282
|
+
await registerWorker(workerName, {
|
|
283
|
+
protocol: localProtocol,
|
|
284
|
+
mode: "local",
|
|
285
|
+
port,
|
|
286
|
+
host: ip,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
278
289
|
onReady?.();
|
|
279
290
|
}
|
|
280
291
|
});
|
|
@@ -357,7 +368,6 @@ function useLocalWorker({
|
|
|
357
368
|
localPersistencePath,
|
|
358
369
|
liveReload,
|
|
359
370
|
assetPaths,
|
|
360
|
-
isWorkersSite,
|
|
361
371
|
rules,
|
|
362
372
|
bindings.wasm_modules,
|
|
363
373
|
bindings.text_blobs,
|
package/src/dev/remote.tsx
CHANGED
|
@@ -55,6 +55,8 @@ export function Remote(props: {
|
|
|
55
55
|
host: string | undefined;
|
|
56
56
|
routes: Route[] | undefined;
|
|
57
57
|
onReady?: (() => void) | undefined;
|
|
58
|
+
sourceMapPath: string | undefined;
|
|
59
|
+
sendMetrics: boolean | undefined;
|
|
58
60
|
}) {
|
|
59
61
|
const [accountId, setAccountId] = useState(props.accountId);
|
|
60
62
|
const accountChoicesRef = useRef<Promise<ChooseAccountItem[]>>();
|
|
@@ -78,6 +80,7 @@ export function Remote(props: {
|
|
|
78
80
|
host: props.host,
|
|
79
81
|
routes: props.routes,
|
|
80
82
|
onReady: props.onReady,
|
|
83
|
+
sendMetrics: props.sendMetrics,
|
|
81
84
|
});
|
|
82
85
|
|
|
83
86
|
usePreviewServer({
|
|
@@ -97,6 +100,7 @@ export function Remote(props: {
|
|
|
97
100
|
: undefined,
|
|
98
101
|
port: props.inspectorPort,
|
|
99
102
|
logToTerminal: true,
|
|
103
|
+
sourceMapPath: props.sourceMapPath,
|
|
100
104
|
});
|
|
101
105
|
|
|
102
106
|
const errorHandler = useErrorHandler();
|
|
@@ -161,6 +165,7 @@ export function useWorker(props: {
|
|
|
161
165
|
host: string | undefined;
|
|
162
166
|
routes: Route[] | undefined;
|
|
163
167
|
onReady: (() => void) | undefined;
|
|
168
|
+
sendMetrics: boolean | undefined;
|
|
164
169
|
}): CfPreviewToken | undefined {
|
|
165
170
|
const {
|
|
166
171
|
name,
|
|
@@ -202,6 +207,7 @@ export function useWorker(props: {
|
|
|
202
207
|
zone: props.zone,
|
|
203
208
|
host: props.host,
|
|
204
209
|
routes: props.routes,
|
|
210
|
+
sendMetrics: props.sendMetrics,
|
|
205
211
|
};
|
|
206
212
|
|
|
207
213
|
setSession(
|
|
@@ -230,6 +236,7 @@ export function useWorker(props: {
|
|
|
230
236
|
props.legacyEnv,
|
|
231
237
|
props.routes,
|
|
232
238
|
props.zone,
|
|
239
|
+
props.sendMetrics,
|
|
233
240
|
]);
|
|
234
241
|
|
|
235
242
|
// This effect uses the session to upload the worker and create a preview
|
|
@@ -320,17 +327,40 @@ export function useWorker(props: {
|
|
|
320
327
|
zone: props.zone,
|
|
321
328
|
host: props.host,
|
|
322
329
|
routes: props.routes,
|
|
330
|
+
sendMetrics: props.sendMetrics,
|
|
323
331
|
};
|
|
324
332
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
abortController.signal
|
|
332
|
-
)
|
|
333
|
+
const workerPreviewToken = await createWorkerPreview(
|
|
334
|
+
init,
|
|
335
|
+
workerAccount,
|
|
336
|
+
workerCtx,
|
|
337
|
+
session,
|
|
338
|
+
abortController.signal
|
|
333
339
|
);
|
|
340
|
+
|
|
341
|
+
setToken(workerPreviewToken);
|
|
342
|
+
|
|
343
|
+
// TODO: Once we get service bindings working in the
|
|
344
|
+
// edge preview server, we can define remote dev service bindings
|
|
345
|
+
// and you can uncomment this code.
|
|
346
|
+
// https://github.com/cloudflare/wrangler2/issues/1182
|
|
347
|
+
|
|
348
|
+
/*
|
|
349
|
+
if (name) {
|
|
350
|
+
await registerWorker(name, {
|
|
351
|
+
mode: "remote",
|
|
352
|
+
// upstream protocol is always https (https://github.com/cloudflare/wrangler2/issues/583)
|
|
353
|
+
protocol: "https",
|
|
354
|
+
port: undefined,
|
|
355
|
+
host: workerPreviewToken.host,
|
|
356
|
+
headers: {
|
|
357
|
+
"cf-workers-preview-token": workerPreviewToken.value,
|
|
358
|
+
host: workerPreviewToken.host,
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
*/
|
|
363
|
+
|
|
334
364
|
onReady?.();
|
|
335
365
|
}
|
|
336
366
|
start().catch((err) => {
|
|
@@ -377,6 +407,7 @@ export function useWorker(props: {
|
|
|
377
407
|
props.routes,
|
|
378
408
|
session,
|
|
379
409
|
onReady,
|
|
410
|
+
props.sendMetrics,
|
|
380
411
|
]);
|
|
381
412
|
return token;
|
|
382
413
|
}
|
package/src/dev/use-esbuild.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { useState, useEffect } from "react";
|
|
|
5
5
|
import { bundleWorker } from "../bundle";
|
|
6
6
|
import { logger } from "../logger";
|
|
7
7
|
import type { Config } from "../config";
|
|
8
|
+
import type { WorkerRegistry } from "../dev-registry";
|
|
8
9
|
import type { Entry } from "../entry";
|
|
9
10
|
import type { CfModule } from "../worker";
|
|
10
11
|
import type { WatchMode } from "esbuild";
|
|
@@ -15,6 +16,7 @@ export type EsbuildBundle = {
|
|
|
15
16
|
entry: Entry;
|
|
16
17
|
type: "esm" | "commonjs";
|
|
17
18
|
modules: CfModule[];
|
|
19
|
+
sourceMapPath: string | undefined;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export function useEsbuild({
|
|
@@ -23,24 +25,32 @@ export function useEsbuild({
|
|
|
23
25
|
jsxFactory,
|
|
24
26
|
jsxFragment,
|
|
25
27
|
rules,
|
|
28
|
+
assets,
|
|
26
29
|
serveAssetsFromWorker,
|
|
27
30
|
tsconfig,
|
|
28
31
|
minify,
|
|
29
32
|
nodeCompat,
|
|
30
33
|
define,
|
|
31
34
|
noBundle,
|
|
35
|
+
workerDefinitions,
|
|
36
|
+
services,
|
|
37
|
+
firstPartyWorkerDevFacade,
|
|
32
38
|
}: {
|
|
33
39
|
entry: Entry;
|
|
34
40
|
destination: string | undefined;
|
|
35
41
|
jsxFactory: string | undefined;
|
|
36
42
|
jsxFragment: string | undefined;
|
|
37
43
|
rules: Config["rules"];
|
|
44
|
+
assets: Config["assets"];
|
|
38
45
|
define: Config["define"];
|
|
46
|
+
services: Config["services"];
|
|
39
47
|
serveAssetsFromWorker: boolean;
|
|
40
48
|
tsconfig: string | undefined;
|
|
41
49
|
minify: boolean | undefined;
|
|
42
50
|
nodeCompat: boolean | undefined;
|
|
43
51
|
noBundle: boolean;
|
|
52
|
+
workerDefinitions: WorkerRegistry;
|
|
53
|
+
firstPartyWorkerDevFacade: boolean | undefined;
|
|
44
54
|
}): EsbuildBundle | undefined {
|
|
45
55
|
const [bundle, setBundle] = useState<EsbuildBundle>();
|
|
46
56
|
const { exit } = useApp();
|
|
@@ -76,12 +86,14 @@ export function useEsbuild({
|
|
|
76
86
|
bundleType,
|
|
77
87
|
modules,
|
|
78
88
|
stop,
|
|
89
|
+
sourceMapPath,
|
|
79
90
|
}: Awaited<ReturnType<typeof bundleWorker>> = noBundle
|
|
80
91
|
? {
|
|
81
92
|
modules: [],
|
|
82
93
|
resolvedEntryPointPath: entry.file,
|
|
83
94
|
bundleType: entry.format === "modules" ? "esm" : "commonjs",
|
|
84
95
|
stop: undefined,
|
|
96
|
+
sourceMapPath: undefined,
|
|
85
97
|
}
|
|
86
98
|
: await bundleWorker(entry, destination, {
|
|
87
99
|
serveAssetsFromWorker,
|
|
@@ -94,6 +106,14 @@ export function useEsbuild({
|
|
|
94
106
|
nodeCompat,
|
|
95
107
|
define,
|
|
96
108
|
checkFetch: true,
|
|
109
|
+
assets: assets && {
|
|
110
|
+
...assets,
|
|
111
|
+
// disable the cache in dev
|
|
112
|
+
bypassCache: true,
|
|
113
|
+
},
|
|
114
|
+
workerDefinitions,
|
|
115
|
+
services,
|
|
116
|
+
firstPartyWorkerDevFacade,
|
|
97
117
|
});
|
|
98
118
|
|
|
99
119
|
// Capture the `stop()` method to use as the `useEffect()` destructor.
|
|
@@ -119,6 +139,7 @@ export function useEsbuild({
|
|
|
119
139
|
path: resolvedEntryPointPath,
|
|
120
140
|
type: bundleType,
|
|
121
141
|
modules,
|
|
142
|
+
sourceMapPath,
|
|
122
143
|
});
|
|
123
144
|
}
|
|
124
145
|
|
|
@@ -145,6 +166,10 @@ export function useEsbuild({
|
|
|
145
166
|
minify,
|
|
146
167
|
nodeCompat,
|
|
147
168
|
define,
|
|
169
|
+
assets,
|
|
170
|
+
services,
|
|
171
|
+
workerDefinitions,
|
|
172
|
+
firstPartyWorkerDevFacade,
|
|
148
173
|
]);
|
|
149
174
|
return bundle;
|
|
150
175
|
}
|