-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
Bug Report
I have a package with "type": "module" which uses the "exports" field to indicate how to use it via require:
"type": "module",
"exports": {
".": {
"types": "./build/index.d.ts",
"require": "./build/index.cjs",
"import": "./build/index.cjs"
}
},
and I have a project targeting commonjs that wants to use it. In order to do so, I have to set "moduleResolution":"node16" (or nodenext) in my project (the real package has multiple exports, so I can't just fall back to "main" and "types").
But now I get an error:
src/index.ts:1:21 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("package")' call instead.
To convert this file to an ECMAScript module, change its file extension to '.mts' or create a local package.json file with `{ "type": "module" }`.
even though the package explicitly exports a require friendly version.
In addition, if index.d.ts in the package imports from another file eg:
import { foo } from "./util";
I get another error:
../package/build/index.d.ts:1:21 - error TS2835: Relative import paths need explicit file extensions in EcmaScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './util.js'?
1 import { foo } from "./util";
I sort of get why this happens; but the .d.ts was generated by tsc in the first place, and is solely for tsc's consumption. And since I'm generating commonjs from a commonjs export, it seems like this really shouldn't apply.
If I change the type of the package to "commonjs" all the issues go away. But I don't necessarily have control over the package, and even if I do, it seems reasonable that I should be able to develop it as a module (ie have .js files treated as esm rather than commonjs) while providing suitable exports for both commonjs and esm. And I should add that this actually works as far as node is concerned.
🔎 Search Terms
moduleresolution node16 commonjs
🕗 Version & Regression Information
4.7 (when ts first added support for "exports" in package files).
- This is the behavior in every version I tried, from 4.7 through
@nextand I reviewed the FAQ for entries aboutmoduleResolution
⏯ Playground Link
I don't think its possible to setup the playground or workbench to demonstrate this, but here's a tiny project:
git clone https://github.com/markw65/moduleresolution-bug
cd moduleresolution-bug/package
npm install
npx tsc
cd ../project
npm install
npx tscresults in
../package/build/index.d.ts:1:21 - error TS2835: Relative import paths need explicit file extensions in EcmaScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './util.js'?
1 import { foo } from "./util";
~~~~~~~~
src/index.ts:1:21 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("package")' call instead.
To convert this file to an ECMAScript module, change its file extension to '.mts' or create a local package.json file with `{ "type": "module" }`.
1 import { baz } from "package";
💻 Code
This is less of a code issue, and more related to the whole environment
🙁 Actual behavior
tsc reports an error saying that commonjs code can't require a esmodule
🙂 Expected behavior
tsc should recognize that the "exports" field explicitly exports a commonjs entry point, and use that.