diff --git a/.changeset/big-waves-hammer.md b/.changeset/big-waves-hammer.md new file mode 100644 index 000000000000..4682e09aa640 --- /dev/null +++ b/.changeset/big-waves-hammer.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +fix: debounce restarting worker on assets dir file changes when `--x-dev-env` is enabled. diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index 7ec1dc18ed57..4435c70b0c04 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -1452,6 +1452,53 @@ describe("watch mode", () => { response = await fetch(`${url}/hey`); expect(response.status).toBe(404); }); + + it("debounces runtime restarts when assets are modified", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed({ + "wrangler.toml": dedent` + name = "${workerName}" + compatibility_date = "2023-01-01" + main = "src/index.ts" + + [assets] + directory = "./public" + `, + "src/index.ts": dedent` + export default { + async fetch(request) { + return new Response("Hello, World!") + } + } + `, + "public/index.html": "Hello from Assets", + }); + const worker = helper.runLongLived("wrangler dev"); + + const { url } = await worker.waitForReady(); + + // Modify assets multiple times in quick succession + + await helper.seed({ + "public/a.html": "a", + }); + + await helper.seed({ + "public/b.html": "b", + }); + + await helper.seed({ + "public/c.html": "c", + }); + + await worker.waitForReload(); + + // The three changes should be debounced, so only one reload should occur + await expect(worker.waitForReload(5_000)).rejects.toThrowError(); + + // now check assets are still fetchable + await expect(fetchText(url)).resolves.toBe("Hello from Assets"); + }); }); describe.each([ diff --git a/packages/wrangler/e2e/helpers/wrangler.ts b/packages/wrangler/e2e/helpers/wrangler.ts index 3eb2a176589b..791add741de4 100644 --- a/packages/wrangler/e2e/helpers/wrangler.ts +++ b/packages/wrangler/e2e/helpers/wrangler.ts @@ -39,9 +39,10 @@ export class WranglerLongLivedCommand extends LongLivedCommand { return match.groups as { url: string }; } - async waitForReload(): Promise { + async waitForReload(readTimeout?: number): Promise { await this.readUntil( - /Detected changes, restarted server|Reloading local server\.\.\./ + /Detected changes, restarted server|Reloading local server\.\.\./, + readTimeout ); } } diff --git a/packages/wrangler/src/api/startDevWorker/BundlerController.ts b/packages/wrangler/src/api/startDevWorker/BundlerController.ts index c327ac9ebfbc..24688760f1ee 100644 --- a/packages/wrangler/src/api/startDevWorker/BundlerController.ts +++ b/packages/wrangler/src/api/startDevWorker/BundlerController.ts @@ -14,6 +14,7 @@ import { getAssetChangeMessage } from "../../dev"; import { runBuild } from "../../dev/use-esbuild"; import { logger } from "../../logger"; import { isNavigatorDefined } from "../../navigator-user-agent"; +import { debounce } from "../../pages/utils"; import { getWranglerTmpDir } from "../../paths"; import { Controller } from "./BaseController"; import { castErrorCause } from "./events"; @@ -264,6 +265,12 @@ export class BundlerController extends Controller { async #ensureWatchingAssets(config: StartDevWorkerOptions) { await this.#assetsWatcher?.close(); + const debouncedRefreshBundle = debounce(() => { + if (this.#currentBundle) { + this.emitBundleCompleteEvent(config, this.#currentBundle); + } + }); + if (config.assets?.directory) { this.#assetsWatcher = watch(config.assets.directory, { persistent: true, @@ -271,9 +278,7 @@ export class BundlerController extends Controller { }).on("all", async (eventName, filePath) => { const message = getAssetChangeMessage(eventName, filePath); logger.debug(`🌀 ${message}...`); - if (this.#currentBundle) { - this.emitBundleCompleteEvent(config, this.#currentBundle); - } + debouncedRefreshBundle(); }); } }