wrangler 2.1.7 → 2.1.9
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/package.json +3 -3
- package/src/__tests__/dev.test.tsx +13 -12
- package/src/__tests__/init.test.ts +99 -0
- package/src/__tests__/publish.test.ts +7 -4
- package/src/api/dev.ts +1 -0
- package/src/bundle.ts +11 -1
- package/src/config/index.ts +14 -4
- package/src/dev/dev.tsx +4 -0
- package/src/dev/local.tsx +103 -5
- package/src/dev/start-server.ts +34 -2
- package/src/dev/use-esbuild.ts +4 -0
- package/src/dev.tsx +25 -3
- package/src/init.ts +10 -6
- package/src/module-collection.ts +9 -0
- package/src/proxy.ts +59 -24
- package/src/publish.ts +1 -0
- package/templates/experimental-local-cache-stubs.js +27 -0
- package/templates/new-worker.js +1 -1
- package/wrangler-dist/cli.d.ts +1 -0
- package/wrangler-dist/cli.js +13477 -16174
- package/src/faye-websocket.d.ts +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wrangler",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.9",
|
|
4
4
|
"description": "Command-line interface for all things Cloudflare Workers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wrangler",
|
|
@@ -112,6 +112,7 @@
|
|
|
112
112
|
"@databases/sql": "^3.2.0",
|
|
113
113
|
"@iarna/toml": "^3.0.0",
|
|
114
114
|
"@microsoft/api-extractor": "^7.28.3",
|
|
115
|
+
"@miniflare/tre": "3.0.0-next.2",
|
|
115
116
|
"@types/better-sqlite3": "^7.6.0",
|
|
116
117
|
"@types/busboy": "^1.5.0",
|
|
117
118
|
"@types/command-exists": "^1.2.0",
|
|
@@ -138,7 +139,6 @@
|
|
|
138
139
|
"dotenv": "^16.0.0",
|
|
139
140
|
"execa": "^6.1.0",
|
|
140
141
|
"express": "^4.18.1",
|
|
141
|
-
"faye-websocket": "^0.11.4",
|
|
142
142
|
"finalhandler": "^1.2.0",
|
|
143
143
|
"find-up": "^6.3.0",
|
|
144
144
|
"get-port": "^6.1.2",
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
"jest-websocket-mock": "^2.3.0",
|
|
158
158
|
"mime": "^3.0.0",
|
|
159
159
|
"msw": "^0.47.1",
|
|
160
|
-
"npx-import": "^1.
|
|
160
|
+
"npx-import": "^1.1.3",
|
|
161
161
|
"open": "^8.4.0",
|
|
162
162
|
"p-queue": "^7.2.0",
|
|
163
163
|
"pretty-bytes": "^6.0.0",
|
|
@@ -1022,6 +1022,7 @@ describe("wrangler dev", () => {
|
|
|
1022
1022
|
--jsx-fragment The function that is called for each JSX fragment [string]
|
|
1023
1023
|
--tsconfig Path to a custom tsconfig.json file [string]
|
|
1024
1024
|
-l, --local Run on my machine [boolean] [default: false]
|
|
1025
|
+
--experimental-local Run on my machine using the Cloudflare Workers runtime [boolean] [default: false]
|
|
1025
1026
|
--minify Minify the script [boolean]
|
|
1026
1027
|
--node-compat Enable node.js compatibility [boolean]
|
|
1027
1028
|
--persist Enable persistence for local mode, using default path: .wrangler/state [boolean]
|
|
@@ -1325,18 +1326,18 @@ describe("wrangler dev", () => {
|
|
|
1325
1326
|
fs.writeFileSync("index.js", `export default {};`);
|
|
1326
1327
|
await runWrangler("dev index.js");
|
|
1327
1328
|
expect(std).toMatchInlineSnapshot(`
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1329
|
+
Object {
|
|
1330
|
+
"debug": "",
|
|
1331
|
+
"err": "",
|
|
1332
|
+
"out": "Using vars defined in .dev.vars
|
|
1333
|
+
Your worker has access to the following bindings:
|
|
1334
|
+
- Vars:
|
|
1335
|
+
- variable: 123
|
|
1336
|
+
- overriden: \\"(hidden)\\"
|
|
1337
|
+
- SECRET: \\"(hidden)\\"",
|
|
1338
|
+
"warn": "",
|
|
1339
|
+
}
|
|
1340
|
+
`);
|
|
1340
1341
|
});
|
|
1341
1342
|
});
|
|
1342
1343
|
});
|
|
@@ -2608,6 +2608,105 @@ describe("init", () => {
|
|
|
2608
2608
|
).rejects.toThrowError();
|
|
2609
2609
|
});
|
|
2610
2610
|
|
|
2611
|
+
it("should not inlcude migrations in config file when none are necessary", async () => {
|
|
2612
|
+
const mockDate = "1988-08-07";
|
|
2613
|
+
jest
|
|
2614
|
+
.spyOn(Date.prototype, "toISOString")
|
|
2615
|
+
.mockImplementation(() => `${mockDate}T00:00:00.000Z`);
|
|
2616
|
+
const mockData = {
|
|
2617
|
+
id: "memory-crystal",
|
|
2618
|
+
default_environment: {
|
|
2619
|
+
environment: "test",
|
|
2620
|
+
created_on: "1988-08-07",
|
|
2621
|
+
modified_on: "1988-08-07",
|
|
2622
|
+
script: {
|
|
2623
|
+
id: "memory-crystal",
|
|
2624
|
+
tag: "test-tag",
|
|
2625
|
+
etag: "some-etag",
|
|
2626
|
+
handlers: [],
|
|
2627
|
+
modified_on: "1988-08-07",
|
|
2628
|
+
created_on: "1988-08-07",
|
|
2629
|
+
usage_model: "bundled",
|
|
2630
|
+
compatibility_date: "1988-08-07",
|
|
2631
|
+
},
|
|
2632
|
+
},
|
|
2633
|
+
environments: [],
|
|
2634
|
+
};
|
|
2635
|
+
|
|
2636
|
+
setMockResponse(
|
|
2637
|
+
`/accounts/:accountId/workers/services/:scriptName`,
|
|
2638
|
+
"GET",
|
|
2639
|
+
() => mockData
|
|
2640
|
+
);
|
|
2641
|
+
setMockResponse(
|
|
2642
|
+
`/accounts/:accountId/workers/services/:scriptName/environments/:environment/bindings`,
|
|
2643
|
+
"GET",
|
|
2644
|
+
() => []
|
|
2645
|
+
);
|
|
2646
|
+
setMockResponse(
|
|
2647
|
+
`/accounts/:accountId/workers/services/:scriptName/environments/:environment/routes`,
|
|
2648
|
+
"GET",
|
|
2649
|
+
() => []
|
|
2650
|
+
);
|
|
2651
|
+
setMockResponse(
|
|
2652
|
+
`/accounts/:accountId/workers/services/:scriptName/environments/:environment`,
|
|
2653
|
+
"GET",
|
|
2654
|
+
() => mockServiceMetadata.default_environment
|
|
2655
|
+
);
|
|
2656
|
+
setMockResponse(
|
|
2657
|
+
`/accounts/:accountId/workers/scripts/:scriptName/schedules`,
|
|
2658
|
+
"GET",
|
|
2659
|
+
() => {
|
|
2660
|
+
return {
|
|
2661
|
+
schedules: [],
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2664
|
+
);
|
|
2665
|
+
|
|
2666
|
+
setMockFetchDashScript({
|
|
2667
|
+
accountId: "LCARS",
|
|
2668
|
+
fromDashScriptName: "isolinear-optical-chip",
|
|
2669
|
+
environment: mockServiceMetadata.default_environment.environment,
|
|
2670
|
+
mockResponse: mockDashboardScript,
|
|
2671
|
+
});
|
|
2672
|
+
|
|
2673
|
+
mockConfirm(
|
|
2674
|
+
{
|
|
2675
|
+
text: "Would you like to use git to manage this Worker?",
|
|
2676
|
+
result: false,
|
|
2677
|
+
},
|
|
2678
|
+
{
|
|
2679
|
+
text: "Would you like to use TypeScript?",
|
|
2680
|
+
result: true,
|
|
2681
|
+
},
|
|
2682
|
+
{
|
|
2683
|
+
text: "No package.json found. Would you like to create one?",
|
|
2684
|
+
result: true,
|
|
2685
|
+
},
|
|
2686
|
+
{
|
|
2687
|
+
text: "Would you like to install the type definitions for Workers into your package.json?",
|
|
2688
|
+
result: true,
|
|
2689
|
+
}
|
|
2690
|
+
);
|
|
2691
|
+
|
|
2692
|
+
await runWrangler("init --from-dash isolinear-optical-chip");
|
|
2693
|
+
|
|
2694
|
+
checkFiles({
|
|
2695
|
+
items: {
|
|
2696
|
+
"isolinear-optical-chip/wrangler.toml": wranglerToml({
|
|
2697
|
+
compatibility_date: "1988-08-07",
|
|
2698
|
+
env: {},
|
|
2699
|
+
main: "src/index.ts",
|
|
2700
|
+
triggers: {
|
|
2701
|
+
crons: [],
|
|
2702
|
+
},
|
|
2703
|
+
usage_model: "bundled",
|
|
2704
|
+
name: "isolinear-optical-chip",
|
|
2705
|
+
}),
|
|
2706
|
+
},
|
|
2707
|
+
});
|
|
2708
|
+
});
|
|
2709
|
+
|
|
2611
2710
|
it("should not continue if no worker name is provided", async () => {
|
|
2612
2711
|
await expect(
|
|
2613
2712
|
runWrangler("init --from-dash")
|
|
@@ -512,7 +512,7 @@ describe("publish", () => {
|
|
|
512
512
|
"Total Upload: xx KiB / gzip: xx KiB
|
|
513
513
|
Your worker has access to the following bindings:
|
|
514
514
|
- Vars:
|
|
515
|
-
- xyz:
|
|
515
|
+
- xyz: 123
|
|
516
516
|
Uploaded test-name (TIMINGS)
|
|
517
517
|
Published test-name (TIMINGS)
|
|
518
518
|
https://test-name.test-sub-domain.workers.dev"
|
|
@@ -4527,7 +4527,7 @@ addEventListener('fetch', event => {});`
|
|
|
4527
4527
|
- some unsafe thing: UNSAFE_BINDING_ONE
|
|
4528
4528
|
- another unsafe thing: UNSAFE_BINDING_TWO
|
|
4529
4529
|
- Vars:
|
|
4530
|
-
- ENV_VAR_ONE:
|
|
4530
|
+
- ENV_VAR_ONE: 123
|
|
4531
4531
|
- ENV_VAR_TWO: \\"Hello, I'm an environment variable\\"
|
|
4532
4532
|
- Wasm Modules:
|
|
4533
4533
|
- WASM_MODULE_ONE: some_wasm.wasm
|
|
@@ -5275,8 +5275,11 @@ addEventListener('fetch', event => {});`
|
|
|
5275
5275
|
Your worker has access to the following bindings:
|
|
5276
5276
|
- Vars:
|
|
5277
5277
|
- text: \\"plain ol' string\\"
|
|
5278
|
-
- count:
|
|
5279
|
-
- complex:
|
|
5278
|
+
- count: 1
|
|
5279
|
+
- complex: {
|
|
5280
|
+
\\"enabled\\": true,
|
|
5281
|
+
\\"id\\": 123
|
|
5282
|
+
}
|
|
5280
5283
|
Uploaded test-name (TIMINGS)
|
|
5281
5284
|
Published test-name (TIMINGS)
|
|
5282
5285
|
https://test-name.test-sub-domain.workers.dev"
|
package/src/api/dev.ts
CHANGED
package/src/bundle.ts
CHANGED
|
@@ -79,6 +79,7 @@ export async function bundleWorker(
|
|
|
79
79
|
targetConsumer: "dev" | "publish";
|
|
80
80
|
local: boolean;
|
|
81
81
|
testScheduled?: boolean | undefined;
|
|
82
|
+
experimentalLocalStubCache: boolean | undefined;
|
|
82
83
|
}
|
|
83
84
|
): Promise<BundleResult> {
|
|
84
85
|
const {
|
|
@@ -99,6 +100,7 @@ export async function bundleWorker(
|
|
|
99
100
|
firstPartyWorkerDevFacade,
|
|
100
101
|
targetConsumer,
|
|
101
102
|
testScheduled,
|
|
103
|
+
experimentalLocalStubCache,
|
|
102
104
|
} = options;
|
|
103
105
|
|
|
104
106
|
// We create a temporary directory for any oneoff files we
|
|
@@ -233,12 +235,20 @@ export async function bundleWorker(
|
|
|
233
235
|
|
|
234
236
|
// At this point, inputEntry points to the entry point we want to build.
|
|
235
237
|
|
|
238
|
+
const inject: string[] = [];
|
|
239
|
+
if (checkFetch) inject.push(checkedFetchFileToInject);
|
|
240
|
+
if (experimentalLocalStubCache) {
|
|
241
|
+
inject.push(
|
|
242
|
+
path.resolve(getBasePath(), "templates/experimental-local-cache-stubs.js")
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
236
246
|
const result = await esbuild.build({
|
|
237
247
|
entryPoints: [inputEntry.file],
|
|
238
248
|
bundle: true,
|
|
239
249
|
absWorkingDir: entry.directory,
|
|
240
250
|
outdir: destination,
|
|
241
|
-
inject
|
|
251
|
+
inject,
|
|
242
252
|
external: ["__STATIC_CONTENT_MANIFEST"],
|
|
243
253
|
format: entry.format === "modules" ? "esm" : "iife",
|
|
244
254
|
target: "es2020",
|
package/src/config/index.ts
CHANGED
|
@@ -219,10 +219,20 @@ export function printBindings(bindings: CfWorkerInit["bindings"]) {
|
|
|
219
219
|
if (vars !== undefined && Object.keys(vars).length > 0) {
|
|
220
220
|
output.push({
|
|
221
221
|
type: "Vars",
|
|
222
|
-
entries: Object.entries(vars).map(([key, value]) =>
|
|
223
|
-
|
|
224
|
-
value
|
|
225
|
-
|
|
222
|
+
entries: Object.entries(vars).map(([key, value]) => {
|
|
223
|
+
let parsedValue;
|
|
224
|
+
if (typeof value === "string") {
|
|
225
|
+
parsedValue = `"${truncate(value)}"`;
|
|
226
|
+
} else if (typeof value === "object") {
|
|
227
|
+
parsedValue = JSON.stringify(value, null, 1);
|
|
228
|
+
} else {
|
|
229
|
+
parsedValue = `${truncate(`${value}`)}`;
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
key,
|
|
233
|
+
value: parsedValue,
|
|
234
|
+
};
|
|
235
|
+
}),
|
|
226
236
|
});
|
|
227
237
|
}
|
|
228
238
|
|
package/src/dev/dev.tsx
CHANGED
|
@@ -153,6 +153,7 @@ export type DevProps = {
|
|
|
153
153
|
firstPartyWorker: boolean | undefined;
|
|
154
154
|
sendMetrics: boolean | undefined;
|
|
155
155
|
testScheduled: boolean | undefined;
|
|
156
|
+
experimentalLocal: boolean | undefined;
|
|
156
157
|
};
|
|
157
158
|
|
|
158
159
|
export function DevImplementation(props: DevProps): JSX.Element {
|
|
@@ -213,6 +214,7 @@ function InteractiveDevSession(props: DevProps) {
|
|
|
213
214
|
|
|
214
215
|
type DevSessionProps = DevProps & {
|
|
215
216
|
local: boolean;
|
|
217
|
+
experimentalLocal?: boolean;
|
|
216
218
|
};
|
|
217
219
|
|
|
218
220
|
function DevSession(props: DevSessionProps) {
|
|
@@ -274,6 +276,7 @@ function DevSession(props: DevSessionProps) {
|
|
|
274
276
|
// Enable the bundling to know whether we are using dev or publish
|
|
275
277
|
targetConsumer: "dev",
|
|
276
278
|
testScheduled: props.testScheduled ?? false,
|
|
279
|
+
experimentalLocalStubCache: props.local && props.experimentalLocal,
|
|
277
280
|
});
|
|
278
281
|
|
|
279
282
|
return props.local ? (
|
|
@@ -300,6 +303,7 @@ function DevSession(props: DevSessionProps) {
|
|
|
300
303
|
inspect={props.inspect}
|
|
301
304
|
onReady={props.onReady}
|
|
302
305
|
enablePagesAssetsServiceBinding={props.enablePagesAssetsServiceBinding}
|
|
306
|
+
experimentalLocal={props.experimentalLocal}
|
|
303
307
|
/>
|
|
304
308
|
) : (
|
|
305
309
|
<Remote
|
package/src/dev/local.tsx
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
1
2
|
import { fork } from "node:child_process";
|
|
2
3
|
import { realpathSync } from "node:fs";
|
|
3
|
-
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
4
5
|
import path from "node:path";
|
|
6
|
+
import { npxImport } from "npx-import";
|
|
5
7
|
import { useState, useEffect, useRef } from "react";
|
|
6
8
|
import onExit from "signal-exit";
|
|
7
9
|
import { registerWorker } from "../dev-registry";
|
|
8
10
|
import useInspector from "../inspect";
|
|
9
11
|
import { logger } from "../logger";
|
|
10
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_MODULE_RULES,
|
|
14
|
+
ModuleTypeToRuleType,
|
|
15
|
+
} from "../module-collection";
|
|
11
16
|
import { getBasePath } from "../paths";
|
|
12
17
|
import { waitForPortToBeAvailable } from "../proxy";
|
|
13
18
|
import type { Config } from "../config";
|
|
@@ -27,8 +32,13 @@ import type {
|
|
|
27
32
|
CfD1Database,
|
|
28
33
|
} from "../worker";
|
|
29
34
|
import type { EsbuildBundle } from "./use-esbuild";
|
|
35
|
+
import type {
|
|
36
|
+
Miniflare as Miniflare3Type,
|
|
37
|
+
MiniflareOptions as Miniflare3Options,
|
|
38
|
+
} from "@miniflare/tre";
|
|
30
39
|
import type { MiniflareOptions } from "miniflare";
|
|
31
40
|
import type { ChildProcess } from "node:child_process";
|
|
41
|
+
|
|
32
42
|
export interface LocalProps {
|
|
33
43
|
name: string | undefined;
|
|
34
44
|
bundle: EsbuildBundle | undefined;
|
|
@@ -53,6 +63,7 @@ export interface LocalProps {
|
|
|
53
63
|
logPrefix?: string;
|
|
54
64
|
enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions;
|
|
55
65
|
testScheduled?: boolean;
|
|
66
|
+
experimentalLocal?: boolean;
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
export function Local(props: LocalProps) {
|
|
@@ -88,9 +99,11 @@ function useLocalWorker({
|
|
|
88
99
|
onReady,
|
|
89
100
|
logPrefix,
|
|
90
101
|
enablePagesAssetsServiceBinding,
|
|
102
|
+
experimentalLocal,
|
|
91
103
|
}: LocalProps) {
|
|
92
104
|
// TODO: pass vars via command line
|
|
93
105
|
const local = useRef<ChildProcess>();
|
|
106
|
+
const experimentalLocalRef = useRef<Miniflare3Type>();
|
|
94
107
|
const removeSignalExitListener = useRef<() => void>();
|
|
95
108
|
const [inspectorUrl, setInspectorUrl] = useState<string | undefined>();
|
|
96
109
|
|
|
@@ -187,6 +200,20 @@ function useLocalWorker({
|
|
|
187
200
|
enablePagesAssetsServiceBinding,
|
|
188
201
|
});
|
|
189
202
|
|
|
203
|
+
if (experimentalLocal) {
|
|
204
|
+
// TODO: refactor setupMiniflareOptions so we don't need to parse here
|
|
205
|
+
const mf2Options: MiniflareOptions = JSON.parse(forkOptions[0]);
|
|
206
|
+
const mf = await setupExperimentalLocal(mf2Options, format, bundle);
|
|
207
|
+
await mf.ready;
|
|
208
|
+
experimentalLocalRef.current = mf;
|
|
209
|
+
removeSignalExitListener.current = onExit(() => {
|
|
210
|
+
logger.log("⎔ Shutting down experimental local server.");
|
|
211
|
+
mf.dispose();
|
|
212
|
+
experimentalLocalRef.current = undefined;
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
190
217
|
const nodeOptions = setupNodeOptions({ inspect, ip, inspectorPort });
|
|
191
218
|
logger.log("⎔ Starting a local server...");
|
|
192
219
|
|
|
@@ -279,9 +306,16 @@ function useLocalWorker({
|
|
|
279
306
|
logger.log("⎔ Shutting down local server.");
|
|
280
307
|
local.current?.kill();
|
|
281
308
|
local.current = undefined;
|
|
282
|
-
removeSignalExitListener.current && removeSignalExitListener.current();
|
|
283
|
-
removeSignalExitListener.current = undefined;
|
|
284
309
|
}
|
|
310
|
+
if (experimentalLocalRef.current) {
|
|
311
|
+
logger.log("⎔ Shutting down experimental local server.");
|
|
312
|
+
// Initialisation errors are also thrown asynchronously by dispose().
|
|
313
|
+
// The catch() above should've caught them though.
|
|
314
|
+
experimentalLocalRef.current?.dispose().catch(() => {});
|
|
315
|
+
experimentalLocalRef.current = undefined;
|
|
316
|
+
}
|
|
317
|
+
removeSignalExitListener.current?.();
|
|
318
|
+
removeSignalExitListener.current = undefined;
|
|
285
319
|
};
|
|
286
320
|
}, [
|
|
287
321
|
bundle,
|
|
@@ -314,6 +348,7 @@ function useLocalWorker({
|
|
|
314
348
|
logPrefix,
|
|
315
349
|
onReady,
|
|
316
350
|
enablePagesAssetsServiceBinding,
|
|
351
|
+
experimentalLocal,
|
|
317
352
|
]);
|
|
318
353
|
return { inspectorUrl };
|
|
319
354
|
}
|
|
@@ -458,7 +493,10 @@ export function setupMiniflareOptions({
|
|
|
458
493
|
logPrefix,
|
|
459
494
|
workerDefinitions,
|
|
460
495
|
enablePagesAssetsServiceBinding,
|
|
461
|
-
}: SetupMiniflareOptionsProps):
|
|
496
|
+
}: SetupMiniflareOptionsProps): {
|
|
497
|
+
miniflareCLIPath: string;
|
|
498
|
+
forkOptions: string[];
|
|
499
|
+
} {
|
|
462
500
|
// It's now getting _really_ messy now with Pages ASSETS binding outside and the external Durable Objects inside.
|
|
463
501
|
const options = {
|
|
464
502
|
name: workerName,
|
|
@@ -586,3 +624,63 @@ export function setupNodeOptions({
|
|
|
586
624
|
}
|
|
587
625
|
return nodeOptions;
|
|
588
626
|
}
|
|
627
|
+
|
|
628
|
+
// Caching of the `npx-import`ed `@miniflare/tre` package
|
|
629
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
630
|
+
let Miniflare: typeof import("@miniflare/tre").Miniflare;
|
|
631
|
+
|
|
632
|
+
function arrayToObject(values: string[] = []): Record<string, string> {
|
|
633
|
+
return Object.fromEntries(values.map((value) => [value, value]));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
export async function setupExperimentalLocal(
|
|
637
|
+
mf2Options: MiniflareOptions,
|
|
638
|
+
format: CfScriptFormat,
|
|
639
|
+
bundle: EsbuildBundle
|
|
640
|
+
): Promise<Miniflare3Type> {
|
|
641
|
+
const options: Miniflare3Options = {
|
|
642
|
+
...mf2Options,
|
|
643
|
+
// Miniflare 3 distinguishes between binding name and namespace/bucket IDs.
|
|
644
|
+
// For now, just use the same value as we did in Miniflare 2.
|
|
645
|
+
// TODO: use defined KV preview ID if any
|
|
646
|
+
kvNamespaces: arrayToObject(mf2Options.kvNamespaces),
|
|
647
|
+
r2Buckets: arrayToObject(mf2Options.r2Buckets),
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
if (format === "modules") {
|
|
651
|
+
// Manually specify all modules from the bundle. If we didn't do this,
|
|
652
|
+
// Miniflare 3 would try collect them automatically again itself.
|
|
653
|
+
|
|
654
|
+
// Resolve entrypoint relative to the temporary directory, ensuring
|
|
655
|
+
// path doesn't start with `..`, which causes issues in `workerd`.
|
|
656
|
+
// Also ensures other modules with relative names can be resolved.
|
|
657
|
+
const root = path.dirname(bundle.path);
|
|
658
|
+
|
|
659
|
+
assert.strictEqual(bundle.type, "esm");
|
|
660
|
+
options.modules = [
|
|
661
|
+
// Entrypoint
|
|
662
|
+
{
|
|
663
|
+
type: "ESModule",
|
|
664
|
+
path: path.relative(root, bundle.path),
|
|
665
|
+
contents: await readFile(bundle.path, "utf-8"),
|
|
666
|
+
},
|
|
667
|
+
// Misc (WebAssembly, etc, ...)
|
|
668
|
+
...bundle.modules.map((module) => ({
|
|
669
|
+
type: ModuleTypeToRuleType[module.type ?? "esm"],
|
|
670
|
+
path: module.name,
|
|
671
|
+
contents: module.content,
|
|
672
|
+
})),
|
|
673
|
+
];
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
logger.log("⎔ Starting an experimental local server...");
|
|
677
|
+
|
|
678
|
+
if (Miniflare === undefined) {
|
|
679
|
+
({ Miniflare } = await npxImport<
|
|
680
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
681
|
+
typeof import("@miniflare/tre")
|
|
682
|
+
>("@miniflare/tre@next"));
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return new Miniflare(options);
|
|
686
|
+
}
|
package/src/dev/start-server.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { logger } from "../logger";
|
|
|
17
17
|
import { waitForPortToBeAvailable } from "../proxy";
|
|
18
18
|
import {
|
|
19
19
|
setupBindings,
|
|
20
|
+
setupExperimentalLocal,
|
|
20
21
|
setupMiniflareOptions,
|
|
21
22
|
setupNodeOptions,
|
|
22
23
|
} from "./local";
|
|
@@ -28,6 +29,8 @@ import type { Entry } from "../entry";
|
|
|
28
29
|
import type { DevProps, DirectorySyncResult } from "./dev";
|
|
29
30
|
import type { LocalProps } from "./local";
|
|
30
31
|
import type { EsbuildBundle } from "./use-esbuild";
|
|
32
|
+
import type { Miniflare as Miniflare3Type } from "@miniflare/tre";
|
|
33
|
+
import type { MiniflareOptions } from "miniflare";
|
|
31
34
|
|
|
32
35
|
import type { ChildProcess } from "node:child_process";
|
|
33
36
|
|
|
@@ -91,6 +94,7 @@ export async function startDevServer(
|
|
|
91
94
|
services: props.bindings.services,
|
|
92
95
|
firstPartyWorkerDevFacade: props.firstPartyWorker,
|
|
93
96
|
testScheduled: props.testScheduled,
|
|
97
|
+
experimentalLocalStubCache: props.experimentalLocal,
|
|
94
98
|
});
|
|
95
99
|
|
|
96
100
|
//run local now
|
|
@@ -117,6 +121,7 @@ export async function startDevServer(
|
|
|
117
121
|
enablePagesAssetsServiceBinding: props.enablePagesAssetsServiceBinding,
|
|
118
122
|
usageModel: props.usageModel,
|
|
119
123
|
workerDefinitions,
|
|
124
|
+
experimentalLocal: props.experimentalLocal,
|
|
120
125
|
});
|
|
121
126
|
|
|
122
127
|
return {
|
|
@@ -159,6 +164,7 @@ async function runEsbuild({
|
|
|
159
164
|
services,
|
|
160
165
|
firstPartyWorkerDevFacade,
|
|
161
166
|
testScheduled,
|
|
167
|
+
experimentalLocalStubCache,
|
|
162
168
|
}: {
|
|
163
169
|
entry: Entry;
|
|
164
170
|
destination: string | undefined;
|
|
@@ -176,6 +182,7 @@ async function runEsbuild({
|
|
|
176
182
|
workerDefinitions: WorkerRegistry;
|
|
177
183
|
firstPartyWorkerDevFacade: boolean | undefined;
|
|
178
184
|
testScheduled?: boolean;
|
|
185
|
+
experimentalLocalStubCache: boolean | undefined;
|
|
179
186
|
}): Promise<EsbuildBundle | undefined> {
|
|
180
187
|
if (!destination) return;
|
|
181
188
|
|
|
@@ -213,6 +220,7 @@ async function runEsbuild({
|
|
|
213
220
|
targetConsumer: "dev", // We are starting a dev server
|
|
214
221
|
local: false,
|
|
215
222
|
testScheduled,
|
|
223
|
+
experimentalLocalStubCache,
|
|
216
224
|
});
|
|
217
225
|
|
|
218
226
|
return {
|
|
@@ -248,8 +256,10 @@ export async function startLocalServer({
|
|
|
248
256
|
onReady,
|
|
249
257
|
logPrefix,
|
|
250
258
|
enablePagesAssetsServiceBinding,
|
|
259
|
+
experimentalLocal,
|
|
251
260
|
}: LocalProps) {
|
|
252
261
|
let local: ChildProcess | undefined;
|
|
262
|
+
let experimentalLocalRef: Miniflare3Type | undefined;
|
|
253
263
|
let removeSignalExitListener: (() => void) | undefined;
|
|
254
264
|
let inspectorUrl: string | undefined;
|
|
255
265
|
const setInspectorUrl = (url: string) => {
|
|
@@ -337,6 +347,21 @@ export async function startLocalServer({
|
|
|
337
347
|
enablePagesAssetsServiceBinding,
|
|
338
348
|
});
|
|
339
349
|
|
|
350
|
+
if (experimentalLocal) {
|
|
351
|
+
// TODO: refactor setupMiniflareOptions so we don't need to parse here
|
|
352
|
+
const mf2Options: MiniflareOptions = JSON.parse(forkOptions[0]);
|
|
353
|
+
const mf = await setupExperimentalLocal(mf2Options, format, bundle);
|
|
354
|
+
const runtimeURL = await mf.ready;
|
|
355
|
+
experimentalLocalRef = mf;
|
|
356
|
+
removeSignalExitListener = onExit((_code, _signal) => {
|
|
357
|
+
logger.log("⎔ Shutting down experimental local server.");
|
|
358
|
+
mf.dispose();
|
|
359
|
+
experimentalLocalRef = undefined;
|
|
360
|
+
});
|
|
361
|
+
onReady?.(runtimeURL.hostname, parseInt(runtimeURL.port ?? 8787));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
340
365
|
const nodeOptions = setupNodeOptions({ inspect, ip, inspectorPort });
|
|
341
366
|
logger.log("⎔ Starting a local server...");
|
|
342
367
|
|
|
@@ -431,9 +456,16 @@ export async function startLocalServer({
|
|
|
431
456
|
logger.log("⎔ Shutting down local server.");
|
|
432
457
|
local.kill();
|
|
433
458
|
local = undefined;
|
|
434
|
-
removeSignalExitListener && removeSignalExitListener();
|
|
435
|
-
removeSignalExitListener = undefined;
|
|
436
459
|
}
|
|
460
|
+
if (experimentalLocalRef) {
|
|
461
|
+
logger.log("⎔ Shutting down experimental local server.");
|
|
462
|
+
// Initialisation errors are also thrown asynchronously by dispose().
|
|
463
|
+
// The catch() above should've caught them though.
|
|
464
|
+
experimentalLocalRef?.dispose().catch(() => {});
|
|
465
|
+
experimentalLocalRef = undefined;
|
|
466
|
+
}
|
|
467
|
+
removeSignalExitListener?.();
|
|
468
|
+
removeSignalExitListener = undefined;
|
|
437
469
|
},
|
|
438
470
|
};
|
|
439
471
|
}
|
package/src/dev/use-esbuild.ts
CHANGED
|
@@ -40,6 +40,7 @@ export function useEsbuild({
|
|
|
40
40
|
local,
|
|
41
41
|
targetConsumer,
|
|
42
42
|
testScheduled,
|
|
43
|
+
experimentalLocalStubCache,
|
|
43
44
|
}: {
|
|
44
45
|
entry: Entry;
|
|
45
46
|
destination: string | undefined;
|
|
@@ -61,6 +62,7 @@ export function useEsbuild({
|
|
|
61
62
|
local: boolean;
|
|
62
63
|
targetConsumer: "dev" | "publish";
|
|
63
64
|
testScheduled: boolean;
|
|
65
|
+
experimentalLocalStubCache: boolean | undefined;
|
|
64
66
|
}): EsbuildBundle | undefined {
|
|
65
67
|
const [bundle, setBundle] = useState<EsbuildBundle>();
|
|
66
68
|
const { exit } = useApp();
|
|
@@ -128,6 +130,7 @@ export function useEsbuild({
|
|
|
128
130
|
local,
|
|
129
131
|
targetConsumer,
|
|
130
132
|
testScheduled,
|
|
133
|
+
experimentalLocalStubCache,
|
|
131
134
|
});
|
|
132
135
|
|
|
133
136
|
// Capture the `stop()` method to use as the `useEffect()` destructor.
|
|
@@ -188,6 +191,7 @@ export function useEsbuild({
|
|
|
188
191
|
local,
|
|
189
192
|
targetConsumer,
|
|
190
193
|
testScheduled,
|
|
194
|
+
experimentalLocalStubCache,
|
|
191
195
|
]);
|
|
192
196
|
return bundle;
|
|
193
197
|
}
|