Dependencies in Angular monorepo

I recently created a monorepo housing three libraries: lib1, lib2, and lib3. The structure is designed such that lib3 depends on lib1 and lib2.

https://i.sstatic.net/5xrqf.png

My goal is to establish local references to lib1 and lib2 within lib3.

Traditionally, I would publish lib1 and lib2 to an npm registry and then update the dependencies in lib3 accordingly to ensure an up-to-date version of lib3. This is reflected in the package.json files as follows:

packages/package.json

{
  "name": "packages",
  "scripts": {
    "build-lib1": "ng build lib1",
    "build-lib2": "ng build lib2",
    "build-lib3": "ng build lib3"
  },
  "private": true,
  "dependencies": {
    "lib1": "1.0.0",
    "lib2": "1.0.0",
    ...
  },
  "devDependencies": {
    ...
  }
}

packages/lib1/package.json

{
  "name": "lib1",
  "peerDependencies": {
    ...
  },
  "dependencies": {
    "tslib": "^2.4.0"
  }
}

packages/lib2/package.json

{
  "name": "lib2",
  "peerDependencies": {
    ...
  },
  "dependencies": {
    "tslib": "^2.4.0"
  }
}

packages/lib3/package.json

{
  "name": "lib3",
  "peerDependencies": {
    ...
  },
  "dependencies": {
    "tslib": "^2.4.0",
    "lib1": "1.0.0",
    "lib2": "1.0.0"
  }
}

In this setup, lib1 and lib2 are added as dependencies in lib3, not peerDependencies, to ensure their automatic inclusion as transitive dependencies when installing lib3 in another application. To accomplish this, I needed to include lib and lib2 in allowedNonPeerDependencies within packages/lib3/ng-package.json.

The versions of these libraries are controlled by a CI pipeline and are tied to the git tag of the repository. However, this can result in different versions for lib1/lib2 and lib3. For example, if I publish v1.0.0 for lib1 and lib2, and then update the dependencies in the project, lib3 may end up with v1.0.1.

For context, the versions being used are:

  • Angular 15
  • Typescript 4.8.3
  • npm 9.2.0

My current aim is to find a way to directly reference lib1 and lib2 within lib3 without sacrificing the transitive dependency functionality.

What is considered the best approach to achieve this objective? I've looked into npm workspaces and project references in TypeScript but have hit a roadblock and am unsure of the next steps.

Answer №1

If you're looking to streamline your Angular development process, consider exploring the benefits of setting up an nx workspace. You can find more information on how to get started with nx at .

While it is possible to work solely with Angular, using nx can provide solutions to various challenges:

  • Easily manage local library references.
  • Make libraries buildable.
  • Handle library dependencies automatically.
  • Avoid the need for complex build scripts.

On top of these benefits, nx also offers:

  • A visual representation of library dependencies in a graph format.
  • Caching capabilities for common tasks like building and linting.

If you decide to adopt nx for your projects, consider using the Nx Console extensions for VS Code or WebStorm to simplify tasks like generating libraries. Additionally, I highly recommend checking out the ebook Enterprise Angular Monorepo Patterns, written by one of the library authors and endorsed by the NgRx library that utilizes Nx.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Troubleshooting a pair of distinct software programs: Angular and a web API

I am currently working on two separate applications, one developed in Angular and the other in web API. There is a function in my Angular application that calls a method in .NET Core. I would like to know if it is possible to debug the Angular function and ...

What strategies can be implemented to restrict certain users from accessing specific components by manually altering the URL in Angular 2?

I am currently using Angular 2 to create a data table for displaying information. I have implemented a click event that redirects users to '/viewOutgoing;id=data_id', with the id corresponding to the data's id in the table. However, I need t ...

In fact, retrieve the file from an S3 bucket and save it to your local

I've been attempting to retrieve an s3 file from my bucket using this function: async Export() { const myKey = '...key...' const mySecret = '...secret...' AWS.config.update( { accessKeyId: myKey, secretAcces ...

Mandatory classification eliminates understanding of function type

I'm currently trying to transform an optional argument from one type into a required one in my type definition. However, I am encountering some difficulties and can't seem to figure out what I'm doing wrong in the process. Would appreciate a ...

