Reputation: 857
I have two angular library NPM packages:
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:
npm link --only=production
in (the built version of) A
npm link --only=production
in (the built version of) A-BC
my-app
, run npm link A
my-app
, run npm link A-BC
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:
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
. 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:
A
as a beta versionA-BC
and my-app
A-BC
to my-app
via npm link
A
if changes need to be made, then install that in my-app
and A-BC
againThere may be an alternative workflow around installing A
via NPM's support for local files, but I'm not sure.
Upvotes: 6
Views: 4374
Reputation: 857
What I was trying to do initially had a lot of problems because the scenario was wrong to begin with.
The main two things I learned here were that:
If you are trying to make the scenario I described work, it will give you an endless headache because it is a fundamentally broken approach.
Now all of the related projects that share these libraries are in a single nx monorepo. With the libraries being directly imported, everything just works automatically with live reloading, tree shaking, etc, as other answers/comments here suggested. Migrating was not much of a hassle, and the tooling for the monorepo setup is pretty good.
When setting up your monorepo to make this scenario work, the libraries will be imported to each project via tsconfig paths, as below. This makes the old import statements for the npm packages able to stay the same, as your paths can just reference the name of the previous npm package (like A or A-BC in the question above).
Every project also now shares the same package json, and the npm scripts for serving, building, etc have been greatly improved by centralizing these tooling scripts in the monorepo root, instead of having tooling separately in each repo.
The path for @angular/*
fixed some issues with the libraries conflicting.
Example paths from /apps/example-project/tsconfig.json
"paths": {
"@angular/*": ["../node_modules/@angular/*"],
"@exampleNPMOrg/A": [
"../../libs/A/src/index"
],
"@exampleNPMOrg/A-BC": [
"../../libs/A-BC/src/index"
],
}
Example paths from /tsconfig.json
"paths": {
"@exampleNPMOrg/A": [
"libs/A/src/index"
],
"@exampleNPMOrg/A-BC": [
"libs/A-BC/src/index"
],
}
Upvotes: 1
Reputation: 3588
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.
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.
Upvotes: 4