Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

To exclude all secondary points of a library in a host repo when running ng serve with "npm link" #29170

Open
1 task
kjteh opened this issue Dec 18, 2024 · 4 comments
Labels
angular/build:dev-server area: @angular/build feature: votes required Feature request which is currently still in the voting phase feature Issue that requests a new feature

Comments

@kjteh
Copy link

kjteh commented Dec 18, 2024

Command

serve

Is this a regression?

  • Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

Background:

I am currently developing a library (my-library) using ng-packagr with multiple secondary entry points. I also have another repo (my-application) that depends on the library. For setting up a local development environment, I am using npm link to link dist/lib-a to the my-application repo, running ng watch in lib-a and ng serve in my-application when performing development.

I knew that in order to make ng serve detect the code changes from the linked lib-a, I need to do following:

  • In angular.json, specify architect.build.configurations.development.preserveSymlink: true
  • In tsconfig.json, define the paths property (define prebundle.exclude: "lib-a" in angular.json is not helpful, cause it doesnt support glob pattern to match all of my library's sub-entries):
"paths": {
      "lib-a": ["./node_modules/lib-a"],
      "lib-a/*": ["./node_modules/lib-a/*"],
    },

In my-library (lib-a), I have these 2 sub-entry points, component-y and service-x. Basically the component-y depends on service-x to show some data that is getting from the token that injected in service-x. In my-application (app.config.ts), I will provide the value of the token.

service-x

export const X_TOKEN = new InjectionToken('X_TOKEN');

@Injectable({ providedIn: 'root' })
export class ServiceX {
    myXToken = inject(X_TOKEN);
} 

component-y

@Component({
    changeDetection: ChangeDetectionStrategy.OnPush,
    selector: "component-y",
    template: "<p>lib-a-component works! {{ myServiceX.myXToken}}</p>"
})
export class ComponentY {
    protected myServiceX = inject(ServiceX);
} 

In my-application (app.config.ts)

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }), 
    { provide: X_TOKEN, useValue: 'OTHER_VALUE'},
    provideRouter(routes)
  ]
};

Actual Issue

Everything is working fine when it is being built or serve in my-library.
However, in my-application, the behavior is not working as I expected when running with ng serve.
It produces following error when I navigate to the page that using the component-y:

ERROR NullInjectorError: R3InjectorError(Environment Injector)[_ServiceX -> InjectionToken X_TOKEN -> InjectionToken X_TOKEN]: 
  NullInjectorError: No provider for InjectionToken X_TOKEN!

Observations:

  • If I remove the paths property in tsconfig, the null injector error is not observed in the next following ng serve.
  • I also tested the built files that generated from ng build (development/production) in my-application with angular-http-server. Everything is working fine.
  • The above issue happens in Angular 18 as well.

Expected behavior:

Running ng serve with npm link library should behave the same as running ng serve with library that installed using npm install.
I suspect this is a bug because I cant reproduce this in the codes that generated in ng build (preserveSymlink is specified also).

Other Questions:

  1. Can we just define prebundle.exclude: ["lib-a"] instead of ["lib-a/component-y", "lib-a/service-x"] ? Currently, if there is any code changes done in the sub-entries, it wont detect as a change if we define as ["lib-a"]. As an alternative, I am doing it now in tsconfig instead.
  2. Is it valid to provide the X_TOKEN value in app.config, where the token will be injected in a root service (ServiceX)? I assume provide token in app.config is the same as providedIn: 'root' and it should not cause any race-condition issue that causes the root service not able to inject the token.

Thanks and appreciate your help on this.

Minimal Reproduction

my-library:
https://github.com/kjteh/my-library-npm-link

my-application:
https://github.com/kjteh/my-application-npm-link

Steps:

  1. In my-library-npm-link, run npm run watch
  2. cd to dist/lib-a, run npm link
  3. In my-application-npm-link, run npm link lib-a --save
  4. Run ng serve in my-application-npm-link
  5. Go to localhost:4200/pagez
  6. NullInjector error is shown in the console.

Exception or Error


Your Environment

Angular CLI: 19.0.5
Node: 18.20.4
Package Manager: npm 10.7.0
OS: win32 x64

Angular: 19.0.4
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1900.5
@angular-devkit/build-angular   19.0.5
@angular-devkit/core            19.0.5
@angular-devkit/schematics      19.0.5
@angular/cli                    19.0.5
@schematics/angular             19.0.5
rxjs                            7.8.1
typescript                      5.6.3
zone.js                         0.15.0

Anything else relevant?

No response

@kjteh
Copy link
Author

kjteh commented Dec 18, 2024

Extra findings:
I tried to print the ServiceX to console using Angular Dev Tool browser extension, this is what I get:

Image

@kjteh
Copy link
Author

kjteh commented Dec 23, 2024

Hi @clydin, @alan-agius4

Let me rephrase the question again. I would like to know does angular-cli currently supports excluding prebundle of library that comes with secondary points?

I found a similar issue, might be related:
#27805 (comment)

Based on the above issue, it seems like typescript "does not recommend using the paths option to map to node modules". If that is the case, is there any way for us to define in angular.json to exclude ALL of the secondary points of a library that is installed using npm link?

@kjteh kjteh changed the title Unexpected behavior when running ng serve with "npm link" To exclude all secondary points of a library in a host repo when running ng serve with "npm link" Dec 23, 2024
@alan-agius4
Copy link
Collaborator

Yes, as you mentioned, you would need to exclude each entry point individually. There isn't a way to disable all entry points at once, but we could potentially enhance this feature to support wildcards, such as @mylib/*, to exclude all entry points at once.

@alan-agius4 alan-agius4 added the feature Issue that requests a new feature label Jan 6, 2025
@angular-robot angular-robot bot added the feature: votes required Feature request which is currently still in the voting phase label Jan 6, 2025
Copy link
Contributor

angular-robot bot commented Jan 6, 2025

This feature request is now candidate for our backlog! In the next phase, the community has 60 days to upvote. If the request receives more than 20 upvotes, we'll move it to our consideration list.

You can find more details about the feature request process in our documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
angular/build:dev-server area: @angular/build feature: votes required Feature request which is currently still in the voting phase feature Issue that requests a new feature
Projects
None yet
Development

No branches or pull requests

2 participants