nx icon indicating copy to clipboard operation
nx copied to clipboard

Conflicts with package-based monorepo and tsconfig paths aliases (Parsing issue with `NxViteTsPaths`) + solutions and fixes

Open fsgreco opened this issue 1 year ago β€’ 6 comments

Current Behavior

I have an Nx monorepo with package-based approach in which I generated an app and some libraries using the Nx Plugin Generators (e.g. with nx g @nx/react:lib).

Now since the adoption of nxViteTsPaths (that replaced vite-tsconfig-paths) I started to get the same error again and again whenever I use Nx generators to create an app and a library, and then try to import the library inside the app:

Failed to resolve entry for package "@myorg/mylib". The package may have incorrect main/module/exports specified in its package.json.

I already opened an issue in the past about this (https://github.com/nrwl/nx/issues/18492 ), now I'm reopening it with more context and new solutions. Unfortunately, the issue was closed before I could try the suggested solution and answer (my fault here). Also since the suggested solutions where not ideal to me (they nullified the reasons why I had chosen a package-based monorepo) I started to did some digging and investigation:

TL;DR: scroll until "the less invasive solution" section.

Trying

At first I thought that the problem was caused by the properties in the package.json so I generate 3 types of libraries with the Nx plugin generators (@nx/react:lib):

I basically created:

  • a publishable library (that is buildable and uses vite as bundler)
  • a non publishable library that is buildable and uses vite as bundler
  • a non publishable library without build process (no package.json, no viteconfig file)

This were the results: (you can inspect this on the PoC I linked in this issue - you can follow the git history of the project where I explicitly wrote the shell commands used to generate each library step by step inside the commit messages).

nx g lib Buildable Non Buildable
Publishable πŸ”΄ the package.json contains conflicts (main: dist/index.js, wrong exports, etc...) --- not possible, if publishable has to be buildable ---
Non publishable πŸ”΄ the package.json is present since it's buildable, same conflicts as above βœ… This is fine, the library does not have a package.json so nxViteTsPaths follows the path at tsconfig.base.json

Solutions

I also try to found some alternative solutions, although these worked fine, they were not ideal for me, I had to choose between one of these:

  • Solution A: Remove theΒ package.jsonΒ totally from my custom internal library and use the Ts paths to import the library.
  • Solution B: Change the package.json of the library by setting the "main" prop to the actualΒ ./src/index.tsΒ file.
  • Solution C: Tell Nx to build my custom library and set that build process as targetDefaults on nx.json to build the package every time (even when you use "serve").

The first one was not fine, if I choose to publish my library in the future I need a package.json in place. The second one seems weird to me, I read online that it could also generate problems in the future (again, what happens If you want to publish it?). The third one makes sense, but it ruined my dev experience because it disables the hot reloading whenever I changed the library when working on my main package.

the less invasive solution:

After some try and error and studying what was going on with vite I realized something.
The real problem was not caused by the package.json, not directly at least.
It was caused by the exact correlation between the alias in paths (inside tsconfig.base.json) and the package name inside the package.json of the internal library.

So the fix is easy at this point, I changed the alias inside tsconfig.base.json preventing it from being identical to the name of the internal library (the "name" in its own package.json).

For example, this was the situation before:

monorepo
└── packages
    β”œβ”€β”€ frontend
    └── my-lib
        └── package.json ("name": "@myorg/mylib")

tsconfig.base.json ( "paths": {"@myorg/mylib":"etc..."} )

In this case I just changed the tsconfig.base.json altering the name of the paths alias to not match the package name any more (e.g. ``), by doing so I adopt the Solution A explained above but also keep my package.json inside the custom library.

This is the final result:

monorepo
└── packages
    β”œβ”€β”€ frontend
        └── app.tsx ( import {TheComponent} from '@myorg/mylib-internal' )
    └── my-lib
        └── package.json ("name": "@myorg/mylib")

tsconfig.base.json ( "paths": {"@myorg/mylib-internal":"etc..."} )

You can try this scenario on the github repository I linked below in this issue report. Check also its git commits where I explain step by step what I've done in the commit messages.

Expected Behavior

There should be no issues when importing a library using the tsconfig paths aliases. (I think the new nxViteTsPath should parse this Ts paths as before (the way vite-tsconfig-paths used to do).

GitHub Repo

https://github.com/fsgreco/poc-nx-package-based-monorepo

Steps to Reproduce

You can clone the repository of my PoC linked above, launch the nx server frontend app and try to import some components from the libraries already in place.

Otherwise you could try on the fly for yourself:

  1. npx create-nx-workspace@latest package-based --preset=npm
  2. cd package-based
  3. mkdir packages
  4. npm install @nx/react -W
  5. npx nx g @nx/react:app frontend --routing --style styled-components --bundler vite --e2eTestRunner none
  6. npx nx g @nx/react:lib lib-public-buildable --publishable=true --bundler=vite --importPath=@myorg/lib-public-buildable
  7. launch npx nx s frontend
  8. try to import the component from @myorg/lib-public-buildable inside the frontend packages/frontend/src/app/app.tsx

Nx Report

>  NX   Report complete - copy this into the issue template

   Node   : 18.18.2
   OS     : linux-x64
   npm    : 10.2.5
   
   nx                 : 17.2.8
   @nx/js             : 17.2.8
   @nx/linter         : 17.2.8
   @nx/eslint         : 17.2.8
   @nx/workspace      : 17.2.8
   @nx/devkit         : 17.2.8
   @nx/eslint-plugin  : 17.2.8
   @nx/react          : 17.2.8
   @nrwl/tao          : 17.2.8
   @nx/vite           : 17.2.8
   @nx/web            : 17.2.8
   typescript         : 5.2.2

Failure Logs

[vite] Internal server error: Failed to resolve entry for package "lib-non-public-buildable". The package may have incorrect main/module/exports specified in its package.json.

Package Manager Version

10.2.5

Operating System

  • [X] macOS
  • [X] Linux
  • [ ] Windows
  • [ ] Other (Please specify)

Additional Information

Hope this could help others that had this error previously.

fsgreco avatar Jan 07 '24 01:01 fsgreco

I am experiencing similar issues where all my libraries references in tsconfig.base.json are prefixed with a "@". The nxViteTsPaths plugin fails for all absolute imports "Error: Failed to resolve import "@shared/" from "libs\shared_". Does the file exist? ". Has anyone found a workaround?

joewIST avatar Jan 31 '24 11:01 joewIST

@joewIST can you share the snippet of your tsconfig.base.json file?

Sometimes I had that problem when I changed the paths on the fly (meaning while Nx was serving the development environment), in that case I solved by exit (ctrl+c) and launch the serve comand again (I don't remember if I also do another npm install but I think that's not necessary).

fsgreco avatar Jan 31 '24 11:01 fsgreco

I faced a similar problem and got it resolved by adding the following configuration to the .npmrc file, at the root of my project:

link-workspace-packages=false

By doing so, packages are downloaded and installed from the registry. It seems to be a bug related to Vite and how PNPM workspaces link their inner packages in a monorepo. You'll also need to update your inner dependencies on package.json to the latest version of each package - if you are using "workspace:*" as dependency reference.

josantana avatar Mar 27 '24 21:03 josantana

@fsgreco Wow this saved me. Thank you for putting the effort into this. The step-by-step reproduction you provided in the repo was super helpful.

It's a little weird to me that we would need to rename the library aliases so that they don't match the path but so long as it works I guess.

dbehmoaras avatar Mar 30 '24 14:03 dbehmoaras

@fsgreco Wow this saved me. Thank you for putting the effort into this. The step-by-step reproduction you provided in the repo was super helpful.

It's a little weird to me that we would need to rename the library aliases so that they don't match the path but so long as it works I guess.

Glad it helped you :) indeed I take me a lot of try and error to understand what was happening. However I consider this just a workaround. Unfortunately the bug persists, and it has to do with how nxViteTsPaths works under the hood. It doesn't happened with vite-tsconfig-paths.

fsgreco avatar Mar 30 '24 14:03 fsgreco

This also happens with build / swc; making sure the package.json name and config alias are different solves it.

for reference, it does not solve issues with temporal.io webpack bundle.

mrsufgi avatar Apr 29 '24 20:04 mrsufgi

I also have this issue. It's extremely frustrating. Unfortunately, I can't use any of the work arounds here because I need to publish both the Core Library and the Library that consumes the Core Library for public consumption. Changing the alias would break my naming conventions for my module imports.

@Coly010 Are there any updates on when this issue may be addressed and the nxViteTsPaths can be fixed?

brianlagunas avatar Jun 20 '24 17:06 brianlagunas

I'm also having this issue, with a package based monorepo using vite and vitest.

I continually get Error: Failed to resolve entry for package "@ai-dev/comm". The package may have incorrect main/module/exports specified in its package.json.

When running vitest via nx test I also get this warning:

> vitest

The CJS build of Vite's Node API is deprecated. See https://vitejs.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.
 Vitest  "cache.dir" is deprecated, use Vite's "cacheDir" instead if you want to change the cache director. Note caches will be written to "cacheDir/vitest"

I had an issue where things were working fine, then I copied in a package from another monorepo using the same exact configuration and I started getting errors. After I completely removed this package the problem persisted, even with the exact same files as before when it worked, so I reckon it could also be due to the NX workspace caching getting messed up ant not resetting!?

kristianmandrup avatar Jul 02 '24 07:07 kristianmandrup

I've migrated your reproduction repo to latest (19.5.3), and it works now :) Similarly when creating the repo from scratch.

Coly010 avatar Jul 26 '24 14:07 Coly010

@Coly010 do you happen to have a repository? I just tried to recreate everything from scratch and it's still not working :/

I follow my own procedure, the only change I've done: step 3 is not needed any more since with --preset=npm now Nx creates the folder packages for you. Then on step 5 and 6 i choose "derived"

fsgreco avatar Jul 30 '24 13:07 fsgreco