skip to Main Content

I’m using Angular 18 and trying to import a component(app1/reusable.component.ts) from one project into another one(app2).

And then, I want the component to import its dependencies from the project folder where it itself has been imported into (app2/node_modules) instead of the folder where it is located.

My folder structure looks something like the following:

root
├──app1
│  ├──...
│  ├──node_modules
│  ├──src
│  │  ├──...
│  │  ├──app
│  │  │  ├──...
│  │  │  ├──reusable.component.ts
│  
├──app2
│  ├──...
│  ├──node_modules
│  ├──src
│  │  ├──...
│  │  ├──app
│  │  │  ├──...
│  │  │  ├──app.component.ts

Where the relevant component files are:

// app1/src/app/reusable.component.ts

import { Component } from '@angular/core'; // this is an example of dependency that needs to be imported of app2/node_modu;es

@Component({
  selector: 'reusable-component',
  standalone: true,
  template: 'Reusable Component',
})
export class ReusableAppComponent {
  title = 'ReusableAppComponent';
}

and

// app2/src/app/app.component.ts

import { Component } from '@angular/core';
import { ReusableAppComponent } from '../../../app1/src/app/reusable.app.component'

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ReusableAppComponent],
  template: '<reusable-component></reusable-component>',
})
export class AppComponent {
  title = 'app2';
}

What I have tried so far. And steps to reproduce.

Setup: initialized app1 and app2 with ng new and removed app1/node_modules.

Then, assuming I could pull this off with paths option in tsconfig,
I’ve Modified the compilerOptions in app2/tsconfig.json by adding

    "baseUrl": "./",
    "paths": {
      "@angular/core": ["node_modules/@angular/core"],
      "tslib": ["node_modules/tslib"]
    }

As a result at runtime I see both ReusableComponent and Component from @angular/core get imported, however an error in the console appears:

ERROR RuntimeError: NG0203: inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.dev/errors/NG0203
    at injectInjectorOnly (main.js:650:11)
    at ɵɵinject (main.js:660:59)
    at Object.factory (main.js:14888:45)
    at chunk-IMMNNYUP.js?v=a145dfc3:1965:35
    at runInInjectorProfilerContext (chunk-IMMNNYUP.js?v=a145dfc3:567:5)
    at R3Injector.hydrate (chunk-IMMNNYUP.js?v=a145dfc3:1964:11)
    at R3Injector.get (chunk-IMMNNYUP.js?v=a145dfc3:1854:23)
    at definition.getStandaloneInjector (main.js:14895:27)
    at ComponentFactory.create (chunk-IMMNNYUP.js?v=a145dfc3:9692:53)
    at _ApplicationRef.bootstrap (chunk-IMMNNYUP.js?v=a145dfc3:18388:38)

2

Answers


  1. Maybe you should have a look at this section in the official Angular documentation about multiple projects.

    It allows you to have a repository with one common node_modules folder and several projects where you can even import in between projects. In the documentation they also explain that one of the projects could serve as a library with common pipes, components, etc. So you could move common components to the library and use them in different projects.

    There is an additional section in the documentation that deals with creating libraries here.

    In your example the folder tree would look something like that:

    root
    ├──node_modules
    ├──projects
    │  ├──app1
    │  │  ├──...
    │  │  ├──src
    │  │  │  ├──...
    │  │  │  ├──app
    │  │  │  │  ├──...
    │  │  │  │  ├──reusable.component.ts
    │  │  ├──tsconfig.app.json
    │  │
    │  ├──app2
    │  │  ├──...
    │  │  ├──src
    │  │  │  ├──...
    │  │  │  ├──app
    │  │  │  │  ├──...
    │  │  │  │  ├──app.component.ts
    │  │  ├──tsconfig.app.json
    │
    ├──angular.json
    ├──tsconfig.json
    

    There is a common tsconfig.json and specific configs for the apps where you can define app specific aliases for namespaces.

    If necessary you could even make an alias from one to another project:

    • for example in the tsconfig.app.json for app1:

      "@app2/*": ["../../app2/src/app/*"],

    • and in the tsconfig.app.json for app2:

      "@app1/*": ["../../app1/src/app/*"],

    Now you can import as follows:

    import { ReusableAppComponent } from '@app1/reusable.app.component'
    

    Hope this will help you otherwise please leave a comment.

    Login or Signup to reply.
  2. Make sure you have "preserveSymlinks": true set in angular.json, for all the projects that use linking.

      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            ...
            "preserveSymlinks": true,
    

    This tutorial is good for working with linked packages.

    How to Develop Angular Libraries Locally?

    I think pointing to the dist folder is causing the NG0203 which basically means, the service you have, is not considered as an angular service but a javascript class.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search