Skip to content

Commit cf14e17

Browse files
feat(miniflare): Add assets Proxy Worker skeleton in miniflare (#8288)
* feat(miniflare): Add assets Proxy Worker skeleton in miniflare This commit implements a very basic Proxy Worker skeleton, and wires it in the "pipeline" miniflare creates for assets. This Worker will be incrementally worked on, but for now, the current implementation will forward all incoming requests to the Router Worker, thus leaving the current assets behaviour in local dev, the same. Fixes DEVX-1641, DEVX-1642 * e2e tests
1 parent 2d40989 commit cf14e17

File tree

13 files changed

+655
-523
lines changed

13 files changed

+655
-523
lines changed

.changeset/dry-ends-post.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@cloudflare/vitest-pool-workers": patch
3+
"miniflare": patch
4+
"wrangler": patch
5+
---
6+
7+
feat: Add assets Proxy Worker skeleton in miniflare
8+
9+
This commit implements a very basic Proxy Worker skeleton, and wires it in the "pipeline" miniflare creates for assets. This Worker will be incrementally worked on, but for now, the current implementation will forward all incoming requests to the Router Worker, thus leaving the current assets behaviour in local dev, the same.
10+
11+
This is an experimental feature available under the `--x-assets-rpc` flag: `wrangler dev --x-assets-rpc`.

fixtures/workers-with-assets-only/tests/index.test.ts

Lines changed: 163 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -3,176 +3,184 @@ import { fetch } from "undici";
33
import { afterAll, beforeAll, describe, it } from "vitest";
44
import { runWranglerDev } from "../../shared/src/run-wrangler-long-lived";
55

6-
describe("[Workers + Assets] static-assets only site`", () => {
7-
let ip: string, port: number, stop: (() => Promise<unknown>) | undefined;
8-
9-
beforeAll(async () => {
10-
({ ip, port, stop } = await runWranglerDev(resolve(__dirname, ".."), [
11-
"--port=0",
12-
"--inspector-port=0",
13-
]));
14-
});
15-
16-
afterAll(async () => {
17-
await stop?.();
18-
});
19-
20-
it("should respond with static asset content", async ({ expect }) => {
21-
let response = await fetch(`http://${ip}:${port}/index.html`);
22-
let text = await response.text();
23-
expect(response.status).toBe(200);
24-
expect(text).toContain(`<h1>Hello Workers + Assets World 🚀!</h1>`);
25-
26-
response = await fetch(`http://${ip}:${port}/about/index.html`);
27-
text = await response.text();
28-
expect(response.status).toBe(200);
29-
expect(text).toContain(`<p>Learn more about Workers with Assets soon!</p>`);
30-
});
31-
32-
it("should resolve '/' to '/index.html' ", async ({ expect }) => {
33-
let response = await fetch(`http://${ip}:${port}/`);
34-
expect(response.status).toBe(200);
35-
expect(await response.text()).toContain(
36-
`<h1>Hello Workers + Assets World 🚀!</h1>`
37-
);
38-
});
39-
40-
it("should 404 if asset is not found in the asset manifest", async ({
41-
expect,
42-
}) => {
43-
let response = await fetch(`http://${ip}:${port}/hello.html`);
44-
expect(response.status).toBe(404);
45-
46-
response = await fetch(`http://${ip}:${port}/hello.txt`);
47-
expect(response.status).toBe(404);
48-
});
49-
50-
it("should handle content types correctly", async ({ expect }) => {
51-
let response = await fetch(`http://${ip}:${port}/index.html`);
52-
let text = await response.text();
53-
expect(response.status).toBe(200);
54-
expect(response.headers.get("Content-Type")).toBe(
55-
"text/html; charset=utf-8"
56-
);
57-
58-
response = await fetch(`http://${ip}:${port}/README.md`);
59-
text = await response.text();
60-
expect(response.status).toBe(200);
61-
expect(response.headers.get("Content-Type")).toBe(
62-
"text/markdown; charset=utf-8"
63-
);
64-
expect(text).toContain(`Welcome to Workers + Assets YAY!`);
65-
66-
response = await fetch(`http://${ip}:${port}/yay.txt`);
67-
text = await response.text();
68-
expect(response.status).toBe(200);
69-
expect(response.headers.get("Content-Type")).toBe(
70-
"text/plain; charset=utf-8"
71-
);
72-
expect(text).toContain(`.----------------.`);
73-
74-
response = await fetch(`http://${ip}:${port}/lava-lamps.jpg`);
75-
expect(response.status).toBe(200);
76-
expect(response.headers.get("Content-Type")).toBe("image/jpeg");
77-
});
78-
79-
it("should return 405 for non-GET or HEAD requests if asset route exists", async ({
80-
expect,
81-
}) => {
82-
// as per https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
83-
// excl. TRACE and CONNECT which are not supported
84-
85-
let response = await fetch(`http://${ip}:${port}/index.html`, {
86-
method: "POST",
6+
const devCmds = [{ args: [] }, { args: ["--x-assets-rpc"] }];
7+
8+
describe.each(devCmds)(
9+
"[wrangler dev $args][Workers + Assets] static-assets only site`",
10+
({ args }) => {
11+
let ip: string, port: number, stop: (() => Promise<unknown>) | undefined;
12+
13+
beforeAll(async () => {
14+
({ ip, port, stop } = await runWranglerDev(resolve(__dirname, ".."), [
15+
"--port=0",
16+
"--inspector-port=0",
17+
...args,
18+
]));
8719
});
88-
expect(response.status).toBe(405);
89-
expect(response.statusText).toBe("Method Not Allowed");
9020

91-
response = await fetch(`http://${ip}:${port}/index.html`, {
92-
method: "PUT",
21+
afterAll(async () => {
22+
await stop?.();
9323
});
94-
expect(response.status).toBe(405);
95-
expect(response.statusText).toBe("Method Not Allowed");
9624

97-
response = await fetch(`http://${ip}:${port}/index.html`, {
98-
method: "DELETE",
25+
it("should respond with static asset content", async ({ expect }) => {
26+
let response = await fetch(`http://${ip}:${port}/index.html`);
27+
let text = await response.text();
28+
expect(response.status).toBe(200);
29+
expect(text).toContain(`<h1>Hello Workers + Assets World 🚀!</h1>`);
30+
31+
response = await fetch(`http://${ip}:${port}/about/index.html`);
32+
text = await response.text();
33+
expect(response.status).toBe(200);
34+
expect(text).toContain(
35+
`<p>Learn more about Workers with Assets soon!</p>`
36+
);
9937
});
100-
expect(response.status).toBe(405);
101-
expect(response.statusText).toBe("Method Not Allowed");
10238

103-
response = await fetch(`http://${ip}:${port}/index.html`, {
104-
method: "OPTIONS",
39+
it("should resolve '/' to '/index.html' ", async ({ expect }) => {
40+
let response = await fetch(`http://${ip}:${port}/`);
41+
expect(response.status).toBe(200);
42+
expect(await response.text()).toContain(
43+
`<h1>Hello Workers + Assets World 🚀!</h1>`
44+
);
10545
});
106-
expect(response.status).toBe(405);
107-
expect(response.statusText).toBe("Method Not Allowed");
10846

109-
response = await fetch(`http://${ip}:${port}/index.html`, {
110-
method: "PATCH",
111-
});
112-
expect(response.status).toBe(405);
113-
expect(response.statusText).toBe("Method Not Allowed");
114-
});
115-
116-
it("should return 404 for non-GET requests if asset route does not exist", async ({
117-
expect,
118-
}) => {
119-
// as per https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
120-
// excl. TRACE and CONNECT which are not supported
121-
122-
let response = await fetch(`http://${ip}:${port}/nope.html`, {
123-
method: "HEAD",
124-
});
125-
expect(response.status).toBe(404);
47+
it("should 404 if asset is not found in the asset manifest", async ({
48+
expect,
49+
}) => {
50+
let response = await fetch(`http://${ip}:${port}/hello.html`);
51+
expect(response.status).toBe(404);
12652

127-
response = await fetch(`http://${ip}:${port}/nope.html`, {
128-
method: "POST",
53+
response = await fetch(`http://${ip}:${port}/hello.txt`);
54+
expect(response.status).toBe(404);
12955
});
130-
expect(response.status).toBe(404);
13156

132-
response = await fetch(`http://${ip}:${port}/nope.html`, {
133-
method: "PUT",
57+
it("should handle content types correctly", async ({ expect }) => {
58+
let response = await fetch(`http://${ip}:${port}/index.html`);
59+
let text = await response.text();
60+
expect(response.status).toBe(200);
61+
expect(response.headers.get("Content-Type")).toBe(
62+
"text/html; charset=utf-8"
63+
);
64+
65+
response = await fetch(`http://${ip}:${port}/README.md`);
66+
text = await response.text();
67+
expect(response.status).toBe(200);
68+
expect(response.headers.get("Content-Type")).toBe(
69+
"text/markdown; charset=utf-8"
70+
);
71+
expect(text).toContain(`Welcome to Workers + Assets YAY!`);
72+
73+
response = await fetch(`http://${ip}:${port}/yay.txt`);
74+
text = await response.text();
75+
expect(response.status).toBe(200);
76+
expect(response.headers.get("Content-Type")).toBe(
77+
"text/plain; charset=utf-8"
78+
);
79+
expect(text).toContain(`.----------------.`);
80+
81+
response = await fetch(`http://${ip}:${port}/lava-lamps.jpg`);
82+
expect(response.status).toBe(200);
83+
expect(response.headers.get("Content-Type")).toBe("image/jpeg");
13484
});
135-
expect(response.status).toBe(404);
13685

137-
response = await fetch(`http://${ip}:${port}/nope.html`, {
138-
method: "DELETE",
86+
it("should return 405 for non-GET or HEAD requests if asset route exists", async ({
87+
expect,
88+
}) => {
89+
// as per https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
90+
// excl. TRACE and CONNECT which are not supported
91+
92+
let response = await fetch(`http://${ip}:${port}/index.html`, {
93+
method: "POST",
94+
});
95+
expect(response.status).toBe(405);
96+
expect(response.statusText).toBe("Method Not Allowed");
97+
98+
response = await fetch(`http://${ip}:${port}/index.html`, {
99+
method: "PUT",
100+
});
101+
expect(response.status).toBe(405);
102+
expect(response.statusText).toBe("Method Not Allowed");
103+
104+
response = await fetch(`http://${ip}:${port}/index.html`, {
105+
method: "DELETE",
106+
});
107+
expect(response.status).toBe(405);
108+
expect(response.statusText).toBe("Method Not Allowed");
109+
110+
response = await fetch(`http://${ip}:${port}/index.html`, {
111+
method: "OPTIONS",
112+
});
113+
expect(response.status).toBe(405);
114+
expect(response.statusText).toBe("Method Not Allowed");
115+
116+
response = await fetch(`http://${ip}:${port}/index.html`, {
117+
method: "PATCH",
118+
});
119+
expect(response.status).toBe(405);
120+
expect(response.statusText).toBe("Method Not Allowed");
139121
});
140-
expect(response.status).toBe(404);
141122

142-
response = await fetch(`http://${ip}:${port}/nope.html`, {
143-
method: "OPTIONS",
123+
it("should return 404 for non-GET requests if asset route does not exist", async ({
124+
expect,
125+
}) => {
126+
// as per https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
127+
// excl. TRACE and CONNECT which are not supported
128+
129+
let response = await fetch(`http://${ip}:${port}/nope.html`, {
130+
method: "HEAD",
131+
});
132+
expect(response.status).toBe(404);
133+
134+
response = await fetch(`http://${ip}:${port}/nope.html`, {
135+
method: "POST",
136+
});
137+
expect(response.status).toBe(404);
138+
139+
response = await fetch(`http://${ip}:${port}/nope.html`, {
140+
method: "PUT",
141+
});
142+
expect(response.status).toBe(404);
143+
144+
response = await fetch(`http://${ip}:${port}/nope.html`, {
145+
method: "DELETE",
146+
});
147+
expect(response.status).toBe(404);
148+
149+
response = await fetch(`http://${ip}:${port}/nope.html`, {
150+
method: "OPTIONS",
151+
});
152+
expect(response.status).toBe(404);
153+
154+
response = await fetch(`http://${ip}:${port}/nope.html`, {
155+
method: "PATCH",
156+
});
157+
expect(response.status).toBe(404);
144158
});
145-
expect(response.status).toBe(404);
146159

147-
response = await fetch(`http://${ip}:${port}/nope.html`, {
148-
method: "PATCH",
160+
it("should work with encoded path names", async ({ expect }) => {
161+
let response = await fetch(`http://${ip}:${port}/about/[fünky].txt`);
162+
let text = await response.text();
163+
expect(response.status).toBe(200);
164+
expect(response.url).toBe(
165+
`http://${ip}:${port}/about/%5Bf%C3%BCnky%5D.txt`
166+
);
167+
expect(text).toContain(`This should work.`);
168+
169+
response = await fetch(`http://${ip}:${port}/about/[boop]`);
170+
text = await response.text();
171+
expect(response.status).toBe(200);
172+
expect(response.url).toBe(`http://${ip}:${port}/about/%5Bboop%5D`);
173+
expect(text).toContain(`[boop].html`);
174+
175+
response = await fetch(`http://${ip}:${port}/about/%5Bboop%5D`);
176+
text = await response.text();
177+
expect(response.status).toBe(200);
178+
expect(text).toContain(`[boop].html`);
179+
180+
response = await fetch(`http://${ip}:${port}/about/%255Bboop%255D`);
181+
text = await response.text();
182+
expect(response.status).toBe(200);
183+
expect(text).toContain(`%255Bboop%255D.html`);
149184
});
150-
expect(response.status).toBe(404);
151-
});
152-
153-
it("should work with encoded path names", async ({ expect }) => {
154-
let response = await fetch(`http://${ip}:${port}/about/[fünky].txt`);
155-
let text = await response.text();
156-
expect(response.status).toBe(200);
157-
expect(response.url).toBe(
158-
`http://${ip}:${port}/about/%5Bf%C3%BCnky%5D.txt`
159-
);
160-
expect(text).toContain(`This should work.`);
161-
162-
response = await fetch(`http://${ip}:${port}/about/[boop]`);
163-
text = await response.text();
164-
expect(response.status).toBe(200);
165-
expect(response.url).toBe(`http://${ip}:${port}/about/%5Bboop%5D`);
166-
expect(text).toContain(`[boop].html`);
167-
168-
response = await fetch(`http://${ip}:${port}/about/%5Bboop%5D`);
169-
text = await response.text();
170-
expect(response.status).toBe(200);
171-
expect(text).toContain(`[boop].html`);
172-
173-
response = await fetch(`http://${ip}:${port}/about/%255Bboop%255D`);
174-
text = await response.text();
175-
expect(response.status).toBe(200);
176-
expect(text).toContain(`%255Bboop%255D.html`);
177-
});
178-
});
185+
}
186+
);

0 commit comments

Comments
 (0)