@rollup/plugin-virtual: TS2349: This expression is not callable under modern "moduleResolution": "NodeNext"
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 82/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- javascript, typescript
- Domain
- build-system, tooling
Research direction
Start with packages/virtual/package.json and packages/virtual/types/index.d.ts, then inspect the NodeNext import in the reported src/index.ts context. Verify the package's import and require type mappings by compiling the example with modern TypeScript settings; done means the default import is recognized as callable without TS2349.
Written by the indexing model from the issue text.
Description
- Rollup Plugin Name: @rollup/plugin-virtual
- Rollup Plugin Version: latest
- Rollup Version: latest
- Operating System (or Browser): macOS
- Node Version: v24.18.0
- Link to reproduction (⚠️ read below): I'm providing the exact type error context below. This is a static type resolution failure in TypeScript rather than a runtime execution bug.
Expected Behavior
When importing the plugin into a project using modern TypeScript settings ("moduleResolution": "NodeNext" or "Node16"), the default import should be recognized as a callable function:
import virtual from '@rollup/plugin-virtual';
export default {
plugins: [
virtual({ 'virtual-module': 'export default "hello";' })
]
};
Actual Behavior
The TypeScript compiler throws a compilation error preventing the build from running:
src/index.ts:59:13 - error TS2349: This expression is not callable.
Type 'typeof import(".../node_modules/@rollup/plugin-virtual/types/index")' has no call signatures.
59 virtual({
~~~~~~~
Additional Information
The issue stems from a combination of the package layout configuration inside packages/virtual/package.json and packages/virtual/types/index.d.ts.
Why this happens
The plugin's package.json exports a single top-level typings statement:
"exports": {
"types": "./types/index.d.ts",
"import": "./dist/es/index.js",
"default": "./dist/cjs/index.js"
}
Because the package does not explicitly include "type": "module", TypeScript's NodeNext engine treats ./types/index.d.ts as a CommonJS declaration file.
Under a CommonJS environment interpretation, TypeScript reads export default function virtual as an object property wrapper ({ default: function }) instead of a root-level callable default function export. As a result, the default import resolves to the module namespace object instead of the callable function, breaking execution under strict TypeScript configurations.
Fix
Provide separate type mappings for ESM and CJS hooks within exports so TypeScript evaluates them in their matching format context:
- Copy
packages/virtual/types/index.d.tsto a dedicated.d.mtsversion. - Update the
exportsconfiguration block inpackages/virtual/package.json:"exports": { "import": { "types": "./types/index.d.mts", "default": "./dist/es/index.js" }, "require": { "types": "./types/index.d.ts", "default": "./dist/cjs/index.js" } }
- Dominant language
- JavaScript
- Stars
- 3.8k
- Forks
- 635
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from rollup/plugins
-
Difficulty 4/5 3-5 days Newbie friendliness 52/100
-
Difficulty 3/5 1-2 days Newbie friendliness 48/100
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
-
Support js-yaml v5 Open
Difficulty 4/5 3-5 days Newbie friendliness 45/100
-
Babel 8 support Open
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
HarperFast/skills#96 ·
-
[Block] Latest Posts [Type] Bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Automattic/studio#4908 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
sugarlabs/musicblocks#8847 ·