Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I locally develop Angular 7 libraries that depend on each other? (npm link issues)

I have two angular library NPM packages:

  • A has basic components
  • A-BC has components that build upon the components in A, with added features to integrate with BC library

Some components in A-BC import from A like import { MyThing } from 'A';

A-BC's package.json is:

"peerDependencies": {
   "A": 1.0.0,
   "BC": 4.0.0
},
"devDependencies": {
   "A": 1.0.0,
   "BC": 4.0.0
}

My attempted development steps were to:

  1. npm link --only=production in (the built version of) A
  2. npm link --only=production in (the built version of) A-BC
  3. In my-app, run npm link A
  4. In my-app, run npm link A-BC
  5. Run my-app

Compilation of my-app fails when A-BC can't find A installed anywhere. They are both listed correctly in node_modules right next to each other, as symlinked folders. I have tried this with preserveSymlinks enabled in tsconfig.json and angular.json, but that did not help.

A could be a direct dependency of A-BC, but:

  • Both A and A-BC have a forRoot() called that is required for the package to function properly for the app it is installed in. I don't know of a way to pass the forRoot() parameters dynamically from the A-BC forRoot() to the A forRoot()
  • my-app needs to use components from A AND components from A-BC.
  • If A was a direct dependency, I don't know how I would be able to develop A-BC locally--which can involve changing both A-BC and occasionally A.

Currently my band-aid solution is to:

  1. Publish A as a beta version
  2. Install the beta version in A-BC and my-app
  3. Link A-BC to my-app via npm link
  4. Publish a new beta version of A if changes need to be made, then install that in my-app and A-BC again

There may be an alternative workflow around installing A via NPM's support for local files, but I'm not sure.

like image 448
Paul Avatar asked Jul 10 '19 14:07

Paul


1 Answers

I assume that those two packages that you are talking about were created either with ngCli v6, or you are merging them from already existing ng workspaces, either way let's try to solve your problem.

I will assume that you have ng workspace structure like the following one

...
projects >
  A
  B
  host
...

Where A is a lib B is a lib which depends on A and host is an application that uses B.

When working/developing ng packages locally in your ng workspace, you should add their aliases to your root tsconfig.json file like :

{
 ...
"compilerOptions": {
    ...
    "paths": {
      "a": [
        "dist/a"
      ],
      "a/*": [
        "dist/a/*"
      ],
      "b": [
        "dist/b"
      ],
      "b/*": [
        "dist/b/*"
      ]
    }
  }
}

This is done automatically for you in the CLI v7 when generating a library with ng new lib {yourLibName} command.

After making sure that you have this configuration I would suggest adding some scripts to your package.json, in order to build your libs and serve your development app in more straightforward way (host in the case of the example)

"build:a": "ng build A --watch=true",
"build:b": "ng build B --watch=true",
"serve:host": "ng serve host"

After that, by running the three scripts one after another and importing the appropriate libModules from lib B in your Host App and the appropriate libModules from lib A inside Lib B, you will be able to use the components of lib B, which depend on components from lib A inside the Host APP.

Keep in mind that you must not install the two libs in your workspace, because that will break the imports inside your projects, also those libs should not be part of your workspace package.json.

If you had already completed the above steps and your problem is not fixed, please provide us with link to a git repo, or share your tsconfig.json, package.json, angular.json files, so that we can continue with the investigation.

Answer to sub comment

So if I get your case, you want to be able to develop those packages and also install them in one single ng workspace.

If this is the case, as far as I know, there is no straight forward way to do it, probably you will be able to achieve this behavior (as you suggested in the comment) by tweaking your tsconfig.json files.

But in my opinion, if you want to use this ng packages inside the same workspace, you don't necessarily need to push them, as at the end of the day they are just another set of ngModules that will be "first-class citizens" inside the applications where you reffer them. So when building for production, they will be tree-shaken, minimized-optimized and so on. In this case, you should just extend the deployment script in your package.json, in such way, that before you start building the main app, that will depend on those npm/ng/packages, you build that packages.

"deploy": "ng build A && ng build B && ng build MainApp --production"

At the same time, those same npm/ng/packages will still be npm publishable and you will be able to use them in other workspaces. Keep in mind that they should not be part of the same(the workspace where they are being developed) workspace's package.json dependencies.

like image 191
Християн Христов Avatar answered Sep 17 '22 16:09

Християн Христов