NX : Library types

NX : Library types

ยท

4 min read

Understanding libraries types

Hello friends ๐Ÿš€! As we saw in the previous article, one of NX's core features is the ability to create libraries. These libraries can be categorized into different types, each serving a unique purpose and playing a specific role in your project. Understanding these library types is crucial for organizing your codebase efficiently and making the most of NX's powerful capabilities. Even without NX, it's a good idea to separate your codebase into libraries. NX helps you leverage all of these benefits.

Feature library

Feature libraries encapsulate a specific feature or functionality within your application. They are designed to be reusable and can be imported into multiple applications as a feature. The feature library will include everything you need to create a functionality. It can import all other types of libraries to build it. It can also import other feature libraries to create a larger one.

Example : You could create a weather widget that you want to display in multiples of your application

So you will create a grouping folder named weather-widget and generate your library

weather-widget/feature -> your feature

We will see what you can import on this library and why below

Ui library

UI libraries focus on providing reusable, simple UI components. These components are generally presentational and do not contain any business logic. By centralizing your UI components in libraries, you ensure consistency across your application and make it easier to update and maintain your UI. UI libraries can import utility libraries and other UI libraries, but they cannot import feature libraries or data-access libraries. A dumb component cannot contain an entire feature or a service to manage your application's data. It makes sense.

Example : For your weather-widget you will need to create a dumb component that will take some inputs coming from the back-end, and display the actual weather in a nice way.

weather-widget/feature -> your feature

weather-widget/ui -> the dumb component stuff for your feature

Data-access library

Data access libraries handle interactions with external data sources, such as APIs or databases. They encapsulate the logic for making HTTP requests, handling data transformations, and managing state related to data access. This separation helps keep your feature libraries clean and focused on their specific responsibilities. Since you need to expose your interface in other libraries, you should store the interface linked to your service in another type: util. You can import both data-access and util types into data-access.

Example : For your weather-widget you will need to create a service so your feature will be able to get the current weather data and display it with it's dumb component

weather-widget/feature -> your functionnality

weather-widget/ui -> the dumb component stuff for your feature

weather-widget/data-access -> the service to get the data for your feature

Util library

As explained above, sometimes you will need to make imports that aren't possible without a type that doesn't depend on others. The Util library exists for this reason. Util(ity) libraries are collections of reusable types, interfaces, helper functions, pipes, and other utilities that can be used throughout your application. This library can be imported by any other existing types because it only depends on other util libraries.

Example : For your weather-widget you will need to create an interface for the data so you can use this interface in : feature for the input, ui to structure your dumb component, and in data-access to correctly type the object coming from the back-end.

weather-widget/feature -> your functionnality

weather-widget/ui -> the dumb component stuff for your feature

weather-widget/data-access -> the service to get the data for your feature

weather-widget/util -> the interface for the data for your data-access

Shell library

In NX, a "shell" library refers to a routing library that exposes routes, allowing it to be imported into multiple applications seamlessly. This type of library is particularly useful in a microfrontend architecture or in scenarios where you want to share a common routing configuration across several applications.

Overview

Can I create other types ?

Of course you can create as much types as you need, a good practice is trying to keep the number of them low. Because it can be hard to understand or you will need to document it clearly so every new member of your team can understand the goal of each types.

Example : You could create state libraries to separate data-access services and state management in your application. This way, feature libraries wouldn't depend directly on data-access services. You could also add a facade library so that features wouldn't depend on state libraries directly. Instead, the facade would depend only on state libraries.

In next article we will see how to enforce these rules with ESLint and NX.

Ressources

https://nx.dev/concepts/decisions/project-dependency-rules

https://ng-journal.com/blog/2022-12-19-the-enterprise-monorepo-angular-patterns/