Skip to content

vitest/coverage-istanbul crashes with TypeError: template is not a function when used with cloudflare/vitest-pool-workers #9935

@mictian

Description

@mictian

Describe the bug

When using vitest/[email protected] with cloudflare/[email protected], running tests with coverage fails immediately with:

TypeError: template is not a function
 ❯ requireVisitor node_modules/@vitest/coverage-istanbul/dist/provider.js:1024:40
 ❯ VitestModuleEvaluator._runInlinedModule node_modules/vitest/dist/module-evaluator.js:206:4
 ❯ ServerModuleRunner.directRequest node_modules/vite/dist/node/module-runner.js:1243:59
The error does not occur in a plain Vitest setup (without the Cloudflare Workers pool).

Root cause
The bundled provider.js imports babel/core via a default ESM import (import require$$0$3 from '@babel/core'), generated by rollup/plugin-commonjs during the build. When this import is resolved by Vite's ServerModuleRunner (used by cloudflare/vitest-pool-workers), it only detects CJS named exports declared via direct exports.X = ... assignments.

babel/core declares most of its exports (including template, parseSync, traverse) using Object.defineProperty(exports, ...) with lazy getters. These are invisible to Vite's CJS static analysis. Only 7 out of 34 exports are detected — the ones using direct assignment patterns.

The result: template is undefined on the imported object, and provider.js crashes when it tries to call it.

Used Package Manager
npm

Reproduction

Repo: temp-vitest-istanbul-repro

git clone https://github.com/mictian/temp-vitest-istanbul-repro
cd vitest-istanbul-repro
npm install
npm test

The repro contains:

  • vitest.config.ts — uses cloudflareTest plugin + istanbul coverage
  • wrangler.jsonc — minimal Cloudflare Workers config
  • src/sum.ts + src/sum.test.ts — trivial test file

Suggested fix

In packages/coverage-istanbul/rollup.config.js, replace the ESM default import of babel/core with a createRequire call so it loads via Node's native CJS loader (which correctly handles Object.defineProperty exports).

I verified this locally by patching dist/provider.js:

- import require$$0$3 from '@babel/core';
+ import { createRequire as __createRequire } from 'node:module';
+ const __require = __createRequire(import.meta.url);
+ const require$$0$3 = __require('@babel/core');

After patching, the coverage provider loads successfully with all 34 babel/core exports present.

A possible implementation in the rollup config would be a renderChunk plugin that rewrites the babel/core import to use createRequire.

System Info

System Info
- vitest: 4.1.0
- @vitest/coverage-istanbul: 4.1.0
- @cloudflare/vitest-pool-workers: 0.13.0
- Node: v22.x
- OS: macOS

Used Package Manager

npm

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    feat: coverageIssues and PRs related to the coverage featurep3-minor-bugAn edge case that only affects very specific usage (priority)

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions