wrangler 0.0.0-e29a241 → 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 +25 -14
- package/bin/wrangler.js +13 -1
- package/miniflare-dist/index.mjs +4828 -21
- package/package.json +29 -24
- 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 +692 -321
- package/src/__tests__/dev.test.tsx +284 -18
- package/src/__tests__/guess-worker-format.test.ts +28 -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 +27 -769
- package/src/__tests__/init.test.ts +1042 -0
- package/src/__tests__/jest.setup.ts +4 -4
- package/src/__tests__/kv.test.ts +133 -61
- package/src/__tests__/logger.test.ts +115 -0
- package/src/__tests__/pages.test.ts +311 -26
- package/src/__tests__/publish.test.ts +2789 -618
- package/src/__tests__/r2.test.ts +26 -10
- package/src/__tests__/route.test.ts +4 -4
- package/src/__tests__/secret.test.ts +55 -34
- package/src/__tests__/tail.test.ts +146 -20
- package/src/__tests__/user.test.ts +131 -0
- package/src/__tests__/whoami.test.tsx +14 -9
- package/src/bundle.ts +30 -3
- 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 +13 -53
- package/src/config/environment.ts +88 -4
- package/src/config/index.ts +11 -4
- package/src/config/validation-helpers.ts +96 -7
- package/src/config/validation.ts +407 -79
- 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 +132 -78
- package/src/dev/local.tsx +115 -29
- package/src/dev/remote.tsx +23 -13
- package/src/dev/use-esbuild.ts +23 -5
- package/src/dialogs.tsx +16 -6
- package/src/entry.ts +83 -24
- package/src/environment-variables.ts +3 -1
- package/src/errors.ts +11 -0
- package/src/https-options.ts +3 -2
- package/src/index.tsx +619 -377
- package/src/inspect.ts +17 -11
- package/src/intl-polyfill.d.ts +139 -0
- 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 +883 -62
- package/src/parse.ts +1 -1
- package/src/proxy.ts +25 -11
- package/src/publish.ts +263 -141
- package/src/sites.tsx +27 -14
- package/src/tail/index.ts +2 -2
- package/src/tail/printing.ts +13 -8
- package/src/update-check.ts +19 -0
- package/src/user.tsx +116 -41
- 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 +21167 -50229
- package/miniflare-dist/index.mjs.map +0 -7
- package/src/__tests__/dev2.test.tsx +0 -154
- 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/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,28 +220,33 @@ function useLocalWorker({
|
|
|
143
220
|
);
|
|
144
221
|
const optionsArg = JSON.stringify(options, null);
|
|
145
222
|
|
|
146
|
-
|
|
147
|
-
local.current = spawn(
|
|
148
|
-
"
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
223
|
+
logger.log("⎔ Starting a local server...");
|
|
224
|
+
local.current = spawn(
|
|
225
|
+
"node",
|
|
226
|
+
[
|
|
227
|
+
"--experimental-vm-modules", // ensures that Miniflare can run ESM Workers
|
|
228
|
+
"--no-warnings", // hide annoying Node warnings
|
|
229
|
+
"--inspect", // start Miniflare listening for a debugger to attach
|
|
230
|
+
miniflareCLIPath,
|
|
231
|
+
optionsArg,
|
|
232
|
+
// "--log=VERBOSE", // uncomment this to Miniflare to log "everything"!
|
|
233
|
+
],
|
|
234
|
+
{
|
|
235
|
+
cwd: path.dirname(scriptPath),
|
|
236
|
+
}
|
|
237
|
+
);
|
|
155
238
|
|
|
156
239
|
local.current.on("close", (code) => {
|
|
157
240
|
if (code) {
|
|
158
|
-
|
|
241
|
+
logger.log(`Miniflare process exited with code ${code}`);
|
|
159
242
|
}
|
|
160
243
|
});
|
|
161
244
|
|
|
162
245
|
local.current.stdout?.on("data", (data: Buffer) => {
|
|
163
|
-
|
|
246
|
+
process.stdout.write(data);
|
|
164
247
|
});
|
|
165
248
|
|
|
166
249
|
local.current.stderr?.on("data", (data: Buffer) => {
|
|
167
|
-
console.error(`${data.toString()}`);
|
|
168
250
|
const matches =
|
|
169
251
|
/Debugger listening on (ws:\/\/127\.0\.0\.1:\d+\/[A-Za-z0-9-]+)/.exec(
|
|
170
252
|
data.toString()
|
|
@@ -176,29 +258,30 @@ function useLocalWorker({
|
|
|
176
258
|
|
|
177
259
|
local.current.on("exit", (code) => {
|
|
178
260
|
if (code) {
|
|
179
|
-
|
|
261
|
+
logger.error(`Miniflare process exited with code ${code}`);
|
|
180
262
|
}
|
|
181
263
|
});
|
|
182
264
|
|
|
183
265
|
local.current.on("error", (error: Error) => {
|
|
184
|
-
|
|
185
|
-
|
|
266
|
+
logger.error(`Miniflare process failed to spawn`);
|
|
267
|
+
logger.error(error);
|
|
186
268
|
});
|
|
187
269
|
|
|
188
270
|
removeSignalExitListener.current = onExit((_code, _signal) => {
|
|
189
|
-
|
|
271
|
+
logger.log("⎔ Shutting down local server.");
|
|
190
272
|
local.current?.kill();
|
|
191
273
|
local.current = undefined;
|
|
192
274
|
});
|
|
193
275
|
}
|
|
194
276
|
|
|
195
277
|
startLocalWorker().catch((err) => {
|
|
196
|
-
|
|
278
|
+
logger.error("local worker:", err);
|
|
197
279
|
});
|
|
198
280
|
|
|
199
281
|
return () => {
|
|
282
|
+
abortController.abort();
|
|
200
283
|
if (local.current) {
|
|
201
|
-
|
|
284
|
+
logger.log("⎔ Shutting down local server.");
|
|
202
285
|
local.current?.kill();
|
|
203
286
|
local.current = undefined;
|
|
204
287
|
removeSignalExitListener.current && removeSignalExitListener.current();
|
|
@@ -216,11 +299,14 @@ function useLocalWorker({
|
|
|
216
299
|
bindings.vars,
|
|
217
300
|
compatibilityDate,
|
|
218
301
|
compatibilityFlags,
|
|
219
|
-
|
|
302
|
+
localPersistencePath,
|
|
220
303
|
assetPaths,
|
|
221
304
|
publicDirectory,
|
|
222
305
|
rules,
|
|
223
306
|
bindings.wasm_modules,
|
|
307
|
+
bindings.text_blobs,
|
|
308
|
+
bindings.data_blobs,
|
|
309
|
+
crons,
|
|
224
310
|
]);
|
|
225
311
|
return { inspectorUrl };
|
|
226
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";
|
|
@@ -23,22 +25,29 @@ export function useEsbuild({
|
|
|
23
25
|
jsxFragment,
|
|
24
26
|
rules,
|
|
25
27
|
serveAssetsFromWorker,
|
|
28
|
+
tsconfig,
|
|
29
|
+
minify,
|
|
30
|
+
nodeCompat,
|
|
26
31
|
}: {
|
|
27
32
|
entry: Entry;
|
|
28
33
|
destination: string | undefined;
|
|
29
|
-
staticRoot:
|
|
34
|
+
staticRoot: string | undefined;
|
|
30
35
|
jsxFactory: string | undefined;
|
|
31
36
|
jsxFragment: string | undefined;
|
|
32
37
|
rules: Config["rules"];
|
|
33
38
|
serveAssetsFromWorker: boolean;
|
|
39
|
+
tsconfig: string | undefined;
|
|
40
|
+
minify: boolean | undefined;
|
|
41
|
+
nodeCompat: boolean | undefined;
|
|
34
42
|
}): EsbuildBundle | undefined {
|
|
35
43
|
const [bundle, setBundle] = useState<EsbuildBundle>();
|
|
44
|
+
const { exit } = useApp();
|
|
36
45
|
useEffect(() => {
|
|
37
46
|
let stopWatching: (() => void) | undefined = undefined;
|
|
38
47
|
|
|
39
48
|
const watchMode: WatchMode = {
|
|
40
49
|
async onRebuild(error) {
|
|
41
|
-
if (error)
|
|
50
|
+
if (error) logger.error("Watch build failed:", error);
|
|
42
51
|
else {
|
|
43
52
|
// nothing really changes here, so let's increment the id
|
|
44
53
|
// to change the return object's identity
|
|
@@ -64,6 +73,9 @@ export function useEsbuild({
|
|
|
64
73
|
jsxFragment,
|
|
65
74
|
rules,
|
|
66
75
|
watch: watchMode,
|
|
76
|
+
tsconfig,
|
|
77
|
+
minify,
|
|
78
|
+
nodeCompat,
|
|
67
79
|
});
|
|
68
80
|
|
|
69
81
|
// Capture the `stop()` method to use as the `useEffect()` destructor.
|
|
@@ -79,9 +91,11 @@ export function useEsbuild({
|
|
|
79
91
|
});
|
|
80
92
|
}
|
|
81
93
|
|
|
82
|
-
build().catch(() => {
|
|
83
|
-
// esbuild
|
|
84
|
-
//
|
|
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);
|
|
85
99
|
});
|
|
86
100
|
|
|
87
101
|
return () => {
|
|
@@ -95,6 +109,10 @@ export function useEsbuild({
|
|
|
95
109
|
jsxFragment,
|
|
96
110
|
serveAssetsFromWorker,
|
|
97
111
|
rules,
|
|
112
|
+
tsconfig,
|
|
113
|
+
exit,
|
|
114
|
+
minify,
|
|
115
|
+
nodeCompat,
|
|
98
116
|
]);
|
|
99
117
|
return bundle;
|
|
100
118
|
}
|
package/src/dialogs.tsx
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
1
2
|
import { Box, Text, useInput, render } from "ink";
|
|
2
3
|
import TextInput from "ink-text-input";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { useState } from "react";
|
|
6
|
+
import { logger } from "./logger";
|
|
5
7
|
type ConfirmProps = {
|
|
6
8
|
text: string;
|
|
7
9
|
onConfirm: (answer: boolean) => void;
|
|
8
10
|
};
|
|
9
11
|
function Confirm(props: ConfirmProps) {
|
|
10
|
-
useInput((input: string) => {
|
|
11
|
-
if (input === "y") {
|
|
12
|
+
useInput((input: string, key) => {
|
|
13
|
+
if (input === "y" || key.return === true) {
|
|
12
14
|
props.onConfirm(true);
|
|
13
15
|
} else if (input === "n") {
|
|
14
16
|
props.onConfirm(false);
|
|
15
17
|
} else {
|
|
16
|
-
|
|
18
|
+
logger.warn("Unrecognised input:", input);
|
|
17
19
|
}
|
|
18
20
|
});
|
|
19
21
|
return (
|
|
20
22
|
<Box>
|
|
21
|
-
<Text>
|
|
23
|
+
<Text>
|
|
24
|
+
{props.text} ({chalk.bold("y")}/n)
|
|
25
|
+
</Text>
|
|
22
26
|
</Box>
|
|
23
27
|
);
|
|
24
28
|
}
|
|
@@ -39,12 +43,13 @@ export function confirm(text: string): Promise<boolean> {
|
|
|
39
43
|
|
|
40
44
|
type PromptProps = {
|
|
41
45
|
text: string;
|
|
46
|
+
defaultValue?: string;
|
|
42
47
|
type?: "text" | "password";
|
|
43
48
|
onSubmit: (text: string) => void;
|
|
44
49
|
};
|
|
45
50
|
|
|
46
51
|
function Prompt(props: PromptProps) {
|
|
47
|
-
const [value, setValue] = useState("");
|
|
52
|
+
const [value, setValue] = useState(props.defaultValue || "");
|
|
48
53
|
|
|
49
54
|
return (
|
|
50
55
|
<Box>
|
|
@@ -61,11 +66,16 @@ function Prompt(props: PromptProps) {
|
|
|
61
66
|
);
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
export async function prompt(
|
|
69
|
+
export async function prompt(
|
|
70
|
+
text: string,
|
|
71
|
+
type: "text" | "password" = "text",
|
|
72
|
+
defaultValue?: string
|
|
73
|
+
): Promise<string> {
|
|
65
74
|
return new Promise((resolve) => {
|
|
66
75
|
const { unmount } = render(
|
|
67
76
|
<Prompt
|
|
68
77
|
text={text}
|
|
78
|
+
defaultValue={defaultValue}
|
|
69
79
|
type={type}
|
|
70
80
|
onSubmit={(inputText) => {
|
|
71
81
|
unmount();
|