npm / cli

the package manager for JavaScript
https://docs.npmjs.com/cli/
Other
8.36k stars 3.09k forks source link

[FEATURE REQUEST] workspaces: Configure directory which is linked during installation #6614

Open nioe opened 1 year ago

nioe commented 1 year ago

Simplyfied I've got the following project structure:

workspace/
├─ package.json                  <-- With npm workspaces (see below)
├─ packages/
│  ├─ angular/                   <-- Angular Workspace
│  │  ├─ projects/
│  │  │  ├─ a/                   <-- Angular Library A Source
│  │  │  │  ├─ package.json
│  │  │  ├─ b/                   <-- Angular Library B Source
│  │  │  │  ├─ package.json
│  │  ├─ dist/
│  │  │  ├─ a/                   <-- Built Angular Library A
│  │  │  ├─ b/                   <-- Built Angular Library B
│  ├─ webcomponents/             <-- Stencil.js Webcomponents
│  │  ├─ package.json
│  │  ├─ dist/
│  ├─ demo-app/                  <-- This package depends on all of the above
|  │  ├─ package.json/

In the root package.json I've got the following workspaces config:

"workspaces": [
  "packages/*",
  "packages/angular/projects/*"
]

When I run npm install all dependecies are installed and local packages are linked as expected. The problem is, that Angular builds libraries by default within a dist folder outside of the actual workspace and creates a new package.json in it. So this directory is meant to be packed and published.

In the demo-app however, the source folders of the Angular libraries are linked, since this is configured in the workspaces of course. I haven't found any hint on how I can tell npm to link another directory then the actual workspace.

I used to use Lerna before and it respected the publishConfig.directory setting within the package's package.json for linking.

So my request would be that npm either respects this property as well or finds another way to configure a different directory to link duing the install phase.

ljharb commented 1 year ago

Angular can’t be configured to do what everyone else does, and build in-place?

nioe commented 1 year ago

As far as I understood, I could move the dist folder in my src folder. But since it generates a new package.json this wouldn't do the trick IMHO.

nioe commented 1 year ago

Any ideas or thoughts?

statyan commented 9 months ago

So I managed to make it work but that's not a simple way. Main points are:

  1. each package json has to have "main", "module", "typings" which will point to a file in ./dist/.. folder. I created a custom ts script to update these props in a corresponding package.json after build. (ng-packagr will not allow you to use conditional exports, of course you can have it but clean before build instead)
  2. if you have secondary entry point and don't go with conditional exports (in my case I had issues with Karma resolver which didn't pick new conditional exports) then it's a must to have package.json in each secondary entry point with same properties, pointing to dist (good news it's pretty easy to parse dist/package.json conditional exports to pick the right properties and paths)
  3. At this point you would have a buildable application which will bundle libs from corresponding dists.
  4. However if you're thinking about development with app running on hot module replacement - there is a catch. Naive approach is to run library build in watch mode and app in watch mode so it would recompile whenever library recompiles. But at least in Ag14 you have to start lib watch first then app, if you stop the lib or want to start another one - you must start them in the order they depend on each other. If you don't follow it - compiler at some point fails with "Can't resolve module ..." error and corrupts angular cache, so even if you stop everything and start again - you'll still have that error until you clean up the cache.
  5. So because of that for better dev experience for the app I used the good old method with declaring "paths" in tsconfig, so libraries are picked from sources and you basically run only the app. However webpack resolver "sees" the "main" property pointing to dist and ignores tsconfig paths (processed by angular plugin) so I ended up with patching webpack configuration, adding a custom "tsEntry" to resolver.mainFields array and added this prop in every library, pointing it to index.ts. And I also had to put all the libs into resolver.alias configuration to allow application to start even if no dist folders yet created in libs. That did the trick. I even can use "tsEntry" property now to generate ts paths, which is pretty convenient. Hope that helps.
nioe commented 8 months ago

Hi @statyan Sorry for the late response and thank you for the detailed answer. I'll give that a try. But I still think that npm should support setting the directory which is linked, in a more easy way.