Skip to content

Exclude all entrypoints of a library from prebundling  #29170

@kjteh

Description

@kjteh

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

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions