Skip to content

Cannot read property 'loadChildren' of undefined #4686

Closed

Description

@fulls1z3

Please provide us with the following information:

OS?

Windows 10

Versions.

@angular/cli: 1.0.0-beta.30
node: 6.9.1
os: win32 x64
@angular/common: 2.4.7
@angular/compiler: 2.4.7
@angular/core: 2.4.7
@angular/forms: 2.4.7
@angular/http: 2.4.7
@angular/platform-browser: 2.4.7
@angular/platform-browser-dynamic: 2.4.7
@angular/router: 3.4.7
@angular/cli: 1.0.0-beta.30
@angular/compiler-cli: 2.4.7

Repro steps.

feature.module.ts
Using @nglibs/i18n-router to provide route translations for feature modules (lazy loaded).

import { I18NRouterModule } from '@nglibs/i18n-router';

@NgModule({
  imports: [
    CommonModule,
    // RouterModule.forChild(routes)
    I18NRouterModule.forChild(routes, 'about')
  ],
  declarations: [
    AboutComponent,
    AboutUsComponent,
    AboutBananaComponent,
    AboutApplePearComponent
  ]
})

The whole solution is located on github: angular-cli branch of @nglibs/example-app.

The log given by the failure.

Can't talk about a stack trace, but hope it will be helpful:

$ ng serve
** NG Live Development Server is running on http://localhost:4200. **
Hash: ddefd75abb9ca8b82bd4                                                      Time: 18958ms
chunk    {0} polyfills.bundle.js, polyfills.bundle.map (polyfills) 222 kB {4} [initial] [rendered]
chunk    {1} main.bundle.js, main.bundle.map (main) 8.61 kB {3} [initial] [rendered]
chunk    {2} styles.bundle.js, styles.bundle.map (styles) 10 kB {4} [initial] [rendered]
chunk    {3} vendor.bundle.js, vendor.bundle.map (vendor) 3.49 MB [initial] [rendered]
chunk    {4} inline.bundle.js, inline.bundle.map (inline) 0 bytes [entry] [rendered]

ERROR in Cannot read property 'loadChildren' of undefined
webpack: Failed to compile.

Mention any other details that might be useful.

@nglibs/i18n-router does not work with @angular-cli (yet), and giving the following error during [AoT compilation]:

ERROR in Cannot read property 'loadChildren' of undefined

I suppose @angular-cli uses @ngtools/webpack for [AoT compilation], expecting RouterModule.forChild(...) to resolve lazy-loaded modules (with loadChildren), which is replaced by I18NRouterModule.forChild(...) - providing routes for feature modules instead.

Here's the piece of code from i18n-router module line 72, which provides child routes.

                {
                    provide: ROUTES,
                    useFactory: (provideChildRoutes),
                    deps: [I18NRouterService, RAW_ROUTES, MODULE_KEY],
                    multi: true
                },
                {
                    provide: ANALYZE_FOR_ENTRY_COMPONENTS,
                    useValue: routes,
                    multi: true
                }

It provides ROUTES and ANALYZE_FOR_ENTRY_COMPONENTS to Angular the same way that the router module does (see below):

However, angular-cli seems insisting ignoring the provided child routes and firing errors.

To resolve this issue temporarily, I switched using [ng-router-loader]. Hence @angular-cli doesn't allow modifying the webpack configuration, I need to manually configure build tools (dev/prod sever, task runners, webpack, etc).

I think loadChildren should be able to recognize routes provided with ROUTES and ANALYZE_FOR_ENTRY_COMPONENTS.

