You have two approaches of going about inserting dependency packages into your Angular library (package.json file) and both will work fine:
- "dependencies" (the library will bring this package in when you install the library)
- "peerDependencies" (When you add your library into the consuming project, you will be warned that you have to install this peer dependency yourself in your consuming project)
Which one is the best?
Short answer
The second one.
Long Answer
The second option is best and advised by Angular CLI even when you have packages defined in dependencies instead of peerDependencies. Here is the warning message Angular CLI (at least if you have a newer version of Angular - I have 12.x at the time of writing this) will show in the console when building: "Distributing npm packages with 'dependencies' is not recommended. Please consider adding to 'peerDependencies' or remove it from 'dependencies'."
However, there are a few differences and trade-offs between both of them and it is really up to you to decide which fits you most, but I am definitely going for the second option.
Approach 1 - dependencies
will simplify the setup in the consuming app as you will not see any warning about the peer dependency and you will not need to install the dependency manually. The issue you might have with this approach is that you may have version conflicts in the consuming app in case you already are using the same package in your consuming app. Let's say there is another package you have installed that uses the same peer dependency but in a different version. This approach also brings in performance concerns.
Approach 2 - peerDependencies
The second approach is probably the best of the two as all you need to do is to add the package in the peerDependencies and then when the library is installed in the consuming project, you will get a nice warning that you need to install the peer dependency manually. This approach feels a better practice in general as your application grows. Yes, you will get the warnings on library install, but you want to have as much control as possible over what versions of peer dependencies are installed in your consuming apps in the long run. Also you want to have small packages installed in your consuming app. This option is definitely safer and is the one I go for.
Here's a useful blog that also mentions this topic
https://tomastrajan.medium.com/the-best-way-to-architect-your-angular-libraries-87959301d3d3
Interesting bonus fact
While I was learning about dependencies in Angular libraries, I have also discovered that when you go for option #2 above (peerDependencies), this does not necessarily mean that you will not need to have the dependencies in accessible in the library, otherwise Typescript will complain that it cannot find types.
Say you use are building your library in watch mode
ng build <name of library> --watch
This means that if you do not have the dependency packages installed (in the workspace where your library project files are) in the node_modules folder, Typescript will complain and build will fail. So, what to do in this case? Well, for me, the solution was to also add the required dependencies needed for the library to be built in devDependencies as well. Here is what I mean. This is my library package.json file at the time of writing this:
"name": "@alexrebula/ngx-giselle-ui",
"version": "0.0.8",
"peerDependencies": {
"@angular/common": "^12.2.0",
"@angular/core": "^12.2.0",
"bulma": "^0.9.3",
"@fortawesome/angular-fontawesome": "^0.8.2",
"@fortawesome/fontawesome-free": "^5.15.4",
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-brands-svg-icons": "^5.15.2",
"@fortawesome/free-regular-svg-icons": "^5.15.2",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
"@googlemaps/markerclustererplus": "^1.2.0",
"googlemaps-ts-rich-marker": "0.0.4"
},
"dependencies": {
"tslib": "^2.3.0"
},
"devDependencies": {
"@types/googlemaps": "^3.43.3",
"@fortawesome/angular-fontawesome": "^0.8.2",
"@fortawesome/fontawesome-free": "^5.15.4",
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-brands-svg-icons": "^5.15.2",
"@fortawesome/free-regular-svg-icons": "^5.15.2",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
"@googlemaps/markerclustererplus": "^1.2.0",
"googlemaps-ts-rich-marker": "0.0.4"
}
See how I've literally duplicated the peerDependencies in devDepencencies? Except for Bulma (a CSS framework) of course, because not having CSS will not break the library compilation, I just need to install Bulma in the consuming app.
Credits and contribution
In case you would like to try out this study case, see te code or even collaborate with me on this learning path, I suggest you head on to https://www.npmjs.com/package/@alexrebula/ngx-giselle-ui and https://github.com/AlexRebula/GiselleUI. Any comment or feedback on what I wrote or did in my library would be great appreciated, especially if you think I have made a mistake somewhere along my discovery path. Thank you!