cloudflare / cloudflare/workers-sdk

vitest-pool-workers 0.13.x: require() resolves ESM instead of CJS for transitive deps (mimetext, mime-types via agents)

Open
#13,037 2 comments 1 reaction 2 assignees Claimed by @MattieTK View on GitHub
package:vitest
Dominant language
TypeScript
Stars
4.5k
Forks
1.5k
Avg merge
3d 8h
Merged PRs (30d)
186

Description

## Bug Report

### Versions
- `@cloudflare/vitest-pool-workers`: 0.13.3 and 0.13.4
- `vitest`: 4.1.0
- `wrangler`: 4.76.0
- `workerd`: latest bundled

### Related Issues
- #12899 — same root cause, closed because the reporter worked around it by changing their own package's bundler
- #12902 — PR with a fix, closed by reporter (not by maintainers)

The underlying bug is **not fixed**. It affects anyone with transitive dependencies that have dual CJS/ESM exports.

### Problem

When workerd loads a module via `require()`, the pool-workers 0.13.x module fallback service resolves using the `"import"` export condition instead of `"require"` or `"default"`. This causes workerd to load the ESM entry of a dual-format package, which fails with `SyntaxError: Invalid or unexpected token`.

This worked in 0.12.x because the CJS-ESM shim was applied universally. 0.13.x introduced `?mf_vitest_no_cjs_esm_shim` which disables that shim, exposing this resolution bug.

### Reproduction

Any project using `agents` SDK (Cloudflare's own package) hits this because:

```
agents@0.8.0
→ mimetext@3.0.28 (type: "module", imports node:os, mime-types)
→ mime-types@2.1.35 (CJS, uses require('path'))
```

`mimetext` has `"type": "module"` in its package.json. When workerd `require()`s it, the resolver picks the ESM entry. The ESM file contains `import { EOL } from "node:os"` which fails in the CJS context.

**Minimal test that reproduces:**

```ts
// vitest.config.ts
import { cloudflareTest } from '@cloudflare/vitest-pool-workers'
import { defineConfig } from 'vitest/config'

export default defineConfig({
plugins: [
cloudflareTest({
wrangler: { configPath: './wrangler.jsonc' },
}),
],
})
```

```ts
// test/example.test.ts
import { env } from 'cloudflare:workers'
import { describe, it, expect } from 'vitest'

describe('basic', () => {
it('loads worker', () => {
expect(env).toBeDefined()
})
})
```

Where the worker source imports from `agents` (or any package with a transitive dep that has dual CJS/ESM exports).

The test fails at module load time with:
```
SyntaxError: Invalid or unexpected token
```

No stack trace is provided, making it very hard to debug which package is causing the issue.

### `deps.optimizer.ssr.include` does NOT help

Per the [known issues docs](https://developers.cloudflare.com/workers/testing/vitest-integration/known-issues/), we tried:

```ts
test: {
deps: {
optimizer: {
ssr: {
enabled: true,
include: ['mimetext', 'mime-types'],
},
},
},
}
```

This does not fix the issue because the optimizer operates at the Vite transform level, but the module fallback service in pool-workers reads files from disk and serves them directly to workerd, bypassing the optimizer.

Adding `agents` to the optimizer fails because it imports `node:async_hooks` and `node:diagnostics_channel` which the optimizer can't resolve.

### Expected Behavior

`require()` calls should resolve to CJS entries (`"require"` or `"default"` condition) from `package.json` exports, not ESM entries.

### Suggested Fix

PR #12902 had a working fix with comprehensive tests. The approach:
1. When `method === "require"` and the resolved file is ESM, walk up to find `package.json`
2. Look up the `"require"` or `"default"` condition in the exports map
3. Redirect to the CJS alternative

### Workaround

None known for transitive deps. The reporter of #12899 worked around it by changing their own package's build tooling, but that doesn't help when the broken package is a transitive dependency you don't control.

### Additional Context

This blocks upgrading from pool-workers 0.12.x for any project using the `agents` SDK, `resend` email SDK, or other packages with dual-format transitive deps.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.