Skip to content

Commit a18155f

Browse files
authored
Fix dev server crashing on config changes (#8652)
* Added config-changes playground * Moved miniflare.dispose into createServer and added tests * Revered vitest config * Simplified tests * Added changeset * Fix workers-types version * Increase waitFor timeout * Skip config errors test * Use path.resolve * Log in tests * Normalize Worker config paths to support Windows * Use path.resolve in handleHotUpdate hook * Add tailwindcss to playground to reproduce error * Use hotUpdate and miniflare.setOptions * Filter logs * Remove inspectorPort in playground * Set unique Workflows IDs * Remove unnecessary async * Assert Miniflare
1 parent 14602d9 commit a18155f

File tree

21 files changed

+634
-150
lines changed

21 files changed

+634
-150
lines changed

.changeset/shy-singers-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cloudflare/vite-plugin": patch
3+
---
4+
5+
Fix a bug where updating config files would crash the dev server. This occurred because the previous Miniflare instance was not disposed before creating a new one. This would lead to a port collision because of the `inspectorPort` introduced by the new debugging features.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import * as fs from "node:fs";
2+
import * as path from "node:path";
3+
import { expect, test, vi } from "vitest";
4+
import { getTextResponse, isBuild, serverLogs } from "../../__test-utils__";
5+
6+
test.runIf(!isBuild)(
7+
"successfully updates when a var is updated in the Worker config",
8+
async ({ onTestFinished }) => {
9+
const workerConfigPath = path.join(__dirname, "../wrangler.json");
10+
const originalWorkerConfig = fs.readFileSync(workerConfigPath, "utf-8");
11+
12+
onTestFinished(async () => {
13+
fs.writeFileSync(workerConfigPath, originalWorkerConfig);
14+
// We need to ensure that the original config is restored before the next test runs
15+
await vi.waitFor(
16+
async () => {
17+
const revertedResponse = await getTextResponse();
18+
expect(revertedResponse).toBe('The value of MY_VAR is "one"');
19+
},
20+
{ timeout: 5000 }
21+
);
22+
});
23+
24+
const originalResponse = await getTextResponse();
25+
expect(originalResponse).toBe('The value of MY_VAR is "one"');
26+
27+
const updatedWorkerConfig = JSON.stringify({
28+
...JSON.parse(originalWorkerConfig),
29+
vars: {
30+
MY_VAR: "two",
31+
},
32+
});
33+
fs.writeFileSync(workerConfigPath, updatedWorkerConfig);
34+
await vi.waitFor(
35+
async () => {
36+
const updatedResponse = await getTextResponse();
37+
expect(updatedResponse).toBe('The value of MY_VAR is "two"');
38+
},
39+
{ timeout: 5000 }
40+
);
41+
}
42+
);
43+
44+
test.runIf(!isBuild)(
45+
"reports errors in updates to the Worker config",
46+
async ({ onTestFinished }) => {
47+
const workerConfigPath = path.join(__dirname, "../wrangler.json");
48+
const originalWorkerConfig = fs.readFileSync(workerConfigPath, "utf-8");
49+
50+
onTestFinished(async () => {
51+
fs.writeFileSync(workerConfigPath, originalWorkerConfig);
52+
// We need to ensure that the original config is restored before the next test runs
53+
await vi.waitFor(
54+
async () => {
55+
const revertedResponse = await getTextResponse();
56+
expect(revertedResponse).toBe('The value of MY_VAR is "one"');
57+
},
58+
{ timeout: 5000 }
59+
);
60+
});
61+
62+
const originalResponse = await getTextResponse();
63+
expect(originalResponse).toBe('The value of MY_VAR is "one"');
64+
65+
const updatedWorkerConfig = JSON.stringify({
66+
...JSON.parse(originalWorkerConfig),
67+
main: "./src/non-existing-file.ts",
68+
vars: {
69+
MY_VAR: "two",
70+
},
71+
});
72+
fs.writeFileSync(workerConfigPath, updatedWorkerConfig);
73+
await vi.waitFor(
74+
async () => {
75+
const newResponse = await getTextResponse();
76+
expect(serverLogs.errors.join()).toMatch(
77+
/.*The provided Wrangler config main field .+? doesn't point to an existing file.*/
78+
);
79+
expect(newResponse).toBe('The value of MY_VAR is "one"');
80+
},
81+
{ timeout: 5000 }
82+
);
83+
}
84+
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "@playground/config-changes",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"build": "vite build --app",
7+
"check:types": "tsc --build",
8+
"dev": "vite dev",
9+
"preview": "vite preview"
10+
},
11+
"devDependencies": {
12+
"@cloudflare/vite-plugin": "workspace:*",
13+
"@cloudflare/workers-tsconfig": "workspace:*",
14+
"@cloudflare/workers-types": "^4.20250321.0",
15+
"typescript": "catalog:default",
16+
"vite": "catalog:vite-plugin",
17+
"wrangler": "workspace:*"
18+
}
19+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
interface Env {
2+
MY_VAR: string;
3+
}
4+
5+
export default {
6+
async fetch(_, env) {
7+
return new Response(`The value of MY_VAR is "${env.MY_VAR}"`);
8+
},
9+
} satisfies ExportedHandler<Env>;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"files": [],
3+
"references": [
4+
{ "path": "./tsconfig.node.json" },
5+
{ "path": "./tsconfig.worker.json" }
6+
]
7+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": ["@cloudflare/workers-tsconfig/base.json"],
3+
"include": ["vite.config.ts", "__tests__"]
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": ["@cloudflare/workers-tsconfig/worker.json"],
3+
"include": ["src"]
4+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"$schema": "http://turbo.build/schema.json",
3+
"extends": ["//"],
4+
"tasks": {
5+
"build": {
6+
"outputs": ["dist/**"]
7+
}
8+
}
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { cloudflare } from "@cloudflare/vite-plugin";
2+
import { defineConfig } from "vite";
3+
4+
export default defineConfig({
5+
// We should enable `inspectorPort` in this playground when it's possible to do so to verify that there are no port collisions on server restarts
6+
plugins: [cloudflare({ inspectorPort: false, persistState: false })],
7+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"$schema": "node_modules/wrangler/config-schema.json",
3+
"name": "worker",
4+
"compatibility_date": "2024-12-30",
5+
"main": "./src/index.ts",
6+
"vars": { "MY_VAR": "one" }
7+
}

0 commit comments

Comments
 (0)