Skip to content

[vitest-pool-workers] Fix dynamic import() in entrypoint and DO handlers#13056

Merged
penalosa merged 5 commits intomainfrom
penalosa/vitest-improvements
Mar 27, 2026
Merged

[vitest-pool-workers] Fix dynamic import() in entrypoint and DO handlers#13056
penalosa merged 5 commits intomainfrom
penalosa/vitest-improvements

Conversation

@penalosa
Copy link
Copy Markdown
Contributor

@penalosa penalosa commented Mar 25, 2026

Fixes #12924.
Fixes #5387.

Dynamic import() inside exports.default.fetch(), SELF.fetch(), or Durable Object handlers would hang and fail with "Cannot perform I/O on behalf of a different Durable Object". The module runner's transport — which communicates over a WebSocket owned by the runner DO — was being invoked from a different DO context.

The fix uses the onModuleRunner hook in vitest/worker's init() to patch the module runner's transport.invoke(), routing all calls through runInRunnerObject(). This ensures module resolution always happens in the runner DO's I/O context, regardless of where the import() originates.

Includes a regression fixture (fixtures/vitest-pool-workers-examples/dynamic-import/) covering both the entrypoint path (#12924) and the DO path (#5387).


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: internal fix, no user-facing config change

Open with Devin

Patch the module runner transport via onModuleRunner hook so that
transport.invoke() calls always execute inside the runner DO's I/O
context. This fixes dynamic import() inside exports.default.fetch(),
SELF.fetch(), and Durable Object handlers.

Fixes #12924
Fixes #5387
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 25, 2026

🦋 Changeset detected

Latest commit: 1ab29ab

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 25, 2026

✅ All changesets look good

ask-bonk[bot]

This comment was marked as resolved.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Mar 25, 2026

Review posted successfully on PR #13056. Here's a summary of what I found:

  1. Unused imports in test filerunDurableObjectAlarm and runInDurableObject are imported but never used in dynamic-import.test.ts. Posted a suggestion to clean up the import line.

  2. Inaccurate comment reference — A comment in packages/vitest-pool-workers/src/worker/index.ts:209 says "transport patch in entrypoints.ts" but the transport patch (onModuleRunner) is actually in index.ts itself. entrypoints.ts has a different mechanism (importModule). Posted a suggestion to fix the reference.

The core fix itself — using onModuleRunner to patch transport.invoke() with runInRunnerObject() — looks correct and well-targeted for the cross-DO I/O context issue.

github run

Comment thread packages/vitest-pool-workers/src/worker/index.ts
@penalosa penalosa marked this pull request as ready for review March 25, 2026 18:48
@penalosa penalosa requested a review from a team as a code owner March 25, 2026 18:48
@penalosa penalosa requested a review from jamesopstad March 25, 2026 18:48
@workers-devprod
Copy link
Copy Markdown
Contributor

workers-devprod commented Mar 25, 2026

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

devin-ai-integration[bot]

This comment was marked as resolved.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 25, 2026

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@13056

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@13056

miniflare

npm i https://pkg.pr.new/miniflare@13056

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@13056

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@13056

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@13056

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@13056

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@13056

wrangler

npm i https://pkg.pr.new/wrangler@13056

commit: 1ab29ab

@penalosa
Copy link
Copy Markdown
Contributor Author

/bonk fix the formatting in this PR and commit the result

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good fix. The core approach is sound: onModuleRunner is a documented vitest VitestWorker hook (vitest v4.1.0 src/runtime/workers/types.ts), and patching transport.invoke() to route through runInRunnerObject() correctly ensures module resolution always happens in the runner DO's I/O context.

A few observations:

The transport is private readonly on ModuleRunner — the PR works around this by casting to a structural type at runtime (as { transport?: { invoke?: ... } }). This is fine pragmatically, but it's worth noting this is reaching into vite internals. If a future vite version changes the transport architecture (e.g., making it truly inaccessible or restructuring NormalizedModuleRunnerTransport), this patch would silently become a no-op due to the optional chaining guard. That's actually a reasonable degradation path, but it might be worth adding a __console.warn if the guard fails (i.e., runner.transport?.invoke is falsy), so the team gets early signal when/if vite changes break this.

Agreeing with other reviewers on two minor issues:

  1. The comment on line 208-209 says "transport patch in entrypoints.ts" but the onModuleRunner hook is in this same file (index.ts). entrypoints.ts has the importModule() wrapper which is a separate mechanism. The author already acknowledged this via the reply about the comment never being accurate, but the new text should still be corrected.

  2. runDurableObjectAlarm and runInDurableObject are imported but unused in dynamic-import.test.ts. This will likely fail lint (@typescript-eslint/no-unused-vars).

Neither blocks merging.

ask-bonk[bot]

This comment was marked as resolved.

ask-bonk[bot]

This comment was marked as resolved.

Comment thread packages/vitest-pool-workers/src/worker/index.ts
@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Mar 26, 2026

Review posted on PR #13056 with approval. Here's a summary of my findings:

The fix is correct and well-targeted. It uses vitest's onModuleRunner hook (a documented VitestWorker API in vitest v4.1.0) to patch transport.invoke() so all calls go through runInRunnerObject(). This ensures module resolution from dynamic import() always happens in the runner DO's I/O context, regardless of which DO context triggered it.

Three comments posted:

  1. Unused imports in dynamic-import.test.tsrunDurableObjectAlarm and runInDurableObject are imported but never used. Will fail lint.

  2. Inaccurate comment reference at line 208-209 — says "transport patch in entrypoints.ts" but the onModuleRunner hook is in index.ts. Suggested correcting to "onModuleRunner transport patch below".

  3. Private transport accessModuleRunner.transport is private readonly in vite's source. The type assertion bypasses this at runtime. The optional chaining provides safe degradation, but suggested adding a __console.warn if the guard fails so the team gets early signal if a future vite upgrade breaks the patch.

github run

Comment thread packages/vitest-pool-workers/src/worker/index.ts
Comment thread packages/vitest-pool-workers/src/worker/index.ts
Comment thread packages/vitest-pool-workers/src/worker/index.ts Outdated
@github-project-automation github-project-automation bot moved this from Untriaged to Approved in workers-sdk Mar 26, 2026
@penalosa penalosa merged commit 8384743 into main Mar 27, 2026
51 checks passed
@penalosa penalosa deleted the penalosa/vitest-improvements branch March 27, 2026 01:09
@github-project-automation github-project-automation bot moved this from Approved to Done in workers-sdk Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

3 participants