Closed dereklin closed 5 years ago
I'm not on the Nrwl team; but I think this is actually not a Nx specific question, rather I think it applies quite generally to Angular regardless of the tool you use to manage development of many related applications or libraries.
I believe the generally accepted approach is that you should think of the NgModule as the default unit of modularity, of reuse, etc. of Angular-related code. If you have code sitting in a library that is not a NgModule, then consuming it requires that the consuming code package it into a NgModule, and this of course is fraught with difficulty as the same code could end up double packaged and so on. That's not to say there isn't some use case somewhere where it makes sense to directly expose the code for a Component or similar; just assume that the NgModule is the right way to go until strong evidence arrives otherwise.
When I wrote the original post I used the term module but was really thinking of NgModule. I am going to update it.
It's trivial to put a function or a group of functions as a javascript module nowadays (http://2ality.com/2014/09/es6-modules-final.html)
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
In the above example, lib.js could be named math.js or the math module.
But does it have to be turned into a NgModule inside the libs folder?
Oh yes, that is what I meant also; and I will also edit mind to be clear that I mean NgModule. If you have some block of code to reuse in an Angular context, that has any Angular contents (components, services for, really anything at all) then the default way to package it should be as a NgModule. If you have instead a block of TypeScript code which has no Angular connection at all, then certainly don't add NgModule to it; just package it up as any Node library would have been packaged even if you never heard of Angular.
@kylecordes I think if the topic is not nx related, then using NgModule is definitely the way to go for most cases.
One selling point of nx is that the libs are meant to be internal. So apps can provide services inside of the libs, and they can use components inside libs. And having these small units in libs will make them very reuseable. So that is a legitimate use case.
However, for a more long term view, it's probably more robust to create NgModule wrappers for these small units so that if need be, one can package and deploy the small NgModules to npm for version control and so forth. Furthermore, the Angular compiler can compile NgModules in parallel so there is actual performance gain in compilation (Rob Wormald told me about this the other day)
Now, for things like the MathUtils example:
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
I don't see how to put it inside an NgModule. How do you do this in your real project?
@dereklin That bit of utility example doesn't do anything with Angular; there is no reason to put it in an NgModule. It has no state, and doesn't need to be injected with DI. It can simply be used as a plain JS library. It can sit in a Nx managed library directory, it could be published to NPM, etc. without any Angular awareness.
Viktor actually recommends to put 99% percent of your code in libs. https://youtu.be/qYNiOKDno_I?t=6m35s
@dereklin what is the best practice for moving a lib out of Nx and publish to NPM?
@playground I am not him, and I don't know about "best practice", but practically speaking it is quite easy to add a package.json file to a lib/whatever directory in a Nx project, and put whatever you need in there to publish the library. Peer dependencies on Angular libraries, ng-packagr to do the bundling very easily.
@kylecordes yes, I'm aware of generator-angular2-library and ng-packagr community packaging tools. I was thinking there might be built-in command with Nx to convert the lib to npm module :-)
Agree with @kylecordes I followed this project: https://github.com/dherges/nx-packaged
Just watched James Henry's talk on ngVikings youtube channel: https://www.youtube.com/watch?v=bMkKz8AedHc
He gave this code structure example:
And at 20:30 he talked about the practice of putting non-reusable app specific module in the libs folder.
This rocks my understanding of nx a little bit. What are the benefits of putting an app specific module that's not reusable in libs? What's preventing from other apps importing from the app specific modules?
Another thing, the common-ui module could get really big. This reminds me of when Angular Material first came out, everything was in a single module, and then it was split up into smaller modules to take advantage of treeshaking. Am I missing anything obvious?
@dereklin I agree...seems an odd recommendation given the focus on bundle size, componentization, and lazy loading. Given reuse considerations (and that xplat is probably coming), I've been separating out my UI (splitting web from amp from ...) from non-UI elements (splitting these into core and admin) at the major feature level. Makes for a lot of libraries under each directory!
Had a followup question about any best practices for reusing selectors, reducers, etc (my use case is an admin module that has more functionality than the core module, so reuses selectors but needs to extend the State elements within the feature). Should we put the StoreModule and EffectsModule, for example, in the app or the lib?
StoreModule.forFeature('feature', reducers)
@dereklin i guess putting even non-reusable code into libs makes totally sense when you see your apps as "build targets", libs define your app-functionality, but you need a different (app-) boilerplate, configuration, whatever, if you want to build the same app-functionality for electron or cordova.
I think it's getting better with the documentation, well done. The libs is now slightly described in the new docs, but something like "best practices" would be appreciated as well I guess.
As @danieldanielecki mentioned it, we are approaching this issue in our new documentation website, as well as in our book explaining all the concepts around Nx.
Closing the issue.
I think the examples and best practices can be further improved. As a newbie evaluating Nx it's very confusing to comprehend what goes where. All examples are pretty trivial. I wish there were more advanced examples for organizing full stack enterprise code, e.g. multiple backends, multiple libs, etc. The "Hello World" type of examples are just not enough.
This is still very much needed.
I can only agree with your opinion. In 2021, the documentation on workspace structure is still very superficial. It is such a key thing to consider, but sadly not well enough documented.. I found this article very useful for my needings: https://blog.strongbrew.io/opinionated-guidelines-for-large-nx-angular-projects/
@KonstantinSchuette Manfred Steyer has also written a (I think free) book on Angular Enterprise where he describes how to use Domain Driven Design principles with Nx: https://www.angulararchitects.io/book/
Also if you search on Google, there are lots of talks where he in particular goes into those details a bit.
We are still missing guidelines for organizing backend projects (NestJS). Seems like most of the docs are focused on the Angular frontends.
Still don't get why i have to store 99% of code in libs even though it's only app-specific logic. What's the point? And according to new docs i have to store Domain-specific shared libs at root-level Shared scope. Don't get it as well. Why i need app-specific lib folder then? As far as i understood the app-specific scope (at high level of libs folder) is the place where you store logic that belongs for all particular apps. So shared app-specific scope then for me it's kinda contradictional stuff
Still don't get why i have to store 99% of code in libs even though it's only app-specific logic. What's the point? And according to new docs i have to store Domain-specific shared libs at root-level Shared scope. Don't get it as well. Why i need app-specific lib folder then? As far as i understood the app-specific scope (at high level of libs folder) is the place where you store logic that belongs for all particular apps. So shared app-specific scope then for me it's kinda contradictional stuff
Took me a while to understand too, but a friend explained to me that app-routing-module.ts
is the only thing dictating what page
loads in what app
. So ALL pages are in /libs but only few are accessible. If that makes sense
This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.
I am hoping to get some insight from the nrwl team on what are the best practices on the usage of the libs. Would you recommend putting only Modules (I mean NgModules) (all code should live inside of a module) inside the libs? Or it's ok to put services without modules (NgModules) and other smaller units without modules (NgModules) such as:
Models Interfaces InjectionTokens Utils etc.