Skip to content

moduleResolution node16 conflicts with type "module" packages that export commonjs #53045

@markw65

Description

@markw65

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 @next and I reviewed the FAQ for entries about moduleResolution

⏯ 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 tsc

results 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions