wrangler 0.0.0-e2b7352 → 0.0.0-e2f9bb2
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 +24 -13
- package/bin/wrangler.js +3 -0
- package/miniflare-dist/index.mjs +4828 -21
- package/package.json +29 -22
- package/pages/functions/buildPlugin.ts +92 -0
- package/pages/functions/buildWorker.ts +80 -4
- package/pages/functions/filepath-routing.test.ts +11 -0
- package/pages/functions/filepath-routing.ts +8 -0
- package/pages/functions/routes.ts +6 -1
- package/pages/functions/template-plugin.ts +146 -0
- package/pages/functions/template-worker.ts +21 -8
- package/src/__tests__/config-cache.test.ts +36 -0
- package/src/__tests__/configuration.test.ts +386 -81
- package/src/__tests__/dev.test.tsx +242 -21
- package/src/__tests__/guess-worker-format.test.ts +18 -1
- package/src/__tests__/helpers/mock-cfetch.ts +5 -1
- package/src/__tests__/helpers/mock-console.ts +20 -3
- package/src/__tests__/helpers/mock-dialogs.ts +24 -0
- package/src/__tests__/helpers/mock-http-server.ts +46 -0
- package/src/__tests__/helpers/mock-istty.ts +27 -0
- package/src/__tests__/helpers/mock-oauth-flow.ts +255 -0
- package/src/__tests__/helpers/run-in-tmp.ts +7 -0
- package/src/__tests__/helpers/write-worker-source.ts +31 -0
- package/src/__tests__/https-options.test.ts +5 -2
- package/src/__tests__/index.test.ts +25 -759
- package/src/__tests__/init.test.ts +1042 -0
- package/src/__tests__/jest.setup.ts +4 -4
- package/src/__tests__/kv.test.ts +130 -56
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +290 -43
- package/src/__tests__/publish.test.ts +1699 -333
- package/src/__tests__/r2.test.ts +24 -8
- package/src/__tests__/route.test.ts +4 -4
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +97 -45
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +14 -9
- package/src/bundle.ts +15 -1
- package/src/cfetch/internal.ts +0 -2
- package/src/cli.ts +5 -11
- package/src/config/README.md +1 -1
- package/src/config/config.ts +20 -4
- package/src/config/environment.ts +26 -3
- package/src/config/index.ts +2 -1
- package/src/config/validation-helpers.ts +26 -5
- package/src/config/validation.ts +233 -41
- package/src/config-cache.ts +45 -0
- package/src/create-worker-preview.ts +22 -13
- package/src/create-worker-upload-form.ts +32 -9
- package/src/dev/dev-vars.ts +36 -0
- package/src/dev/dev.tsx +60 -34
- package/src/dev/local.tsx +101 -21
- package/src/dev/remote.tsx +23 -13
- package/src/dev/use-esbuild.ts +19 -5
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +38 -11
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +3 -2
- package/src/index.tsx +529 -303
- package/src/inspect.ts +17 -11
- package/src/logger.ts +66 -0
- package/src/miniflare-cli/index.ts +4 -0
- package/src/miniflare-cli/request-context.ts +40 -0
- package/src/module-collection.ts +7 -7
- package/src/open-in-browser.ts +5 -4
- package/src/package-manager.ts +9 -8
- package/src/pages.tsx +860 -55
- package/src/parse.ts +1 -1
- package/src/proxy.ts +25 -11
- package/src/publish.ts +260 -141
- package/src/sites.tsx +27 -14
- package/src/tail/index.ts +1 -1
- package/src/tail/printing.ts +13 -8
- package/src/update-check.ts +19 -0
- package/src/user.tsx +104 -38
- package/src/whoami.tsx +2 -1
- package/src/worker.ts +15 -6
- package/templates/gitignore +171 -0
- package/templates/static-asset-facade.js +1 -1
- package/wrangler-dist/cli.js +20948 -50169
- package/miniflare-dist/index.mjs.map +0 -7
- package/src/__tests__/logout.test.ts +0 -52
- package/src/__tests__/sentry.test.ts +0 -146
- package/src/reporting.ts +0 -131
- package/wrangler-dist/cli.js.map +0 -7
package/src/dev/dev.tsx
CHANGED
|
@@ -9,8 +9,8 @@ import onExit from "signal-exit";
|
|
|
9
9
|
import tmp from "tmp-promise";
|
|
10
10
|
import { fetch } from "undici";
|
|
11
11
|
import { runCustomBuild } from "../entry";
|
|
12
|
+
import { logger } from "../logger";
|
|
12
13
|
import openInBrowser from "../open-in-browser";
|
|
13
|
-
import { reportError } from "../reporting";
|
|
14
14
|
import { getAPIToken } from "../user";
|
|
15
15
|
import { Local } from "./local";
|
|
16
16
|
import { Remote } from "./remote";
|
|
@@ -28,24 +28,27 @@ export type DevProps = {
|
|
|
28
28
|
ip: string;
|
|
29
29
|
inspectorPort: number;
|
|
30
30
|
rules: Config["rules"];
|
|
31
|
-
accountId:
|
|
31
|
+
accountId: string | undefined;
|
|
32
32
|
initialMode: "local" | "remote";
|
|
33
|
-
jsxFactory:
|
|
34
|
-
jsxFragment:
|
|
33
|
+
jsxFactory: string | undefined;
|
|
34
|
+
jsxFragment: string | undefined;
|
|
35
35
|
tsconfig: string | undefined;
|
|
36
36
|
upstreamProtocol: "https" | "http";
|
|
37
37
|
localProtocol: "https" | "http";
|
|
38
38
|
enableLocalPersistence: boolean;
|
|
39
39
|
bindings: CfWorkerInit["bindings"];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
crons: Config["triggers"]["crons"];
|
|
41
|
+
public: string | undefined;
|
|
42
|
+
assetPaths: AssetPaths | undefined;
|
|
43
|
+
compatibilityDate: string;
|
|
44
|
+
compatibilityFlags: string[] | undefined;
|
|
45
|
+
usageModel: "bundled" | "unbound" | undefined;
|
|
46
|
+
minify: boolean | undefined;
|
|
47
|
+
nodeCompat: boolean | undefined;
|
|
45
48
|
build: {
|
|
46
|
-
command?:
|
|
47
|
-
cwd?:
|
|
48
|
-
watch_dir?:
|
|
49
|
+
command?: string | undefined;
|
|
50
|
+
cwd?: string | undefined;
|
|
51
|
+
watch_dir?: string | undefined;
|
|
49
52
|
};
|
|
50
53
|
env: string | undefined;
|
|
51
54
|
legacyEnv: boolean;
|
|
@@ -65,7 +68,7 @@ export function DevImplementation(props: DevProps): JSX.Element {
|
|
|
65
68
|
|
|
66
69
|
if (props.public && props.entry.format === "service-worker") {
|
|
67
70
|
throw new Error(
|
|
68
|
-
"You cannot use the service
|
|
71
|
+
"You cannot use the service-worker format with a `public` directory."
|
|
69
72
|
);
|
|
70
73
|
}
|
|
71
74
|
|
|
@@ -77,7 +80,13 @@ export function DevImplementation(props: DevProps): JSX.Element {
|
|
|
77
80
|
|
|
78
81
|
if (props.bindings.text_blobs && props.entry.format === "modules") {
|
|
79
82
|
throw new Error(
|
|
80
|
-
"You cannot configure [text_blobs] with an ES module worker. Instead, import the file directly in your code, and optionally configure `[
|
|
83
|
+
"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"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (props.bindings.data_blobs && props.entry.format === "modules") {
|
|
88
|
+
throw new Error(
|
|
89
|
+
"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"
|
|
81
90
|
);
|
|
82
91
|
}
|
|
83
92
|
|
|
@@ -90,6 +99,8 @@ export function DevImplementation(props: DevProps): JSX.Element {
|
|
|
90
99
|
jsxFragment: props.jsxFragment,
|
|
91
100
|
serveAssetsFromWorker: !!props.public,
|
|
92
101
|
tsconfig: props.tsconfig,
|
|
102
|
+
minify: props.minify,
|
|
103
|
+
nodeCompat: props.nodeCompat,
|
|
93
104
|
});
|
|
94
105
|
|
|
95
106
|
// only load the UI if we're running in a supported environment
|
|
@@ -129,11 +140,16 @@ function InteractiveDevSession(props: InteractiveDevSessionProps) {
|
|
|
129
140
|
<>
|
|
130
141
|
<DevSession {...props} local={toggles.local} />
|
|
131
142
|
<Box borderStyle="round" paddingLeft={1} paddingRight={1}>
|
|
132
|
-
<Text>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
</Text>
|
|
143
|
+
<Text bold={true}>[b]</Text>
|
|
144
|
+
<Text> open a browser, </Text>
|
|
145
|
+
<Text bold={true}>[d]</Text>
|
|
146
|
+
<Text> open Devtools, </Text>
|
|
147
|
+
<Text bold={true}>[l]</Text>
|
|
148
|
+
<Text> {toggles.local ? "turn off" : "turn on"} local mode, </Text>
|
|
149
|
+
<Text bold={true}>[c]</Text>
|
|
150
|
+
<Text> clear console, </Text>
|
|
151
|
+
<Text bold={true}>[x]</Text>
|
|
152
|
+
<Text> to exit</Text>
|
|
137
153
|
</Box>
|
|
138
154
|
</>
|
|
139
155
|
);
|
|
@@ -157,6 +173,7 @@ function DevSession(props: DevSessionProps) {
|
|
|
157
173
|
rules={props.rules}
|
|
158
174
|
inspectorPort={props.inspectorPort}
|
|
159
175
|
enableLocalPersistence={props.enableLocalPersistence}
|
|
176
|
+
crons={props.crons}
|
|
160
177
|
/>
|
|
161
178
|
) : (
|
|
162
179
|
<Remote
|
|
@@ -197,7 +214,9 @@ function useTmpDir(): string | undefined {
|
|
|
197
214
|
setDirectory(dir);
|
|
198
215
|
return;
|
|
199
216
|
} catch (err) {
|
|
200
|
-
|
|
217
|
+
logger.error(
|
|
218
|
+
"Failed to create temporary directory to store built files."
|
|
219
|
+
);
|
|
201
220
|
handleError(err);
|
|
202
221
|
}
|
|
203
222
|
return () => {
|
|
@@ -210,9 +229,9 @@ function useTmpDir(): string | undefined {
|
|
|
210
229
|
function useCustomBuild(
|
|
211
230
|
expectedEntry: Entry,
|
|
212
231
|
build: {
|
|
213
|
-
command?:
|
|
214
|
-
cwd?:
|
|
215
|
-
watch_dir?:
|
|
232
|
+
command?: string | undefined;
|
|
233
|
+
cwd?: string | undefined;
|
|
234
|
+
watch_dir?: string | undefined;
|
|
216
235
|
}
|
|
217
236
|
): void {
|
|
218
237
|
useEffect(() => {
|
|
@@ -224,9 +243,9 @@ function useCustomBuild(
|
|
|
224
243
|
ignoreInitial: true,
|
|
225
244
|
}).on("all", (_event, filePath) => {
|
|
226
245
|
//TODO: we should buffer requests to the proxy until this completes
|
|
227
|
-
|
|
246
|
+
logger.log(`The file ${filePath} changed, restarting build...`);
|
|
228
247
|
runCustomBuild(expectedEntry.file, build).catch((err) => {
|
|
229
|
-
|
|
248
|
+
logger.error("Custom build failed:", err);
|
|
230
249
|
});
|
|
231
250
|
});
|
|
232
251
|
}
|
|
@@ -273,12 +292,12 @@ function useTunnel(toggle: boolean) {
|
|
|
273
292
|
try {
|
|
274
293
|
await commandExists("cloudflared");
|
|
275
294
|
} catch (e) {
|
|
276
|
-
|
|
295
|
+
logger.warn(
|
|
277
296
|
"To share your worker on the Internet, please install `cloudflared` from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation"
|
|
278
297
|
);
|
|
279
298
|
return;
|
|
280
299
|
}
|
|
281
|
-
|
|
300
|
+
logger.log("⎔ Starting a tunnel...");
|
|
282
301
|
tunnel.current = spawn("cloudflared", [
|
|
283
302
|
"tunnel",
|
|
284
303
|
"--url",
|
|
@@ -289,30 +308,29 @@ function useTunnel(toggle: boolean) {
|
|
|
289
308
|
|
|
290
309
|
tunnel.current.on("close", (code) => {
|
|
291
310
|
if (code) {
|
|
292
|
-
|
|
311
|
+
logger.log(`Tunnel process exited with code ${code}`);
|
|
293
312
|
}
|
|
294
313
|
});
|
|
295
314
|
|
|
296
315
|
removeSignalExitListener.current = onExit((_code, _signal) => {
|
|
297
|
-
|
|
316
|
+
logger.log("⎔ Shutting down local tunnel.");
|
|
298
317
|
tunnel.current?.kill();
|
|
299
318
|
tunnel.current = undefined;
|
|
300
319
|
});
|
|
301
320
|
|
|
302
321
|
const hostName = await findTunnelHostname();
|
|
303
322
|
await clipboardy.write(hostName);
|
|
304
|
-
|
|
323
|
+
logger.log(`⬣ Sharing at ${hostName}, copied to clipboard.`);
|
|
305
324
|
}
|
|
306
325
|
}
|
|
307
326
|
|
|
308
327
|
startTunnel().catch(async (err) => {
|
|
309
|
-
|
|
310
|
-
await reportError(err);
|
|
328
|
+
logger.error("tunnel:", err);
|
|
311
329
|
});
|
|
312
330
|
|
|
313
331
|
return () => {
|
|
314
332
|
if (tunnel.current) {
|
|
315
|
-
|
|
333
|
+
logger.log("⎔ Shutting down tunnel.");
|
|
316
334
|
tunnel.current?.kill();
|
|
317
335
|
tunnel.current = undefined;
|
|
318
336
|
removeSignalExitListener.current && removeSignalExitListener.current();
|
|
@@ -335,6 +353,7 @@ function useHotkeys(
|
|
|
335
353
|
) {
|
|
336
354
|
// UGH, we should put port in context instead
|
|
337
355
|
const [toggles, setToggles] = useState(initial);
|
|
356
|
+
const { exit } = useApp();
|
|
338
357
|
useInput(
|
|
339
358
|
async (
|
|
340
359
|
input,
|
|
@@ -342,6 +361,13 @@ function useHotkeys(
|
|
|
342
361
|
key
|
|
343
362
|
) => {
|
|
344
363
|
switch (input.toLowerCase()) {
|
|
364
|
+
// clear console
|
|
365
|
+
case "c":
|
|
366
|
+
console.clear();
|
|
367
|
+
// This console.log causes Ink to re-render the `DevSession` component.
|
|
368
|
+
// Couldn't find a better way to tell it to do so...
|
|
369
|
+
console.log();
|
|
370
|
+
break;
|
|
345
371
|
// open browser
|
|
346
372
|
case "b": {
|
|
347
373
|
await openInBrowser(`${localProtocol}://${ip}:${port}`);
|
|
@@ -365,7 +391,7 @@ function useHotkeys(
|
|
|
365
391
|
// shut down
|
|
366
392
|
case "q":
|
|
367
393
|
case "x":
|
|
368
|
-
|
|
394
|
+
exit();
|
|
369
395
|
break;
|
|
370
396
|
default:
|
|
371
397
|
// nothing?
|
package/src/dev/local.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { useState, useEffect, useRef } from "react";
|
|
6
6
|
import onExit from "signal-exit";
|
|
7
7
|
import useInspector from "../inspect";
|
|
8
|
+
import { logger } from "../logger";
|
|
8
9
|
import { DEFAULT_MODULE_RULES } from "../module-collection";
|
|
9
10
|
import { waitForPortToBeAvailable } from "../proxy";
|
|
10
11
|
import type { Config } from "../config";
|
|
@@ -14,19 +15,20 @@ import type { EsbuildBundle } from "./use-esbuild";
|
|
|
14
15
|
import type { MiniflareOptions } from "miniflare";
|
|
15
16
|
|
|
16
17
|
interface LocalProps {
|
|
17
|
-
name:
|
|
18
|
+
name: string | undefined;
|
|
18
19
|
bundle: EsbuildBundle | undefined;
|
|
19
20
|
format: CfScriptFormat | undefined;
|
|
20
|
-
compatibilityDate: string
|
|
21
|
-
compatibilityFlags:
|
|
21
|
+
compatibilityDate: string;
|
|
22
|
+
compatibilityFlags: string[] | undefined;
|
|
22
23
|
bindings: CfWorkerInit["bindings"];
|
|
23
|
-
assetPaths:
|
|
24
|
-
public:
|
|
24
|
+
assetPaths: AssetPaths | undefined;
|
|
25
|
+
public: string | undefined;
|
|
25
26
|
port: number;
|
|
26
27
|
ip: string;
|
|
27
28
|
rules: Config["rules"];
|
|
28
29
|
inspectorPort: number;
|
|
29
30
|
enableLocalPersistence: boolean;
|
|
31
|
+
crons: Config["triggers"]["crons"];
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export function Local(props: LocalProps) {
|
|
@@ -52,17 +54,33 @@ function useLocalWorker({
|
|
|
52
54
|
rules,
|
|
53
55
|
enableLocalPersistence,
|
|
54
56
|
ip,
|
|
57
|
+
crons,
|
|
55
58
|
}: LocalProps) {
|
|
56
59
|
// TODO: pass vars via command line
|
|
57
60
|
const local = useRef<ReturnType<typeof spawn>>();
|
|
58
61
|
const removeSignalExitListener = useRef<() => void>();
|
|
59
62
|
const [inspectorUrl, setInspectorUrl] = useState<string | undefined>();
|
|
63
|
+
// if we're using local persistence for data, we should use the cwd
|
|
64
|
+
// as an explicit path, or else it'll use the temp dir
|
|
65
|
+
// which disappears when dev ends
|
|
66
|
+
const localPersistencePath = enableLocalPersistence
|
|
67
|
+
? // Maybe we could make the path configurable as well?
|
|
68
|
+
path.join(process.cwd(), "wrangler-local-state")
|
|
69
|
+
: // We otherwise choose null, but choose true later
|
|
70
|
+
// so that it's persisted in the temp dir across a dev session
|
|
71
|
+
// even when we change source and reload
|
|
72
|
+
null;
|
|
60
73
|
useEffect(() => {
|
|
74
|
+
const abortController = new AbortController();
|
|
61
75
|
async function startLocalWorker() {
|
|
62
76
|
if (!bundle || !format) return;
|
|
63
77
|
|
|
64
78
|
// port for the worker
|
|
65
|
-
await waitForPortToBeAvailable(port, {
|
|
79
|
+
await waitForPortToBeAvailable(port, {
|
|
80
|
+
retryPeriod: 200,
|
|
81
|
+
timeout: 2000,
|
|
82
|
+
abortSignal: abortController.signal,
|
|
83
|
+
});
|
|
66
84
|
|
|
67
85
|
if (publicDirectory) {
|
|
68
86
|
throw new Error(
|
|
@@ -81,7 +99,35 @@ function useLocalWorker({
|
|
|
81
99
|
|
|
82
100
|
const scriptPath = realpathSync(bundle.path);
|
|
83
101
|
|
|
84
|
-
|
|
102
|
+
// the wasm_modules/text_blobs/data_blobs bindings are
|
|
103
|
+
// relative to process.cwd(), but the actual worker bundle
|
|
104
|
+
// is in the temp output directory; so we rewrite the paths to be absolute,
|
|
105
|
+
// letting miniflare resolve them correctly
|
|
106
|
+
|
|
107
|
+
// wasm
|
|
108
|
+
const wasmBindings: Record<string, string> = {};
|
|
109
|
+
for (const [name, filePath] of Object.entries(
|
|
110
|
+
bindings.wasm_modules || {}
|
|
111
|
+
)) {
|
|
112
|
+
wasmBindings[name] = path.join(process.cwd(), filePath);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// text
|
|
116
|
+
const textBlobBindings: Record<string, string> = {};
|
|
117
|
+
for (const [name, filePath] of Object.entries(
|
|
118
|
+
bindings.text_blobs || {}
|
|
119
|
+
)) {
|
|
120
|
+
textBlobBindings[name] = path.join(process.cwd(), filePath);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// data
|
|
124
|
+
const dataBlobBindings: Record<string, string> = {};
|
|
125
|
+
for (const [name, filePath] of Object.entries(
|
|
126
|
+
bindings.data_blobs || {}
|
|
127
|
+
)) {
|
|
128
|
+
dataBlobBindings[name] = path.join(process.cwd(), filePath);
|
|
129
|
+
}
|
|
130
|
+
|
|
85
131
|
if (format === "service-worker") {
|
|
86
132
|
for (const { type, name } of bundle.modules) {
|
|
87
133
|
if (type === "compiled-wasm") {
|
|
@@ -91,6 +137,20 @@ function useLocalWorker({
|
|
|
91
137
|
// characters with an underscore.
|
|
92
138
|
const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
93
139
|
wasmBindings[identifier] = name;
|
|
140
|
+
} else if (type === "text") {
|
|
141
|
+
// In service-worker format, text modules are referenced by global identifiers,
|
|
142
|
+
// so we convert it here.
|
|
143
|
+
// This identifier has to be a valid JS identifier, so we replace all non alphanumeric
|
|
144
|
+
// characters with an underscore.
|
|
145
|
+
const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
146
|
+
textBlobBindings[identifier] = name;
|
|
147
|
+
} else if (type === "buffer") {
|
|
148
|
+
// In service-worker format, data blobs are referenced by global identifiers,
|
|
149
|
+
// so we convert it here.
|
|
150
|
+
// This identifier has to be a valid JS identifier, so we replace all non alphanumeric
|
|
151
|
+
// characters with an underscore.
|
|
152
|
+
const identifier = name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
153
|
+
dataBlobBindings[identifier] = name;
|
|
94
154
|
}
|
|
95
155
|
}
|
|
96
156
|
}
|
|
@@ -111,14 +171,28 @@ function useLocalWorker({
|
|
|
111
171
|
compatibilityDate,
|
|
112
172
|
compatibilityFlags,
|
|
113
173
|
kvNamespaces: bindings.kv_namespaces?.map((kv) => kv.binding),
|
|
114
|
-
kvPersist: enableLocalPersistence,
|
|
115
174
|
durableObjects: Object.fromEntries(
|
|
116
175
|
(bindings.durable_objects?.bindings ?? []).map<[string, string]>(
|
|
117
176
|
(value) => [value.name, value.class_name]
|
|
118
177
|
)
|
|
119
178
|
),
|
|
120
|
-
|
|
121
|
-
|
|
179
|
+
...(localPersistencePath
|
|
180
|
+
? {
|
|
181
|
+
kvPersist: path.join(localPersistencePath, "kv"),
|
|
182
|
+
durableObjectsPersist: path.join(localPersistencePath, "do"),
|
|
183
|
+
cachePersist: path.join(localPersistencePath, "cache"),
|
|
184
|
+
}
|
|
185
|
+
: {
|
|
186
|
+
// We mark these as true, so that they'll
|
|
187
|
+
// persist in the temp directory.
|
|
188
|
+
// This means they'll persist across a dev session,
|
|
189
|
+
// even if we change source and reload,
|
|
190
|
+
// and be deleted when the dev session ends
|
|
191
|
+
durableObjectsPersist: true,
|
|
192
|
+
cachePersist: true,
|
|
193
|
+
kvPersist: true,
|
|
194
|
+
}),
|
|
195
|
+
|
|
122
196
|
sitePath: assetPaths?.assetDirectory
|
|
123
197
|
? path.join(assetPaths.baseDirectory, assetPaths.assetDirectory)
|
|
124
198
|
: undefined,
|
|
@@ -130,8 +204,11 @@ function useLocalWorker({
|
|
|
130
204
|
: undefined,
|
|
131
205
|
bindings: bindings.vars,
|
|
132
206
|
wasmBindings,
|
|
207
|
+
textBlobBindings,
|
|
208
|
+
dataBlobBindings,
|
|
133
209
|
sourceMap: true,
|
|
134
210
|
logUnhandledRejections: true,
|
|
211
|
+
crons,
|
|
135
212
|
};
|
|
136
213
|
|
|
137
214
|
// The path to the Miniflare CLI assumes that this file is being run from
|
|
@@ -143,7 +220,7 @@ function useLocalWorker({
|
|
|
143
220
|
);
|
|
144
221
|
const optionsArg = JSON.stringify(options, null);
|
|
145
222
|
|
|
146
|
-
|
|
223
|
+
logger.log("⎔ Starting a local server...");
|
|
147
224
|
local.current = spawn(
|
|
148
225
|
"node",
|
|
149
226
|
[
|
|
@@ -161,16 +238,15 @@ function useLocalWorker({
|
|
|
161
238
|
|
|
162
239
|
local.current.on("close", (code) => {
|
|
163
240
|
if (code) {
|
|
164
|
-
|
|
241
|
+
logger.log(`Miniflare process exited with code ${code}`);
|
|
165
242
|
}
|
|
166
243
|
});
|
|
167
244
|
|
|
168
245
|
local.current.stdout?.on("data", (data: Buffer) => {
|
|
169
|
-
|
|
246
|
+
process.stdout.write(data);
|
|
170
247
|
});
|
|
171
248
|
|
|
172
249
|
local.current.stderr?.on("data", (data: Buffer) => {
|
|
173
|
-
console.error(`${data.toString()}`);
|
|
174
250
|
const matches =
|
|
175
251
|
/Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)/.exec(
|
|
176
252
|
data.toString()
|
|
@@ -182,29 +258,30 @@ function useLocalWorker({
|
|
|
182
258
|
|
|
183
259
|
local.current.on("exit", (code) => {
|
|
184
260
|
if (code) {
|
|
185
|
-
|
|
261
|
+
logger.error(`Miniflare process exited with code ${code}`);
|
|
186
262
|
}
|
|
187
263
|
});
|
|
188
264
|
|
|
189
265
|
local.current.on("error", (error: Error) => {
|
|
190
|
-
|
|
191
|
-
|
|
266
|
+
logger.error(`Miniflare process failed to spawn`);
|
|
267
|
+
logger.error(error);
|
|
192
268
|
});
|
|
193
269
|
|
|
194
270
|
removeSignalExitListener.current = onExit((_code, _signal) => {
|
|
195
|
-
|
|
271
|
+
logger.log("⎔ Shutting down local server.");
|
|
196
272
|
local.current?.kill();
|
|
197
273
|
local.current = undefined;
|
|
198
274
|
});
|
|
199
275
|
}
|
|
200
276
|
|
|
201
277
|
startLocalWorker().catch((err) => {
|
|
202
|
-
|
|
278
|
+
logger.error("local worker:", err);
|
|
203
279
|
});
|
|
204
280
|
|
|
205
281
|
return () => {
|
|
282
|
+
abortController.abort();
|
|
206
283
|
if (local.current) {
|
|
207
|
-
|
|
284
|
+
logger.log("⎔ Shutting down local server.");
|
|
208
285
|
local.current?.kill();
|
|
209
286
|
local.current = undefined;
|
|
210
287
|
removeSignalExitListener.current && removeSignalExitListener.current();
|
|
@@ -222,11 +299,14 @@ function useLocalWorker({
|
|
|
222
299
|
bindings.vars,
|
|
223
300
|
compatibilityDate,
|
|
224
301
|
compatibilityFlags,
|
|
225
|
-
|
|
302
|
+
localPersistencePath,
|
|
226
303
|
assetPaths,
|
|
227
304
|
publicDirectory,
|
|
228
305
|
rules,
|
|
229
306
|
bindings.wasm_modules,
|
|
307
|
+
bindings.text_blobs,
|
|
308
|
+
bindings.data_blobs,
|
|
309
|
+
crons,
|
|
230
310
|
]);
|
|
231
311
|
return { inspectorUrl };
|
|
232
312
|
}
|
package/src/dev/remote.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { useState, useEffect, useRef } from "react";
|
|
5
5
|
import { createWorkerPreview } from "../create-worker-preview";
|
|
6
6
|
import useInspector from "../inspect";
|
|
7
|
+
import { logger } from "../logger";
|
|
7
8
|
import { usePreviewServer } from "../proxy";
|
|
8
9
|
import { syncAssets } from "../sites";
|
|
9
10
|
import type { CfPreviewToken } from "../create-worker-preview";
|
|
@@ -15,18 +16,18 @@ export function Remote(props: {
|
|
|
15
16
|
name: string | undefined;
|
|
16
17
|
bundle: EsbuildBundle | undefined;
|
|
17
18
|
format: CfScriptFormat | undefined;
|
|
18
|
-
public:
|
|
19
|
-
assetPaths:
|
|
19
|
+
public: string | undefined;
|
|
20
|
+
assetPaths: AssetPaths | undefined;
|
|
20
21
|
port: number;
|
|
21
22
|
ip: string;
|
|
22
23
|
localProtocol: "https" | "http";
|
|
23
24
|
inspectorPort: number;
|
|
24
|
-
accountId:
|
|
25
|
-
apiToken:
|
|
25
|
+
accountId: string | undefined;
|
|
26
|
+
apiToken: string | undefined;
|
|
26
27
|
bindings: CfWorkerInit["bindings"];
|
|
27
|
-
compatibilityDate: string
|
|
28
|
-
compatibilityFlags:
|
|
29
|
-
usageModel:
|
|
28
|
+
compatibilityDate: string;
|
|
29
|
+
compatibilityFlags: string[] | undefined;
|
|
30
|
+
usageModel: "bundled" | "unbound" | undefined;
|
|
30
31
|
env: string | undefined;
|
|
31
32
|
legacyEnv: boolean | undefined;
|
|
32
33
|
zone: { id: string; host: string } | undefined;
|
|
@@ -75,11 +76,11 @@ export function useWorker(props: {
|
|
|
75
76
|
accountId: string;
|
|
76
77
|
apiToken: string;
|
|
77
78
|
bindings: CfWorkerInit["bindings"];
|
|
78
|
-
assetPaths:
|
|
79
|
+
assetPaths: AssetPaths | undefined;
|
|
79
80
|
port: number;
|
|
80
81
|
compatibilityDate: string | undefined;
|
|
81
82
|
compatibilityFlags: string[] | undefined;
|
|
82
|
-
usageModel:
|
|
83
|
+
usageModel: "bundled" | "unbound" | undefined;
|
|
83
84
|
env: string | undefined;
|
|
84
85
|
legacyEnv: boolean | undefined;
|
|
85
86
|
zone: { id: string; host: string } | undefined;
|
|
@@ -106,6 +107,7 @@ export function useWorker(props: {
|
|
|
106
107
|
const startedRef = useRef(false);
|
|
107
108
|
|
|
108
109
|
useEffect(() => {
|
|
110
|
+
const abortController = new AbortController();
|
|
109
111
|
async function start() {
|
|
110
112
|
setToken(undefined); // reset token in case we're re-running
|
|
111
113
|
|
|
@@ -114,7 +116,7 @@ export function useWorker(props: {
|
|
|
114
116
|
if (!startedRef.current) {
|
|
115
117
|
startedRef.current = true;
|
|
116
118
|
} else {
|
|
117
|
-
|
|
119
|
+
logger.log("⎔ Detected changes, restarted server.");
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
const assets = await syncAssets(
|
|
@@ -125,7 +127,8 @@ export function useWorker(props: {
|
|
|
125
127
|
// concept of service environments for kv namespaces yet).
|
|
126
128
|
name + (!props.legacyEnv && props.env ? `-${props.env}` : ""),
|
|
127
129
|
assetPaths,
|
|
128
|
-
true
|
|
130
|
+
true,
|
|
131
|
+
false
|
|
129
132
|
); // TODO: cancellable?
|
|
130
133
|
|
|
131
134
|
const content = await readFile(bundle.path, "utf-8");
|
|
@@ -173,15 +176,22 @@ export function useWorker(props: {
|
|
|
173
176
|
accountId,
|
|
174
177
|
apiToken,
|
|
175
178
|
},
|
|
176
|
-
{ env: props.env, legacyEnv: props.legacyEnv, zone: props.zone }
|
|
179
|
+
{ env: props.env, legacyEnv: props.legacyEnv, zone: props.zone },
|
|
180
|
+
abortController.signal
|
|
177
181
|
)
|
|
178
182
|
);
|
|
179
183
|
}
|
|
180
184
|
start().catch((err) => {
|
|
181
185
|
// we want to log the error, but not end the process
|
|
182
186
|
// since it could recover after the developer fixes whatever's wrong
|
|
183
|
-
|
|
187
|
+
if ((err as { code: string }).code !== "ABORT_ERR") {
|
|
188
|
+
logger.error("Error on remote worker:", err);
|
|
189
|
+
}
|
|
184
190
|
});
|
|
191
|
+
|
|
192
|
+
return () => {
|
|
193
|
+
abortController.abort();
|
|
194
|
+
};
|
|
185
195
|
}, [
|
|
186
196
|
name,
|
|
187
197
|
bundle,
|
package/src/dev/use-esbuild.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
|
+
import { useApp } from "ink";
|
|
2
3
|
import { useState, useEffect } from "react";
|
|
3
4
|
import { bundleWorker } from "../bundle";
|
|
5
|
+
import { logger } from "../logger";
|
|
4
6
|
import type { Config } from "../config";
|
|
5
7
|
import type { Entry } from "../entry";
|
|
6
8
|
import type { CfModule } from "../worker";
|
|
@@ -24,23 +26,28 @@ export function useEsbuild({
|
|
|
24
26
|
rules,
|
|
25
27
|
serveAssetsFromWorker,
|
|
26
28
|
tsconfig,
|
|
29
|
+
minify,
|
|
30
|
+
nodeCompat,
|
|
27
31
|
}: {
|
|
28
32
|
entry: Entry;
|
|
29
33
|
destination: string | undefined;
|
|
30
|
-
staticRoot:
|
|
34
|
+
staticRoot: string | undefined;
|
|
31
35
|
jsxFactory: string | undefined;
|
|
32
36
|
jsxFragment: string | undefined;
|
|
33
37
|
rules: Config["rules"];
|
|
34
38
|
serveAssetsFromWorker: boolean;
|
|
35
39
|
tsconfig: string | undefined;
|
|
40
|
+
minify: boolean | undefined;
|
|
41
|
+
nodeCompat: boolean | undefined;
|
|
36
42
|
}): EsbuildBundle | undefined {
|
|
37
43
|
const [bundle, setBundle] = useState<EsbuildBundle>();
|
|
44
|
+
const { exit } = useApp();
|
|
38
45
|
useEffect(() => {
|
|
39
46
|
let stopWatching: (() => void) | undefined = undefined;
|
|
40
47
|
|
|
41
48
|
const watchMode: WatchMode = {
|
|
42
49
|
async onRebuild(error) {
|
|
43
|
-
if (error)
|
|
50
|
+
if (error) logger.error("Watch build failed:", error);
|
|
44
51
|
else {
|
|
45
52
|
// nothing really changes here, so let's increment the id
|
|
46
53
|
// to change the return object's identity
|
|
@@ -67,6 +74,8 @@ export function useEsbuild({
|
|
|
67
74
|
rules,
|
|
68
75
|
watch: watchMode,
|
|
69
76
|
tsconfig,
|
|
77
|
+
minify,
|
|
78
|
+
nodeCompat,
|
|
70
79
|
});
|
|
71
80
|
|
|
72
81
|
// Capture the `stop()` method to use as the `useEffect()` destructor.
|
|
@@ -82,9 +91,11 @@ export function useEsbuild({
|
|
|
82
91
|
});
|
|
83
92
|
}
|
|
84
93
|
|
|
85
|
-
build().catch(() => {
|
|
86
|
-
// esbuild
|
|
87
|
-
//
|
|
94
|
+
build().catch((err) => {
|
|
95
|
+
// If esbuild fails on first run, we want to quit the process
|
|
96
|
+
// since we can't recover from here
|
|
97
|
+
// related: https://github.com/evanw/esbuild/issues/1037
|
|
98
|
+
exit(err);
|
|
88
99
|
});
|
|
89
100
|
|
|
90
101
|
return () => {
|
|
@@ -99,6 +110,9 @@ export function useEsbuild({
|
|
|
99
110
|
serveAssetsFromWorker,
|
|
100
111
|
rules,
|
|
101
112
|
tsconfig,
|
|
113
|
+
exit,
|
|
114
|
+
minify,
|
|
115
|
+
nodeCompat,
|
|
102
116
|
]);
|
|
103
117
|
return bundle;
|
|
104
118
|
}
|