diff --git a/.changeset/quick-wombats-battle.md b/.changeset/quick-wombats-battle.md new file mode 100644 index 000000000000..100d6a157676 --- /dev/null +++ b/.changeset/quick-wombats-battle.md @@ -0,0 +1,12 @@ +--- +"wrangler": minor +--- + +feat: Make DX improvements in `wrangler dev --remote` + +Workers + Assets projects have, in certain situations, a relatively degraded `wrangler dev --remote` developer experience, as opposed to Workers proper projects. This is due to the fact that, for Workers + Assets, we need to make extra API calls to: + +1. check for asset files changes +2. upload the changed assets, if any + +This commit improves the `wrangler dev --remote` DX for Workers + Assets, for use cases when the User Worker/assets change while the API calls for previous changes are still in flight. For such use cases, we have put an exit early strategy in place, that drops the event handler execution of the previous changes, in favour of the handler triggered by the new changes. diff --git a/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts b/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts index 0b77371402a2..fdff4625e3eb 100644 --- a/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts +++ b/packages/wrangler/src/api/startDevWorker/RemoteRuntimeController.ts @@ -64,13 +64,29 @@ export class RemoteRuntimeController extends RuntimeController { async #previewToken( props: Omit & Partial> & - Parameters[0] + Parameters[0] & { bundleId: number } ): Promise { if (!this.#session) { return; } try { + /* + * Since `getWorkerAccountAndContext`, `createRemoteWorkerInit` and + * `createWorkerPreview` are all async functions, it is technically + * possible that new `bundleComplete` events are trigerred while those + * functions are still executing. In such cases we want to drop the + * current bundle and exit early, to avoid unnecessarily executing any + * further expensive API calls. + * + * For this purpose, we want perform a check before each of these + * functions, to ensure no new `bundleComplete` was triggered. + */ + // If we received a new `bundleComplete` event before we were able to + // dispatch a `reloadComplete` for this bundle, ignore this bundle. + if (props.bundleId !== this.#currentBundleId) { + return; + } const { workerAccount, workerContext } = await getWorkerAccountAndContext( { accountId: props.accountId, @@ -89,6 +105,11 @@ export class RemoteRuntimeController extends RuntimeController { ? this.#session.id : this.#session.host.split(".")[0]); + // If we received a new `bundleComplete` event before we were able to + // dispatch a `reloadComplete` for this bundle, ignore this bundle. + if (props.bundleId !== this.#currentBundleId) { + return; + } const init = await createRemoteWorkerInit({ bundle: props.bundle, modules: props.modules, @@ -105,6 +126,11 @@ export class RemoteRuntimeController extends RuntimeController { compatibilityFlags: props.compatibilityFlags, }); + // If we received a new `bundleComplete` event before we were able to + // dispatch a `reloadComplete` for this bundle, ignore this bundle. + if (props.bundleId !== this.#currentBundleId) { + return; + } const workerPreviewToken = await createWorkerPreview( init, workerAccount, @@ -175,6 +201,13 @@ export class RemoteRuntimeController extends RuntimeController { const { bindings } = await convertBindingsToCfWorkerInitBindings( config.bindings ); + + // If we received a new `bundleComplete` event before we were able to + // dispatch a `reloadComplete` for this bundle, ignore this bundle. + if (id !== this.#currentBundleId) { + return; + } + const token = await this.#previewToken({ bundle, modules: bundle.modules, @@ -201,6 +234,7 @@ export class RemoteRuntimeController extends RuntimeController { host: config.dev.origin?.hostname, sendMetrics: config.sendMetrics, configPath: config.config, + bundleId: id, }); // If we received a new `bundleComplete` event before we were able to