angular: Apps cannot build with AOT if a dependent library was built with barrels

This issue describes mysterious build failures for apps that depend on an npm-installed library that was built with barrels.

A barrel is an index.ts file that consolidates exported symbols of several nested files.

The problem lies somewhere in the interaction among barrels, AOT, and ngPackagr.

Workaround: Do not use barrels in your library. Always and everywhere make direct references to the source files.

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

ng build --AOT of an app fails with absurd errors concerning a library installed with npm.

That library was built with barrels.

Specifically, the top-level index.ts that tells ngPackagr which artifacts to include in the library’s public API was built with barrels.

The library author (me) was able to build that library for production without any warnings or errors. Worse, it seemed to work when used in most applications that installed the library.

But occasionally you’d get weird errors when you ng build --aot the application, such as

ERROR in ./src/client/app/test-users/test-users.module.ngfactory.js
Module not found: Error: Can't resolve 'ngrx-data/selectors/index' in '/Users/Ward/_git/sp-x/src/client/app/test-users'

Note the reference in the error to index in ‘ngrx-data/selectors/index’. That’s a barrel file the wasn’t directly exposed publicaly.

ERROR in app/store/app-pluralizer.ts(17,13): Error during template compile of 'AppPluralizer'
  Only initialized variables and constants can be referenced in decorators because the value of this variable is needed by the template compiler in 'PLURAL_NAMES_TOKEN'
    'PLURAL_NAMES_TOKEN' references 'PLURAL_NAMES_TOKEN'
      'PLURAL_NAMES_TOKEN' references 'PLURAL_NAMES_TOKEN'
        'PLURAL_NAMES_TOKEN' is not initialized at ../../ngrx-data/utils/interfaces.ts(13,22).

The constant was initialized … on line 16 in ngrx-data/utils/interfaces.ts. Notice the line number is 13 in the error message. Thats where the token is declared in the d.ts type definition file (interfaces.d.ts), not the .ts source file.

Shuffling the order of exports in the top level index.ts would fix one use case but trigger another.

These are all clues that you are using barrels and AOT + ngPackagr` do not like barrels.

Expected behavior

I think we should be able to use barrels.

AOT + ngPackagr should be able to determine the proper dependency order as is possible with JIT compilation.

Minimal reproduction of the problem with instructions

There is no easy way to reproduce this bad behavior because barrels often appear to work. The problem likely arises when a library’s sub-files refer to files that are exported in other barrels (even when those references are direct to the dependent files, by-passing barrels).

You can see the horror story play-out in the 1.0.0-beta.12 and 1.0.0-beta.13 releases of https://github.com/johnpapa/angular-ngrx-data.

This repo has both a library (/lib) and an example that uses that library (/src/client).

To experience the problem:

  • clone https://github.com/johnpapa/angular-ngrx-data
  • go back to the Beta 12 commit
  • npm install
  • npm run build-all # this should succeed.
  • Edit lib/src/index.ts
  • Move export * from './utils'; to the bottom of the file
  • npm run build-lib # rebuilds the library
  • ng build --aot # now it fails with the strange InjectionToken error ^^^

You can build with AOT if you remove the following providers from src/client/app/store/entity-store.module.ts

    { provide: Logger, useClass: AppLogger },
    { provide: Pluralizer, useClass: AppPluralizer }

This succeeds because these providers reference the library’s Logger and Pluralizer abstract classes in ./util (the barrel). Removing them by-passes the library reference lookup that produces the errors.

Pragmatically, this means that the library author (me) won’t discover there is a problem until some consumer (you) tries to override the default logger and pluralizer behaviors by supplying alternative implementations through this official extension point.

  • revert change to lib/src/index.ts.
  • npm run build-lib # rebuilds the library
  • ng build --aot # build succeeds

A dev build (e.g, ng serve) works fine at any point in this process.

If you now move forward to Beta 13 where barrels are eliminated, all of these problems go away and you can build the sample app with ng build --aot at any point.

What is the motivation / use case for changing the behavior?

Barrels nicely encapsulate and minimize low-level details of a library’s internal folder structure. They work great with JIT. Obviously not with AOT at this time.

Environment


Angular version: 5.2.10
ngPackagr version: 2.4.2

I do not know if it is still a problem in v.6. I don’t have the time to find out.

Browser: Irrelevant

For Tooling issues: irrelevant

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 20
  • Comments: 15 (8 by maintainers)

Commits related to this issue

Most upvoted comments

It seems this exact same problem occurs with Angular 6. Angular cli libraries. I had to remove all my references to barrels to make it work.

Angular CLI: 6.1.5 Angular: 6.1.4

I’m still having this issue in Angular 8. In a library, anything with decorator won’t work if exported using barrel export. Any resolution to this issue, or perhaps another issue I can keep track of?

I’m following up on this with the team to see what clarification we can get around this issue. Will post an update next week.

TL;DR Barrels are full of oil. We want green Angular! 😆

I opened my PR for this before 6 left beta, in the hope of getting it included (and possibly backported to 5.x). However, the PR has been completely ignored for months despite numerous requests for review / comment. I can only assume the team doesn’t view this as a high priority issue.

@jeffora Thanks for the PR and it was overlooked, though it’s definitely an important one. I’m closing this issue as that PR has now been merged. It should be out with tomorrow’s release. #22856

@jasonaden Thanks, and no worries. Glad to see it get in!