Repository navigation
Description
I'm submitting a ... (check one with "x")
[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
We are using Features-Modules to encapsulate things belonging together and we are using theses Features-Modules in Routing like this:
app.module.ts
@NgModule({
imports: [SharedModule.forRoot(),
BrowserModule,
RouterModule.forRoot(APP_ROUTES)
],
...
})
export class AppModule {
}app.routes.ts:
export function getTasksModule() {
return TasksModule;
}
export const APP_ROUTES: Routes = [
...
{path: 'tasks', canLoad: [LoginGuard], loadChildren: getTasksModule},
];this works fine when not doing AOT. Now when calling
./node_modules/.bin/ngc -p ./src
the application compiles without errors, but in runtime I get the following exception when enterting the /tasks route:
Error: Uncaught (in promise): TypeError: r.create is not a function
at resolvePromise (zone.js:558)
at zone.js:535
at ZoneDelegate.invoke (zone.js:332)
at Object.NgZoneImpl.inner.inner.fork.onInvoke (ng_zone_impl.js:41)after some debugging it looks like the application get the TasksModule where it needs to have the TasksModuleNgFactory. So the exception happens in this code:
router_config_loader.ts
load(parentInjector: Injector, loadChildren: LoadChildren): Observable<LoadedRouterConfig> {
return this.loadModuleFactory(loadChildren).map(r => {
const ref = r.create(parentInjector);
return new LoadedRouterConfig(
flatten(ref.injector.get(ROUTES)), ref.injector, ref.componentFactoryResolver);
});
}and r is TasksModule when the exeption occurs.
Expected/desired behavior
It should be possible to use loadChildren in combination with AOT
What is the motivation / use case for changing the behavior?
Currently it's not possible to encapsulate routing into Feature-Modules when using the AOT-compiler
Please tell us about your environment:
- Angular version: commit 2b313e4
- Browser: [all ]
- Language: [all ]
Activity
[-](bug)router/AOT unable to use feature-modules in routing when doing AOT compilation[/-][+](bug)router/AOT Unable to use feature-modules in routing when doing AOT compilation[/+]qdouble commentedon Sep 2, 2016
I just encountered this. The bug is still present using the latest incremental builds.
hansl commentedon Sep 6, 2016
Could you try to use a string to the module instead of a function for
loadChildren?Also, the CLI is broken right now until #11387 is in and released.
choeller commentedon Sep 6, 2016
When trying to pass in a string angular seems to try to lazy load although I'm using webpack with a single bundle. (with my setup this fails as it's missing System.JS I think) I don't need lazy loading (nor would I know how to setup my bundles correctly ;)) so using a function to load the module worked perfectly fine for me.
qdouble commentedon Sep 6, 2016
@hansl how would you load it with a string?
when I try to put something like
{ path: 'lazy', loadChildren: './features/lazy#LazyModule' }that does't seem to work at all with webpack.Both of the ones below work fine in JIT, but not AOT.
Is there any current solution for us that are using Webpack 2, but not CLI?
hansl commentedon Sep 6, 2016
@choeller it fails because it uses
System.import(), yes, but not because you're missingSystemJS.SystemJSis a library that implements a polyfill ofSystem.import(), but normally webpack is able to detect calls to it and refactor the code to use an internal webpack-specific implementation. In the current RC6 the bug is that webpack is not smart enough to detect the call toSystem.import()and leave the code as is, resulting in a real call to a non-existantSystem.There are many ways to fix it, but there's only 2 ways that work with the CLI:
System.import(), similar to what @qdouble posted in his second example. You could also use the first one but it's more reliant on webpack and might require more typing.There is a few other solutions but they're way more complicated. The truth is, when Angular RC6+1 comes around with bug fixes that bug will be fixed in Angular. Until then, you're stuck with a manual solution, at least temporarily.
qdouble commentedon Sep 6, 2016
@hansl I'm a bit confused by your reply, it seems you are not specifically addressing the issue as it pertains to AOT. You said the export functions work are a solution, but they do not work properly in AOT mode. It compiles fine, but when you actually navigate to the route it gives the
t.create is not a function error.I'm using the latest nightly builds by the way.
hansl commentedon Sep 6, 2016
That's because Lazy Loading changes with AoT. You're not loading a module anymore, but a module factory.
qdouble commentedon Sep 6, 2016
@hansl so the solution would be that we have to point to somewhere different when the module is loaded lazily? Like in JIT it'd point to
LazyModuleand in AOT we'd set it to point toLazyModuleNgFactory? Or is there some other workaround we need to implement?qdouble commentedon Sep 6, 2016
@hansl Okay, I got what you are saying now...if I point directly to the ngc generated factory, it lazy loads fine. Seems that unless you have a plugin that knows where your tsconfig output is going and that can parse your existing module, it could be a bit tedious to set both...but assuming you don't have a boat load of lazy loaded modules, doing it manually isn't torture I suppose.
hansl commentedon Sep 7, 2016
If you use a string, the module loader will inject an
ngfactoryin the string before calling system.import. That's why you don't need to change anything in that case.One way we've been doing AoT is by running the ngc tool ourselves and then using the cli to compile. Rob Wormald should be close to be done with integrating AoT in the CLI. That will also include code to support lazy loading.
qdouble commentedon Sep 7, 2016
@hansl could you give me an example of
return System.import('./features/lazy').then((r: any) => r.LazyModule);into a valid string? I'm having issues getting it to work, not quite sure how it's supposed to look.19 remaining items
SamVerschueren commentedon Jan 11, 2017
It's not angular CLI specific. I never used the CLI and I have the same issues.
I created a quick example here.
git clone https://github.com/SamVerschueren/ng2-hello-world-routingcd ng2-hello-world-routinggit checkout load-childrennpm installIf you run
npm start, you will notice that you can navigate fromHometoContactand back while it uses the approach mentioned in the initial post.Now if you build it with
npm run build, it will output a production bundle in thebuildsdirectory. So navigate to that directory and start a local server (http-server,lite-server, ...). Open the url and open devtools. If you click onContact, it will fail to load and shows an error aboutr.createnot being a function.DzmitryShylovich commentedon Jan 11, 2017
@SamVerschueren rollup doesn't support lazy loading
SamVerschueren commentedon Jan 11, 2017
@DzmitryShylovich You pinged the wrong Sam ;).
Yes I know, but this issue isn't about lazy loading. Lazy loading happens when you use a string literal as value of the
loadChildrenproperty.This issue is about passing a function that returns a module to the
loadChildrenproperty. For example, the app.routing.ts from my exampleEverything is in one bundle. The main benefit is that every route inside the
contactpart of your application starts with/contactand you can easily change that.So yes, rollup doesn't work with lazy loading but like said in the beginning, this is not the same.
DzmitryShylovich commentedon Jan 11, 2017
sorry, github didn't suggest your name for some reason :)
kpudlik commentedon Jan 13, 2017
+1
Using loadChildren() is the only way to follow the NgModule encapsulation conception (because it encapsulates routes too). Without using loadChildren there is a huge mess with different conventions... It should work with AoT out of the box...
DzmitryShylovich commentedon Jan 13, 2017
You need to return
NgModuleFactoryinstead ofNgModule, because we cannot compile it at runtime (compiler is not available after aot).Example is here #13909
Until pr will be merged you need to cast factory to
any:You should open a feature request in cli repo to automatically convert
NgModuleintoNgModuleFactoryduring compilation, but for other build tools you need to do this manually.fix(router): enable loadChildren with function in aot (#13909)
fix(router): enable loadChildren with function in aot (#13909)
fix(router): enable loadChildren with function in aot (angular#13909)
baisui1981 commentedon Aug 12, 2017
@SamVerschueren i have fixed it, as u mentioned
`
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { ContactModule } from './contact/contact.module';
export function loadContactModule() {
return ContactModule;
}
export const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'contact', loadChildren: loadContactModule }
];
export const routing = RouterModule.forRoot(routes);
change the ContactModule To ContactModuleNgFactoryimport { Routes, RouterModule, PreloadAllModules } from '@angular/router';import { HomeComponent } from './home/home.component';
import {ContactModuleNgFactory} from "../../aot/src/user/contact.module.ngfactory";
export function loadContactModule() {
return ContactModuleNgFactory;
}
export const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'contact', loadChildren: loadContactModule }
];
export const routing = RouterModule.forRoot(routes);
in order to make aot compile success,create a new file named “app.module-aot.ts” and also should modify the element "files" which is aot compiler entry in "tsconfig-aot.json""files": ["src/app.module.ts",
"src/main.ts"
],
to"files": [
"src/contact/contact.module.ts",
"src/app.module-aot.ts",
"src/main.ts"
]
`
tested, that is effective
fix(router): enable loadChildren with function in aot (angular#13909)
angular-automatic-lock-bot commentedon Sep 12, 2019
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.
fix(router): enable loadChildren with function in aot (angular#13909)