Skip to content

Improve error messages for cases when circular dependencies cause symbols with metadata be undefined at the time when they are captured  #9334

Closed

Description

@Blasz

I'm submitting a ...

  • bug report

Current behavior
If a component (A) imports and uses a service/component (B) from a barrel containing the exports of both A and B, and A appears before B in the barrel, the imported value of B is undefined and results in the following errors when that service/component is used:

  • If B is a service:
EXCEPTION: TypeError: Cannot read property 'parameters' of undefined
EXCEPTION: Error: Uncaught (in promise): TypeError: Cannot read property 'parameters' of undefined
  • If B is a component:
EXCEPTION: Unexpected directive value 'undefined' on the View of component 'FeatureComponent'
EXCEPTION: Error: Uncaught (in promise): Unexpected directive value 'undefined' on the View of component 'FeatureComponent'

I'm guessing that when importing from a barrel, the exported modules are processed topdown and if the module matches the importing module it thinks there is a circular dependency and just short-circuits with undefined.

Expected/desired behavior
I'd expect:

  • the module to import correctly, regardless of the order of exports in the barrel.
  • the service error message above to be less cryptic like the component message (maybe separate issue?)
  • some kind of proper warning/error when a circular depedency is encountered (false positive or otherwise)

If this issue can't be fixed in angular, I'd suggest:

  • A warning in the angular styleguide/glossary on barrels that ordering of exports may cause circular-dependency related errors.
  • Potentially stricter guidelines on how barrels are used that prevents this use case from happening.

Reproduction of the problem

Importing service: http://plnkr.co/edit/vlPyw7aV3V35s1yTJbal?p=preview
Importing component: http://plnkr.co/edit/Qa1Hof7GsrBcfNso8WCL?p=preview

Toggle the commenting of the exports in app/feature/index.ts to see that the problem is order-related.

Please tell us about your environment:

  • Angular version: 2.0.0-rc.2

Activity

  1. changed the title [-]Certain ordering barrels result in circular dependency false positive and cryptic error message[/-] [+]Certain ordering in barrels result in circular dependency false positive and cryptic error message[/+] on Jun 18, 2016
  2. Blasz commented on Jun 18, 2016

    @Blasz
    Author

    After further investigation, I've narrowed this down to the fact that the typescript compiler configuration compiles down to commonjs modules by default:

    tsconfig.json

    {
      "compilerOptions": {
        ..
        "module": "commonjs"
        ..
    

    Setting it to system fixes this issue and kind of makes sense considering we're using systemJS to load angular by default.

    Perhaps the angular.io docs and angular-CLI can be updated to use system instead of commonjs?

  3. robwormald commented on Jun 19, 2016

    @robwormald
    Contributor

    This is an inherent issue with commonJS modules, but not one we can really do much about, unfortunately.

    ES6 modules (and SystemJS, because it implements the same semantics) have support for this, but we can't (yet) mandate either of those as browser support is not in place yet.

    CommonJS is the defacto for NPM, and thus we can't use System there (nor can we mandate that everybody use SystemJS modules). We do ship ES6 modules alongside the commonJS code (see the /esm subdirectory), and I'd expect we'll eventually move the CLI to use those.

    Our best advice on this is to avoid circular dependencies where possible.

  4. changed the title [-]Certain ordering in barrels result in circular dependency false positive and cryptic error message[/-] [+]Improve error messages for cases when circular dependencies cause symbols with metadata be undefined at the time when they are captured [/+] on Jun 22, 2016
  5. IgorMinar commented on Jun 22, 2016

    @IgorMinar
    Contributor

    Another way to work around this is by using forwardRef which delays the dereferencing of the component type and allows us to get the right instance:

    directives: [forwardRef(() =>OtherComponent)]
    

    http://plnkr.co/edit/YMhas7tEHskSZGOcHSTd?p=preview

    The same works for services.

    I agree that we should improve the error messages though as they don't give a clue as to what went wrong.

  6. added this to the Angular 2 Final milestone on Jun 22, 2016
  7. pkozlowski-opensource commented on Jun 22, 2016

    @pkozlowski-opensource
    Member

    I will have a look at those error messages as I was tackling similar cases recently.

  8. Blasz commented on Jun 22, 2016

    @Blasz
    Author

    The issue remains that it's not obvious that the ordering of exports in a barrel will cause circular dependency problems.
    In the example plunk, it's clear that there is no real circular dependency between the feature and other component.
    Unless the developer already has deep knowledge of how module import resolution works for commonjs, they will not know that:

    • when importing from a barrel, the module importer will short circuit and return undefined when it comes across a reference to the importing module itself.
    • a specific ordering in barrels is required where module dependencies are exported before their dependants.

    I believe docs will still be needed detailing this if we can't allow arbitrary ordering.

    I might test this case out in node instead of systemjs to see if the behaviour is caused commonjs or systemjs loading commonjs

  9. pkozlowski-opensource commented on Aug 30, 2016

    @pkozlowski-opensource
    Member

    This is an inherent issue with commonJS modules, but not one we can really do much about, unfortunately.

    Yeh, @robwormald is totally right here....

    I agree that we should improve the error messages though as they don't give a clue as to what went wrong.

    The good news is that now we've got clear error messages for undefined providers (a provider gets undefined in the circular dependency case): https://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=preview - the error is Error: One or more of providers for "App" were not defined: [?]..

    Since the imports of directives on a component level is gone we don't need to worry about this case.

    To sum up: we can't do much about circular deps and error messages were clarified.

  10. maliksahil commented on Jul 25, 2017

    @maliksahil

    Is there a way or tool that detects circular dependencies? Unfortunately in a large project it is very difficult to detect circular dependencies.

  11. KostyaTretyak commented on Aug 29, 2017

    @KostyaTretyak
    Contributor

    @maliksahil, to avoid circular dependency, just don't:

    import { SomeClass } from './path/to/index';

    Instead, use directly path to the file:

    import { SomeClass } from './path/to/some-class';

    This does not apply to the modules that you import from the node_modules.

  12. angular-automatic-lock-bot commented on Sep 12, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  13. locked and limited conversation to collaborators on Sep 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions