Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect resolution of CJS types from dual-package dependency in multi-project build with mixed ESNext/Bundler and NodeNext modules #57553

Open
haines opened this issue Feb 26, 2024 · 3 comments · May be fixed by #60039
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@haines
Copy link

haines commented Feb 26, 2024

🔎 Search Terms

"NodeNext", "ESNext", "Bundler", "module", "moduleResolution", "ESM", "CJS", "multi-project", "dual package"

🕗 Version & Regression Information

  • This is the behavior in every version I tried (5.0.4, 5.1.6, 5.2.2, 5.3.3, and 5.5.0-dev.20240226), and I reviewed the FAQ for entries about ESM

⏯ Playground Link

https://github.com/haines/typescript-dual-package-esnext-bundler-nodenext

💻 Code

It's probably less confusing to look at the repo, sorry 🙈 I've tried to make it as minimal as possible.

This bug occurs in a multi-project build where one project (app) is configured to use ESNext module and Bundler module resolution, and another (lib) is using NodeNext. Everything is set up to use ESM with "type": "module" in package.json.

If both projects depend on the same dual-packaged dependency (dep), then when app imports dep directly, TypeScript correctly resolves the ESM types. However, transitive imports of dep through lib are resolved to the CJS types.

🙁 Actual behavior

TypeScript resolves the CJS types for transitive imports of the dual-packaged dependency. If the CJS types are not perfectly compatible with the ESM types, then this causes compile errors.

🙂 Expected behavior

TypeScript resolves the ESM types for all imports of the dual-packaged dependency.

Additional information about the issue

Originally encountered in @bufbuild/protobuf: bufbuild/protobuf-es#718

Our app is full-stack and built with Vite, which is why we want to use ESNext/Bundler, but our lib is consumed by other Node.js-only projects that are built with tsc and therefore it makes sense for that to be built with NodeNext.

@RyanCavanaugh
Copy link
Member

Nice repro setup 🙂

The --traceResolution output explains what's happening:

======== Resolving module '@ahaines/dep' from 'D:/Throwaway/typescript-dual-package-esnext-bundler-nodenext/lib/dist/index.d.ts'. ========
Using compiler options of project reference redirect 'D:/Throwaway/typescript-dual-package-esnext-bundler-nodenext/lib/tsconfig.json'.
Explicitly specified module resolution kind: 'NodeNext'.
======== Module name '@ahaines/dep' was successfully resolved to 'D:/Throwaway/typescript-dual-package-esnext-bundler-nodenext/dep/cjs/index.d.ts'. ========

When app resolves dep from the reference inside lib, it uses lib's moduleResolution setting, which is NodeNext, but it doesn't appear to be respecting the type: module field in the adjacent package.json to know that it should be in ESM mode instead of CJS during that resolution. I believe this is a bug but @andrewbranch should confirm

@andrewbranch andrewbranch added this to the TypeScript 5.5.0 milestone Feb 26, 2024
@andrewbranch
Copy link
Member

This was fixed by #57896

@haines
Copy link
Author

haines commented Aug 30, 2024

Can this please be reopened given #57896 was reverted? I've updated the repro to use TS 5.5.4 and confirmed that it is not working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants