Skip to content

Commit d304055

Browse files
authored
refactor: migrate wrangler dev to use Miniflare dev registry (#10245)
1 parent 18701d1 commit d304055

File tree

28 files changed

+510
-919
lines changed

28 files changed

+510
-919
lines changed

.changeset/deep-rules-burn.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"wrangler": patch
3+
---
4+
5+
Migrate wrangler dev to use Miniflare dev registry implementation
6+
7+
Updated `wrangler dev` to use a shared dev registry implementation that now powers both the Cloudflare Vite plugin and Wrangler. This internal refactoring has no user-facing changes but consolidates registry logic for better consistency across tools.

fixtures/dev-registry/tests/dev-registry.test.ts

Lines changed: 266 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,262 @@ async function setupPlatformProxy(config: string, devRegistryPath?: string) {
9999
return proxy;
100100
}
101101

102+
describe("Dev Registry: wrangler dev <-> wrangler dev", () => {
103+
it("supports fetch over service binding", async ({ devRegistryPath }) => {
104+
const workerEntrypointWithAssets = await runWranglerDev(
105+
"wrangler.worker-entrypoint-with-assets.jsonc",
106+
devRegistryPath
107+
);
108+
109+
// Test fallback service before module-worker is started
110+
await vi.waitFor(async () => {
111+
const searchParams = new URLSearchParams({
112+
"test-service": "module-worker",
113+
"test-method": "fetch",
114+
});
115+
const response = await fetch(
116+
`${workerEntrypointWithAssets}?${searchParams}`
117+
);
118+
119+
expect({
120+
status: response.status,
121+
body: await response.text(),
122+
}).toEqual({
123+
status: 503,
124+
body: `Couldn't find a local dev session for the "default" entrypoint of service "module-worker" to proxy to`,
125+
});
126+
});
127+
128+
const moduleWorker = await runWranglerDev(
129+
"wrangler.module-worker.jsonc",
130+
devRegistryPath
131+
);
132+
133+
// Test module-worker -> worker-entrypoint
134+
await vi.waitFor(async () => {
135+
const searchParams = new URLSearchParams({
136+
"test-service": "worker-entrypoint-with-assets",
137+
"test-method": "fetch",
138+
});
139+
const response = await fetch(`${moduleWorker}?${searchParams}`);
140+
141+
expect(await response.text()).toBe("Hello from Worker Entrypoint!");
142+
expect(response.status).toBe(200);
143+
144+
// Test fetching asset from "worker-entrypoint-with-assets" over service binding
145+
// Module worker has no assets, so it will hit the user worker and
146+
// forward the request to "worker-entrypoint-with-assets" with the asset path
147+
const assetResponse = await fetch(
148+
`${moduleWorker}/example.txt?${searchParams}`
149+
);
150+
expect(await assetResponse.text()).toBe("This is an example asset file");
151+
});
152+
153+
// Test worker-entrypoint -> module-worker
154+
await vi.waitFor(async () => {
155+
const searchParams = new URLSearchParams({
156+
"test-service": "module-worker",
157+
"test-method": "fetch",
158+
});
159+
const response = await fetch(
160+
`${workerEntrypointWithAssets}?${searchParams}`
161+
);
162+
163+
expect(await response.text()).toEqual("Hello from Module Worker!");
164+
expect(response.status).toBe(200);
165+
});
166+
});
167+
168+
it("supports RPC over service binding", async ({ devRegistryPath }) => {
169+
const workerEntrypoint = await runWranglerDev(
170+
"wrangler.worker-entrypoint.jsonc",
171+
devRegistryPath
172+
);
173+
174+
await vi.waitFor(async () => {
175+
const searchParams = new URLSearchParams({
176+
"test-service": "worker-entrypoint-with-assets",
177+
"test-method": "rpc",
178+
});
179+
const response = await fetch(`${workerEntrypoint}?${searchParams}`);
180+
181+
expect(response.status).toBe(500);
182+
expect(await response.text()).toEqual(
183+
`Cannot access "ping" as we couldn't find a local dev session for the "default" entrypoint of service "worker-entrypoint-with-assets" to proxy to.`
184+
);
185+
});
186+
187+
const workerEntrypointWithAssets = await runWranglerDev(
188+
"wrangler.worker-entrypoint-with-assets.jsonc",
189+
devRegistryPath
190+
);
191+
192+
await vi.waitFor(async () => {
193+
const searchParams = new URLSearchParams({
194+
"test-service": "worker-entrypoint",
195+
"test-method": "rpc",
196+
});
197+
const response = await fetch(
198+
`${workerEntrypointWithAssets}?${searchParams}`
199+
);
200+
201+
expect(response.status).toBe(200);
202+
expect(await response.text()).toEqual("Pong");
203+
});
204+
205+
await vi.waitFor(async () => {
206+
const searchParams = new URLSearchParams({
207+
"test-service": "worker-entrypoint-with-assets",
208+
"test-method": "rpc",
209+
});
210+
const response = await fetch(`${workerEntrypoint}?${searchParams}`);
211+
212+
expect(response.status).toBe(200);
213+
expect(await response.text()).toEqual("Pong");
214+
});
215+
});
216+
217+
it("supports fetch over durable object binding", async ({
218+
devRegistryPath,
219+
}) => {
220+
const externalDurableObject = await runWranglerDev(
221+
"wrangler.external-durable-object.jsonc",
222+
devRegistryPath
223+
);
224+
225+
// Test fallback before internal durable object is started
226+
await vi.waitFor(async () => {
227+
const searchParams = new URLSearchParams({
228+
"test-service": "durable-object",
229+
"test-method": "fetch",
230+
});
231+
const response = await fetch(`${externalDurableObject}?${searchParams}`);
232+
233+
expect(response.status).toBe(503);
234+
expect(await response.text()).toEqual("Service Unavailable");
235+
});
236+
237+
await runWranglerDev(
238+
"wrangler.internal-durable-object.jsonc",
239+
devRegistryPath
240+
);
241+
242+
await vi.waitFor(async () => {
243+
const searchParams = new URLSearchParams({
244+
"test-service": "durable-object",
245+
"test-method": "fetch",
246+
});
247+
const response = await fetch(`${externalDurableObject}?${searchParams}`);
248+
249+
expect(response.status).toBe(200);
250+
expect(await response.text()).toEqual("Hello from Durable Object!");
251+
});
252+
});
253+
254+
it("supports RPC over durable object binding", async ({
255+
devRegistryPath,
256+
}) => {
257+
const externalDurableObject = await runWranglerDev(
258+
"wrangler.external-durable-object.jsonc",
259+
devRegistryPath
260+
);
261+
262+
// Test RPC fallback before internal durable object is started
263+
await vi.waitFor(async () => {
264+
const searchParams = new URLSearchParams({
265+
"test-service": "durable-object",
266+
"test-method": "rpc",
267+
});
268+
const response = await fetch(`${externalDurableObject}?${searchParams}`);
269+
270+
expect({
271+
status: response.status,
272+
body: await response.text(),
273+
}).toEqual({
274+
status: 500,
275+
body: 'Cannot access "TestObject#ping" as Durable Object RPC is not yet supported between multiple dev sessions.',
276+
});
277+
});
278+
279+
await runWranglerDev(
280+
"wrangler.internal-durable-object.jsonc",
281+
devRegistryPath
282+
);
283+
284+
// Test RPC after internal durable object is started (should still fail)
285+
await vi.waitFor(async () => {
286+
const searchParams = new URLSearchParams({
287+
"test-service": "durable-object",
288+
"test-method": "rpc",
289+
});
290+
const response = await fetch(`${externalDurableObject}?${searchParams}`);
291+
292+
expect(response.status).toBe(500);
293+
expect(await response.text()).toEqual(
294+
'Cannot access "TestObject#ping" as Durable Object RPC is not yet supported between multiple dev sessions.'
295+
);
296+
});
297+
});
298+
299+
it("supports tail handler", async ({ devRegistryPath }) => {
300+
const moduleWorkerWithAssets = await runWranglerDev(
301+
"wrangler.module-worker-with-assets.jsonc",
302+
devRegistryPath
303+
);
304+
const workerEntrypoint = await runWranglerDev(
305+
"wrangler.worker-entrypoint.jsonc",
306+
devRegistryPath
307+
);
308+
309+
const searchParams = new URLSearchParams({
310+
"test-method": "tail",
311+
});
312+
313+
await vi.waitFor(async () => {
314+
// Trigger tail handler of worker-entrypoint via module-worker
315+
await fetch(`${moduleWorkerWithAssets}?${searchParams}`, {
316+
method: "POST",
317+
body: JSON.stringify(["hello world", "this is the 2nd log"]),
318+
});
319+
await fetch(`${moduleWorkerWithAssets}?${searchParams}`, {
320+
method: "POST",
321+
body: JSON.stringify(["some other log"]),
322+
});
323+
324+
const response = await fetch(`${workerEntrypoint}?${searchParams}`);
325+
326+
expect(await response.json()).toEqual({
327+
worker: "Worker Entrypoint",
328+
tailEvents: expect.arrayContaining([
329+
[["[Module Worker]"], ["hello world", "this is the 2nd log"]],
330+
[["[Module Worker]"], ["some other log"]],
331+
]),
332+
});
333+
});
334+
335+
await vi.waitFor(async () => {
336+
// Trigger tail handler of module-worker via worker-entrypoint
337+
await fetch(`${workerEntrypoint}?${searchParams}`, {
338+
method: "POST",
339+
body: JSON.stringify(["hello from test"]),
340+
});
341+
await fetch(`${workerEntrypoint}?${searchParams}`, {
342+
method: "POST",
343+
body: JSON.stringify(["yet another log", "and another one"]),
344+
});
345+
const response = await fetch(`${moduleWorkerWithAssets}?${searchParams}`);
346+
347+
expect(await response.json()).toEqual({
348+
worker: "Module Worker",
349+
tailEvents: expect.arrayContaining([
350+
[["[Worker Entrypoint]"], ["hello from test"]],
351+
[["[Worker Entrypoint]"], ["yet another log", "and another one"]],
352+
]),
353+
});
354+
});
355+
});
356+
});
357+
102358
describe("Dev Registry: vite dev <-> vite dev", () => {
103359
it("supports module worker fetch over service binding", async ({
104360
devRegistryPath,
@@ -244,10 +500,10 @@ describe("Dev Registry: vite dev <-> vite dev", () => {
244500

245501
expect(await response.json()).toEqual({
246502
worker: "Worker Entrypoint",
247-
tailEvents: [
503+
tailEvents: expect.arrayContaining([
248504
[["[Module Worker]"], ["hello world", "this is the 2nd log"]],
249505
[["[Module Worker]"], ["some other log"]],
250-
],
506+
]),
251507
});
252508
});
253509

@@ -266,10 +522,10 @@ describe("Dev Registry: vite dev <-> vite dev", () => {
266522

267523
expect(await response.json()).toEqual({
268524
worker: "Module Worker",
269-
tailEvents: [
525+
tailEvents: expect.arrayContaining([
270526
[["[Worker Entrypoint]"], ["hello from test"]],
271527
[["[Worker Entrypoint]"], ["yet another log", "and another one"]],
272-
],
528+
]),
273529
});
274530
});
275531
});
@@ -466,10 +722,10 @@ describe("Dev Registry: vite dev <-> wrangler dev", () => {
466722

467723
expect(await response.json()).toEqual({
468724
worker: "Worker Entrypoint",
469-
tailEvents: [
725+
tailEvents: expect.arrayContaining([
470726
[["[Module Worker]"], ["hello world", "this is the 2nd log"]],
471727
[["[Module Worker]"], ["some other log"]],
472-
],
728+
]),
473729
});
474730
});
475731

@@ -490,10 +746,10 @@ describe("Dev Registry: vite dev <-> wrangler dev", () => {
490746

491747
expect(await response.json()).toEqual({
492748
worker: "Module Worker",
493-
tailEvents: [
749+
tailEvents: expect.arrayContaining([
494750
[["[Worker Entrypoint]"], ["hello from test"]],
495751
[["[Worker Entrypoint]"], ["yet another log", "and another one"]],
496-
],
752+
]),
497753
});
498754
});
499755
});
@@ -642,15 +898,15 @@ describe("Dev Registry: getPlatformProxy -> wrangler / vite dev", () => {
642898
const stub = env.DURABLE_OBJECT.get(id);
643899

644900
expect(() => stub.ping()).toThrowErrorMatchingInlineSnapshot(
645-
`[Error: Cannot access "ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
901+
`[Error: Cannot access "TestObject#ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
646902
);
647903
await runWranglerDev(
648904
"wrangler.internal-durable-object.jsonc",
649905
devRegistryPath
650906
);
651907

652908
expect(() => stub.ping()).toThrowErrorMatchingInlineSnapshot(
653-
`[Error: Cannot access "ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
909+
`[Error: Cannot access "TestObject#ping" as Durable Object RPC is not yet supported between multiple dev sessions.]`
654910
);
655911
});
656912
});

fixtures/entrypoints-rpc-tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
},
88
"devDependencies": {
99
"@cloudflare/workers-tsconfig": "workspace:*",
10+
"miniflare": "workspace:*",
1011
"ts-dedent": "^2.2.0",
1112
"undici": "catalog:default",
1213
"vitest": "catalog:default",

0 commit comments

Comments
 (0)