nx
nx copied to clipboard
Type error when building dependent packages using Node16 Module Setting
Current Behavior
In Typescript 5.1 with moduleResolution set to Node16, I think there's an issue with the approach Nx uses to handle incremental builds when combined with ESM modules.
Currently if a package A
(which is ESM) in your repo depends on another module B
, then Typescript will produce type errors when building A
complaining that package B can't be resolved. The explanation for this appears to be that Node treats "relative" imports differently from imports of "node_modules", and in ESM it's not possible to "relatively" import a package.
That means that Typescript also errors when moduleResolution
is Node16 because it tries to match Node's behaviour.
Under the hood, Nx is "swapping" the tsconfig alias for package B
when it builds package A
, to point to the dist/
directory output of package B
. That means it's being treated as a "relative" import by the type system, so it prevents the build from succeeding.
The behaviour of Typescript is explained more here: https://github.com/microsoft/TypeScript/issues/54620#issuecomment-1648618109
Expected Behavior
The strategy Nx uses for incremental building should support Node and Typescript's module resolution behaviour.
Typescript >5 moduleResolution: node16
GitHub Repo
https://github.com/DevCycleHQ/js-sdks/tree/typescript-repro
Steps to Reproduce
- Check out the linked branch of our Nx Monorepo
- run
nx build js
- Observe the type errors that occur
the js
lib depends on the shared-types
lib which is being output to dist/lib/shared/types
so you can inspect the output of the package.json there
Nx Report
Node : 18.16.0
OS : darwin arm64
yarn : 3.6.0
Hasher : Native
nx : 16.3.2
lerna : 5.6.2
@nx/js : 16.3.2
@nx/jest : 16.3.2
@nx/linter : 16.3.2
@nx/workspace : 16.3.2
@nx/cypress : 16.3.2
@nx/detox : 16.3.2
@nx/devkit : 16.3.2
@nx/esbuild : 16.3.2
@nx/eslint-plugin : 16.3.2
@nx/next : 16.3.2
@nx/node : 16.3.2
@nx/react : 16.3.2
@nx/react-native : 16.3.2
@nx/rollup : 16.3.2
@nrwl/tao : 16.3.2
@nx/web : 16.3.2
@nx/webpack : 16.3.2
typescript : 5.0.4
---------------------------------------
Local workspace plugins:
@devcycle/bucketing-assembly-script
@devcycle/nodejs-server-sdk-cloud-typescript-example
@devcycle/nodejs-server-sdk-local-typescript-example
@devcycle/openfeature-nodejs-provider
@devcycle/bucketing-test-data
@devcycle/js-client-sdk-web-example
with-provider
@devcycle/openfeature-nodejs-example
next-js-app
@devcycle/nodejs-server-sdk-cloud-js-example
@devcycle/nodejs-server-sdk-local-js-example
@devcycle/bucketing
@devcycle/react-native-client-sdk
@devcycle/types
@devcycle/nodejs-server-sdk
@devcycle/react-client-sdk
Failure Logs
No response
Operating System
- [X] macOS
- [ ] Linux
- [ ] Windows
- [ ] Other (Please specify)
Additional Information
No response
This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! 🙏
not stale
Just to add more context here, Typescript's docs are now updated with a really good guide on ES modules compatibility. There's a relevant section here about not using paths
to link monorepo packages with the main justification being the issue that's reported here
https://www.typescriptlang.org/docs/handbook/modules/reference.html#paths-should-not-point-to-monorepo-packages-or-node_modules-packages
Basically I think the fundamental way that Nx links packages is flawed and can't be used in an ES module future where relative package imports are no longer supported. To work properly it would likely need to switch to some kind of system that takes advantage of native workspace linking (supported by all major package managers)