Calculating the total of all values in a table

For my ngFor loop, the invoice total is calculated based on price and hours, but I also want to calculate the totals of all invoices in the end. <tr *ngFor="let invoice of invoiceItem.rows"> <td>{{ invoice.rowName }}</td> <td& ...

Is there a way to find the recursive key types in TypeScript?

Is there a method to ensure that code like this can compile while maintaining type safety? type ComplexObject = { primitive1: boolean; complex: { primitive2: string; primitive3: boolean; } }; interface MyReference { myKey: keyof ComplexObj ...

Is it possible to turn off Angular CLI ng build linting for a specific directory?

I am facing an issue with a specific directory in my project template that I want to exclude from linting. Despite excluding it in both tsconfig and eslint, running eslint works fine but when using ng build, the directory is still included in linting and e ...

Does an AsyncMethod().Result equivalent exist in typescript?

When working in C#, you have the ability to call the result of an asynchronous method synchronously by accessing the Result property. For example: var returnVal = AsyncMethod().Result; What is a similar approach in typescript? ...

Is there a way to merge two typed Joi schemas together?

I have two different interfaces, where the second one is an extension of the first: interface Core { id: string; } interface User extends Core { firstName: string; } To ensure validation, I utilize Joi schemas. For the Core interface, it's easy ...

Develop a new traceur compiler using brew and then proceed to globally install npm

My goal is to create a custom homebrew formula that relies on the installation of npm modules. I've noticed that homebrew handles npm as an external dependency, so I need to download and build the traceur-compiler. The formula structure I'm work ...

Why isn't my NPM package functioning properly within the Laravel framework?

I recently developed an npm package for my personal use, but encountered a ReferenceError when attempting to utilize it in a Laravel project. Here's the breakdown of what I did: I followed a tutorial on initializing an npm package, and it functioned p ...

Having trouble locating a module? I've developed a simple React NPM package, but encountered an issue with the message "Module Not Found."

I recently developed a React npm package using the npx create-react-app command as instructed in the geeksforgeeks-create-react-npm-package guide. However, upon publishing it, I encountered an error. Link to npm repository: k-k-react-header-package import ...

Is it feasible to distribute logic across Components?

My components all serve the same purpose: They display a form (with varying HTML) Capture the form data Validate and send the form using a REST API I am trying to find a way to share common elements among these components. For instance, each form includ ...

Vue's computed property utilizing typed variables

I am trying to create a computed array of type Todo[], but I keep encountering this specific error: No overload matches this call. Overload 1 of 2, '(getter: ComputedGetter<Todo[]>, debugOptions?: DebuggerOptions | undefined): ComputedRef<T ...

Utilizing ElementRef in Angular 4 to close dropdown when clicking outside of it

I recently came across this helpful tutorial, but I'm having trouble grasping how it actually functions. Here's the code snippet I've incorporated into my TypeScript file: @Component({ host: { '(document:click)': 'onOuts ...

How can I create a custom validator in Angular 2 that trims the input fields?

As a newcomer to Angular, I am looking to create a custom validator that can trim the input field of a model-driven approach form. However, I have encountered difficulties during implementation. When attempting to set the value using setValue() within th ...

Is implementing client components in Server Side pages an effective strategy for optimizing SSR performance?

In order to overcome the challenge of using client-side components in server-side pages, I made the decision to create a client-side wrapper to encapsulate these components within server-side pages. This way, I can manage all API calls and data fetching on ...

Is it possible to define a data type from an external package using TypeScript and Node.js?

I'm currently in the process of reorganizing some code to utilize a list of signals and connect `.once` handlers to each one individually. const terminationSignals = ["SIGINT", "SIGUSR2", "SIGTERM"]; terminationSignals.f ...

Obtain the value of a template variable in Angular 2

I am seeking information on how to access the values of selected items in templates. Specifically, I want to understand how to retrieve the selected value of IPMIDisplayTime and IPMIDisplayTime within the template for later use. import {ViewChild, Elem ...

Issue: Module 'number-is-nan' not found

While developing a react native app with expo-cli, I successfully implemented two UI buttons that trigger redux actions to update a date label on the UI. However, out of nowhere, when running 'expo start' in the terminal, I encountered the follow ...