Skip to content

[vitest-pool-workers] Support require("./x.wasm?module") in CommonJS deps#14189

Open
tahmid-23 wants to merge 4 commits into
cloudflare:mainfrom
tahmid-23:fix/cjs-wasm-module-fallback
Open

[vitest-pool-workers] Support require("./x.wasm?module") in CommonJS deps#14189
tahmid-23 wants to merge 4 commits into
cloudflare:mainfrom
tahmid-23:fix/cjs-wasm-module-fallback

Conversation

@tahmid-23

@tahmid-23 tahmid-23 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Previously, only literal await import("./x.wasm?module") specifiers were rewritten through the static analysis path added in #11094. CommonJS dependencies that use require("./x.wasm?module") reach the module-fallback service at runtime, where the ?module suffix went unhandled. The fallback either failed with No such module "<abs>/x.wasm?module" or, when a CompiledWasm rule was configured, attempted to evaluate the WebAssembly bytes as JavaScript.

These require()s work in deployed workers because esbuild's bundler statically rewrites them into ES dynamic imports. vitest-pool-workers' Vite-based pipeline doesn't do that rewrite and instead defers to the module-fallback at runtime.

The module-fallback now strips ?module from the resolved target and synthesizes a CommonJS wrapper that re-requires the underlying .wasm by absolute path, exposing it on default to match what workerd produces for CompiledWasm modules.

Prisma 7 generates such require() statements on wasm?module imports. When running vitest under its default configuration, it prefers to load js-like extensions before ts-like extensions. Hence, this issue currently exists while running Prisma 7 with vitest-pool-workers, with the workaround being to reorder the extensions to prefer ts-like extensions first. This fix aims to make this workaround unnecessary (and support other possible packages that require() a wasm?module import.

It is possible to construct code, somewhat pathologically, that uses a require statement that the fallback server does not handle because we do not strip the ?module suffix from specifier. However, the example that I tried wouldn't actually resolve the imports when actually running the worker. Hence, I did not choose to strip the suffix from specifier, since I do not believe it is necessary for imports that actually resolve on workerd.


  • 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: bug fix

A picture of a cute animal (not mandatory, but encouraged)


Open in Devin Review

@changeset-bot

changeset-bot Bot commented Jun 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: dda6544

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

This PR includes changesets to release 1 package
Name Type
@cloudflare/vitest-pool-workers Patch

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

@workers-devprod workers-devprod requested review from a team and emily-shen and removed request for a team June 4, 2026 20:25
@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/cjs-wasm-module-fallback.md: [@cloudflare/wrangler]
  • fixtures/vitest-pool-workers-examples/module-resolution/test/index.spec.ts: [@cloudflare/wrangler]
  • fixtures/vitest-pool-workers-examples/module-resolution/vendor/cjs-wasm-module-dep/add.wasm: [@cloudflare/wrangler]
  • fixtures/vitest-pool-workers-examples/module-resolution/vendor/cjs-wasm-module-dep/index.d.ts: [@cloudflare/wrangler]
  • fixtures/vitest-pool-workers-examples/module-resolution/vendor/cjs-wasm-module-dep/index.js: [@cloudflare/wrangler]
  • fixtures/vitest-pool-workers-examples/module-resolution/vendor/cjs-wasm-module-dep/package.json: [@cloudflare/wrangler]
  • fixtures/vitest-pool-workers-examples/package.json: [@cloudflare/wrangler]
  • packages/vitest-pool-workers/src/pool/module-fallback.ts: [@cloudflare/wrangler]
  • pnpm-lock.yaml: [@cloudflare/wrangler]

devin-ai-integration[bot]

This comment was marked as resolved.

@tahmid-23 tahmid-23 force-pushed the fix/cjs-wasm-module-fallback branch 2 times, most recently from f4c2a37 to 701ab4d Compare June 8, 2026 17:54
@tahmid-23 tahmid-23 force-pushed the fix/cjs-wasm-module-fallback branch from 701ab4d to 866ec46 Compare June 15, 2026 08:58
@github-project-automation github-project-automation Bot moved this to Untriaged in workers-sdk Jun 15, 2026
@workers-devprod

workers-devprod commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

devin-ai-integration[bot]

This comment was marked as resolved.

@tahmid-23 tahmid-23 force-pushed the fix/cjs-wasm-module-fallback branch from 866ec46 to dfc80a4 Compare June 15, 2026 09:04
@pkg-pr-new

pkg-pr-new Bot commented Jun 15, 2026

Copy link
Copy Markdown
create-cloudflare

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

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/@cloudflare/deploy-helpers@14189

@cloudflare/kv-asset-handler

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

miniflare

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

@cloudflare/pages-shared

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

@cloudflare/unenv-preset

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

@cloudflare/vite-plugin

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

@cloudflare/vitest-pool-workers

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

@cloudflare/workers-auth

npm i https://pkg.pr.new/@cloudflare/workers-auth@14189

@cloudflare/workers-editor-shared

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

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@14189

wrangler

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

commit: dda6544

@tahmid-23

Copy link
Copy Markdown
Contributor Author

@emily-shen do you think you could take a look at this? I totally understand if you're attending to other work, just bumping in case you've forgotten. thank you

@emily-shen emily-shen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm, sorry for the delayed review!

emily-shen and others added 4 commits June 16, 2026 10:43
…deps

Previously, only literal `await import("./x.wasm?module")` specifiers were
rewritten through the static analysis path added in cloudflare#11094. CommonJS
dependencies that use `require("./x.wasm?module")` reach the module-fallback
service at runtime, where the `?module` suffix went unhandled. The fallback
either failed with `No such module "<abs>/x.wasm?module"` or, when a
CompiledWasm rule was configured, attempted to evaluate the WebAssembly bytes
as JavaScript.

These `require()`s work in deployed workers because esbuild's bundler
statically rewrites them into ES dynamic imports. vitest-pool-workers'
Vite-based pipeline doesn't do that rewrite and instead defers to the
module-fallback at runtime.

The module-fallback now strips `?module` from the resolved target and
synthesizes a CommonJS wrapper that re-`require`s the underlying `.wasm` by
absolute path, exposing it on `default` to match what workerd produces for
CompiledWasm modules.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per .changeset/README.md, changeset titles shouldn't use `fix:`/`feat:`/etc
prefixes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…Windows

The CommonJS wrapper added in the previous commit embeds the resolved wasm
filePath into a `require(...)` call. On Linux/macOS this is `/abs/path.wasm`,
which workerd resolves as intended. On Windows the leading `/` has been
stripped at the module-fallback entry, leaving paths like `C:/a/b.wasm`.

workerd resolves non-prefixed specifiers via `kj::Path::eval` against the
referrer's parent directory; it only anchors to the root when the specifier
starts with `/`. Without the slash, `C:/a/b.wasm` is appended to the
referrer's directory, which doesn't exist.

Extract `ensureRootedPath` (mirroring the existing redirect-side normalization
in `buildRedirectResponse`) and apply it to the wrapper's embedded path.
@emily-shen emily-shen force-pushed the fix/cjs-wasm-module-fallback branch from 3e637c1 to dda6544 Compare June 16, 2026 09:47

@workers-devprod workers-devprod left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codeowners reviews satisfied

@github-project-automation github-project-automation Bot moved this from Untriaged to Approved in workers-sdk Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Approved

Development

Successfully merging this pull request may close these issues.

3 participants