Activity

  1. Meligy commented on Feb 14, 2017

    @Meligy
    Contributor

    That's where the lazy route discovery is happening:

    https://github.com/angular/angular/blob/master/modules/%40angular/compiler-cli/src/ngtools_impl.ts#L56

    I wasn't even aware there're other alternatives to this, but to start with, it seems to be considering the ROUTES bit:

    // We cannot depend directly to @angular/router.
    type Route = any;
    const ROUTER_MODULE_PATH = '@angular/router/src/router_config_loader';
    const ROUTER_ROUTES_SYMBOL_NAME = 'ROUTES';
    
    ...
    
      const ROUTES = reflector.findDeclaration(ROUTER_MODULE_PATH, ROUTER_ROUTES_SYMBOL_NAME);
    

    No idea about ANALYZE_FOR_ENTRY_COMPONENTS (maybe the core team of the CLI has better idea).

    I wouldn't expect focus on this one from the core team before v1.0 final (could be wrong). Would you have any idea extending the above file to cater for your case?

  2. filipesilva commented on Mar 13, 2017

    @filipesilva
    Contributor

    I think this is essentially the same issue as #4541, please have a look.

  3. fulls1z3 commented on Mar 14, 2017

    @fulls1z3
    Author

    Hi @filipesilva, I've read #4541 and @christopherthielen talks about more or less a similar functionality.

    Currently waiting for updates, and many thanks for your attention 👍

  4. fulls1z3 commented on Mar 20, 2017

    @fulls1z3
    Author

    First of all I'd like to say thanks to @christopherthielen, for all the details he provided on #4541. This information was very helpful while analyzing the issue with @nglibs/i18n-router.

    As far as I can progress, I've found out that if I provide child routes unprocessed, then the @ngtools/webpack can find the lazy routes.

            {
              provide: ROUTES,
              useValue: routes,
              // useFactory: (provideChildRoutes),
              // deps: [I18NRouterService, RAW_ROUTES, MODULE_KEY],
              multi: true
            },
            {
              provide: ANALYZE_FOR_ENTRY_COMPONENTS,
              useValue: routes,
              multi: true
            }
    

    Now, the challenge is to get the @ngtools/webpack identify routes provided by useFactory.

  5. bevlison commented on Feb 20, 2018

    @bevlison

    I had the error. Found the cause in my case, want to share
    in the TS app-routes module (of angular 5 project) I made a syntax error :

    const routes: Routes = [
    { path: '', redirectTo:'/', pathMatch: 'full' }
    , { path: 'a', component : aComponent }
    , { path: 'a/detail/:id', component: aDetailComponent },
    , { path: 'b', component : bComponent }
    , { path: 'b/detail/:id', component : bDetailComponent }
    ];

    The error is the

    ,

    at the end of the 4th line, which delivers an empty element in the Routes array, which delivers the loadChildren error.

  6. akash-potdar7 commented on Jun 25, 2018

    @akash-potdar7

    I had the same error as well, but the problem was I had move the app-router.module.ts outside app folder.

  7. tomsaleeba commented on Jun 27, 2018

    @tomsaleeba

    I had the same error but yet another cause. I was dynamically assigning a key to the routes object:

    const routes: Routes = [{
      path: '',
      component: SomeComponent,
      children: [{
        path: 'blah',
        component: BlahCreateComponent,
        resolve: {
          [SOME_CONSTANT]: SomeResolver, // <-- you can't do this
        },
      }],
    }]

    I was only able to track down the issue by doing ng build --prod --aot which gave me an more descriptive error.

  8. thiagofrancisquete commented on Sep 2, 2018

    @thiagofrancisquete

    @tomsaleeba and how you fixed it? you just deleted the resolve part?

  9. skorenb commented on Sep 3, 2018

    @skorenb

    @tomsaleeba
    thank you for this clue.
    i did similar thing: i set a constant as key

    {
        path: 'feature',
        loadChildren: '...path-to-module...',
        data: {
            'menu-bar': MenuBar.Show,
            [AFTER_LOGIN_PRELOADING_STRATEGY]: true
        }
    }
    

    it's properly to set a key as direct definition or instant string value like data: { YEAR: 2018, 'month-text': 'August' }

  10. tomsaleeba commented on Sep 6, 2018

    @tomsaleeba

    @thiagofrancisquete as @KorenB mentioned, it seems like you can't dynamically set the key of the object (using that syntax with the square braces [SOME_KEY]. Instead, you need to directly define the key.

    As a concrete example, assume I was trying to assing the dynamic key like this

    const SOME_CONSTANT = 'theKey'
    ...
        resolve: {
          [SOME_CONSTANT]: SomeResolver,
        },
    ...

    ...to fix it, you need to do this:

    ...
        resolve: {
          theKey: SomeResolver,
        },
    ...
  11. vsagar9944 commented on Sep 13, 2018

    @vsagar9944

    I had faced same issue. In My case I had not included my Route resolver in provider property of NgModule.
    After declaring in provider this issue get fixed.

  12. tokiodeo commented on Oct 17, 2018

    @tokiodeo

    as I commented @bevlison I also had syntax error [ , , ]
    export const AuthRoutes: Routes = [ { path: '', redirectTo: 'signin', pathMatch: 'full' }, { path: 'signin', component: SigninComponent }, { path: 'signup', component: SignupComponent }, { path: 'reset-password', component: ResetPasswordComponent }, { path: 'recover-email', component: RecoverEmailComponent }, , { path: 'verify-email', component: VerifyEmailComponent }];

  13. klst-speterson commented on Jan 3, 2019

    @klst-speterson

    One final gotcha to contribute:

    import { urls } from 'consts'
    
    const { topLevelRoutes } = urls
    
    const routes = [
        { path: topLevelRoutes.login, loadChildren: 'path/login.module#LoginModule' },
        { path: topLevelRoutes.dashboard, loadChildren: 'path/dashboard.module#DashboardModule' },
        { path: '**', redirectTo: topLevelRoutes.dashboard }
    ]

    Fails with the aforementioned error.

    import { urls } from 'consts'
    
    // const { topLevelRoutes } = urls
    
    const routes = [
        { path: urls.topLevelRoutes.login, loadChildren: 'path/login.module#LoginModule' },
        { path: urls.topLevelRoutes.dashboard, loadChildren: 'path/dashboard.module#DashboardModule' },
        { path: '**', redirectTo: urls.topLevelRoutes.dashboard }
    ]

    Works fine.

    Not sure if it's only a dev server thing and works with a proper build or not. Also not sure about any permutations. Obviously not a pain point, just wanted to add this in case somehow runs into a similar circumstance.

  14. RasicN commented on Jan 28, 2019

    @RasicN

    I came to this issue with a similar problem and actually found my fix here.

    The problem I was having was I did not have the export on my function as soon as I added export to it I could build again. Sorry if this isn't specifically related to the OP but thought it may help someone.

  15. sanidz commented on Feb 19, 2019

    @sanidz

    I had the same error but yet another cause. I was dynamically assigning a key to the routes object:

    const routes: Routes = [{
      path: '',
      component: SomeComponent,
      children: [{
        path: 'blah',
        component: BlahCreateComponent,
        resolve: {
          [SOME_CONSTANT]: SomeResolver, // <-- you can't do this
        },
      }],
    }]

    I was only able to track down the issue by doing ng build --prod --aot which gave me an more descriptive error.

    Sure, in my case this did the trick:

    const routes: Routes = [];
    routes.push(...links.map(link => <Route> { path: link.url, component: link.component }));

  16. esiva commented on Apr 16, 2019

    @esiva

    run angular using aot option to get a full descriptive error
    ng s --aot

  17. Uirado commented on Jun 28, 2019

    @Uirado

    I faced this error as well but for another reason.
    I was passing a regex as value inside the data:
    data: { regex: /^([0-9]+)$/ }

    I had to convert it to a string:
    data: { regex: '^([0-9]+)$' }

  18. rcollette commented on Jul 8, 2019

    @rcollette

    I know this thread is becoming like stack overflow, but it's the first hit on Google. Here was my scenario.

    Cause: routes was not defined as a constant.

    I had a route configuration like:

    let routes: Routes;
    routes = [
      {
        path: '',
        children: [
          {
            path: '',
            children: [
              {
                path: '',
                children: [
                  {path: '', component: HeaderComponent, outlet: 'header'},
                  {path: '', component: FooterComponent, outlet: 'footer'}
                  // Routes that display a header and footer go here.
                ]
              },
              {
                path: '',
                children: [
                  {
                    path: '/frame',
                    children: [{
                      path: 'search',
                      loadChildren: () => import('./search/search.module').then(module => module.SearchModule)
                    }]
                  }
                ]
              }
            ]
          }
        ]
      }
    ];

    Very specifically, while I was in ng serve (npm start) mode and the browser was at the /frame/search path, I modified the routes to include a ** path (just randomly adding stuff from another working application).

    let routes: Routes;
    routes = [
      {
        path: '',
        children: [
          {
            path: '',
            children: [
              {
                path: '',
                children: [
                  {path: '', component: HeaderComponent, outlet: 'header'},
                  {path: '', component: FooterComponent, outlet: 'footer'}
                  // Routes that display a header and footer go here.
                ]
              },
              {
                path: '',
                children: [
                  {
                    path: '/frame',
                    children: [{
                      path: 'search',
                      loadChildren: () => import('./search/search.module').then(module => module.SearchModule)
                    }]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        path: '**',
        redirectTo: '/frame/search',
        pathMatch: 'full'
      }
    ];

    The browser refreshed and there was a console error:

    Uncaught Error: Component HeaderComponent is not part of any NgModule or the module has not been imported into your module.
    

    So sure enough, I had not added those imports to the app.module. I don't know if the error message presented simply by making any change or by adding this specific route change. I do know that if I ran npm start after adding the ** path, I could not get the console error to present.

    After adding those imports I got another console error:

    Invalid configuration of route '/frame': path cannot start with a slash
    

    I fixed that:

    let routes: Routes
    routes = [
      {
        path: '',
        children: [
          {
            path: '',
            children: [
              {
                path: '',
                children: [
                  {path: '', component: HeaderComponent, outlet: 'header'},
                  {path: '', component: FooterComponent, outlet: 'footer'}
                  // Routes that display a header and footer go here.
                ]
              },
              {
                path: '',
                data: {header: false, footer: false},
                children: [
                  {
                    path: 'frame',
                    children: [{
                      path: 'search',
                      loadChildren: () => import('./search/search.module').then(module => module.SearchModule)
                    }]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        path: '**',
        redirectTo: '/frame/search',
        pathMatch: 'full'
      }
    ];

    And I was good to go (or so I thought).

    npm start was still throwing the error.

    Comparing the route files between a new project and mine, I noticed that routes was defined as a constant. I probably had copied in the routes from a prior project, or WebStorm modified the code somehow, not sure.

    So finally my working app-routes.

    const routes: Routes = [
      {
        path: '',
        children: [
          {
            path: '',
            children: [
              {
                path: '',
                children: [
                  {path: '', component: HeaderComponent, outlet: 'header'},
                  {path: '', component: FooterComponent, outlet: 'footer'}
                  // Routes that display a header and footer go here.
                ]
              },
              {
                path: '',
                data: {header: false, footer: false},
                children: [
                  {
                    path: 'frame',
                    children: [{
                      path: 'search',
                      loadChildren: () => import('./search/search.module').then(module => module.SearchModule)
                    }]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        path: '**',
        redirectTo: '/frame/search',
        pathMatch: 'full'
      }
    ];
  19. vladimiry commented on Jul 18, 2019

    @vladimiry

    By the way, using constants for defining the route props works if you compile with Ivy renderer.

  20. gbertoncelli commented on Jul 26, 2019

    @gbertoncelli

    I had the same error but yet another cause. I was dynamically assigning a key to the routes object:

    const routes: Routes = [{
      path: '',
      component: SomeComponent,
      children: [{
        path: 'blah',
        component: BlahCreateComponent,
        resolve: {
          [SOME_CONSTANT]: SomeResolver, // <-- you can't do this
        },
      }],
    }]

    I was only able to track down the issue by doing ng build --prod --aot which gave me an more descriptive error.

    This should be working however, it is not so unusual to use constant keys for routing data that eventually you have to retrieve in other places of the application...

    My workaround was something like this:

    const routesData = {
      data: {
        [CONSTANT_1]: 'PARAM_VALUE_1',
        [CONSTANT_2]: 'PARAM_VALUE_2'
      }
    }
    
    const routes: Routes = [
      {
        path: 'myPath',
        component: MyComponent,
        ...routesData,
        // ... other routes configuration params
      }
    ];
    

    This actually works because the constant key values are resolved before the routes definition so there are no compilation errors.

  21. angular-automatic-lock-bot commented on Sep 9, 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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions