Skip to content

Commit 8efa136

Browse files
authored
fix(page-router-outlet): make page-router-outlet lazy-loadable (NativeScript#530)
1 parent f8a56f3 commit 8efa136

File tree

5 files changed

+140
-23
lines changed

5 files changed

+140
-23
lines changed

nativescript-angular/router/page-router-outlet.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,16 @@ export class PageRouterOutlet {
152152
if (this.locationStrategy._isPageNavigatingBack()) {
153153
this.activateOnGoBack(activatedRoute, providers, outletMap);
154154
} else {
155-
this.activateOnGoForward(activatedRoute, providers, outletMap);
155+
this.activateOnGoForward(activatedRoute, providers, outletMap, loadedResolver);
156156
}
157157
}
158158

159159
private activateOnGoForward(
160160
activatedRoute: ActivatedRoute,
161161
providers: ResolvedReflectiveProvider[],
162-
outletMap: RouterOutletMap): void {
163-
const factory = this.getComponentFactory(activatedRoute);
162+
outletMap: RouterOutletMap,
163+
loadedResolver: ComponentFactoryResolver): void {
164+
const factory = this.getComponentFactory(activatedRoute, loadedResolver);
164165

165166
const pageRoute = new PageRoute(activatedRoute);
166167
providers = [...providers, ...ReflectiveInjector.resolve([{ provide: PageRoute, useValue: pageRoute }])];
@@ -241,31 +242,19 @@ export class PageRouterOutlet {
241242
}
242243

243244
// NOTE: Using private APIs - potential break point!
244-
private getComponentFactory(activatedRoute: any): ComponentFactory<any> {
245+
private getComponentFactory(activatedRoute: any, loadedResolver: ComponentFactoryResolver): ComponentFactory<any> {
245246
const snapshot = activatedRoute._futureSnapshot;
246247
const component = <any>snapshot._routeConfig.component;
247248
let factory: ComponentFactory<any>;
248-
try {
249-
factory = typeof component === 'string' ?
250-
snapshot._resolvedComponentFactory :
251-
this.componentFactoryResolver.resolveComponentFactory(component);
252-
} catch (e) {
253-
if (!(e.constructor.name === "NoComponentFactoryError")) {
254-
throw e;
255-
}
256-
// TODO: vsavkin uncomment this once ComponentResolver is deprecated
257-
// const componentName = component ? component.name : null;
258-
// console.warn(
259-
// `'${componentName}' not found in precompile array. To ensure all components referred
260-
// to by the RouterConfig are compiled, you must add '${componentName}' to the
261-
// 'precompile' array of your application component. This will be required in a future
262-
// release of the router.`);
263-
264-
factory = snapshot._resolvedComponentFactory;
249+
250+
if (loadedResolver) {
251+
factory = loadedResolver.resolveComponentFactory(component);
252+
} else {
253+
factory = this.componentFactoryResolver.resolveComponentFactory(component);
265254
}
255+
266256
return factory;
267257
}
268-
269258
}
270259

271260
function log(msg: string) {

tests/app/lazy-load-main.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Component } from "@angular/core";
2+
import { FirstComponent } from "./first.component";
3+
4+
@Component({
5+
template: `
6+
<Label text="Lazy load router"></Label>
7+
<page-router-outlet></page-router-outlet>
8+
`
9+
})
10+
export class LazyLoadMain {
11+
}
12+
13+
export const routes = [
14+
{ path: "", redirectTo: "first/lazy-load", pathMatch: "full" },
15+
{ path: "first/:id", component: FirstComponent },
16+
{ path: "second", loadChildren: () => require("./lazy-loaded.module")["SecondModule"] }
17+
];

tests/app/lazy-loaded.module.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NgModule } from '@angular/core';
2+
import { NativeScriptModule } from "nativescript-angular";
3+
import { NativeScriptRouterModule } from "nativescript-angular/router";
4+
5+
import { SecondComponent } from './second.component';
6+
7+
const routes = [
8+
{ path: ":id", component: SecondComponent },
9+
];
10+
11+
@NgModule({
12+
declarations: [SecondComponent],
13+
imports: [
14+
NativeScriptModule,
15+
NativeScriptRouterModule,
16+
NativeScriptRouterModule.forChild(routes)
17+
]
18+
})
19+
export class SecondModule { }
20+

tests/app/main.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import "ui/frame";
1616
import {HOOKS_LOG} from "./base.component";
1717
import {MultiPageMain, routes as multiPageRoutes} from "./multi-page-main.component";
1818
import {SinglePageMain, routes as singlePageRoutes} from "./single-page-main.component";
19+
import {LazyLoadMain, routes as lazyLoadRoutes} from "./lazy-load-main";
1920
import {FirstComponent} from "./first.component";
2021
import {SecondComponent} from "./second.component";
2122
import { OpaqueToken, NgModule } from "@angular/core";
@@ -42,6 +43,8 @@ const singlePageHooksLog = new BehaviorSubject([]);
4243
const singlePageHooksLogProvider = {provide: HOOKS_LOG, useValue: singlePageHooksLog};
4344
const multiPageHooksLog = new BehaviorSubject([]);
4445
const multiPageHooksLogProvider = {provide: HOOKS_LOG, useValue: multiPageHooksLog};
46+
const lazyLoadHooksLog = new BehaviorSubject([]);
47+
const lazyLoadHooksLogProvider = {provide: HOOKS_LOG, useValue: lazyLoadHooksLog};
4548

4649
@NgModule({
4750
bootstrap: [
@@ -107,6 +110,34 @@ class SinglePageModule {}
107110
})
108111
class MultiPageModule {}
109112

113+
@NgModule({
114+
bootstrap: [
115+
LazyLoadMain
116+
],
117+
declarations: [
118+
LazyLoadMain,
119+
FirstComponent,
120+
],
121+
entryComponents: [
122+
LazyLoadMain,
123+
],
124+
imports: [
125+
NativeScriptModule,
126+
NativeScriptFormsModule,
127+
NativeScriptRouterModule,
128+
NativeScriptRouterModule.forRoot(lazyLoadRoutes),
129+
],
130+
exports: [
131+
NativeScriptModule,
132+
NativeScriptFormsModule,
133+
NativeScriptRouterModule,
134+
],
135+
providers: [
136+
rootViewProvider,
137+
lazyLoadHooksLogProvider,
138+
]
139+
})
140+
class LazyLoadModule {}
110141

111142
application.start({
112143
create: (): Page => {
@@ -120,9 +151,10 @@ application.start({
120151

121152
//profiling.start('ng-bootstrap');
122153
console.log('BOOTSTRAPPING TEST APPS...');
123-
154+
124155
platform.bootstrapModule(SinglePageModule);
125156
platform.bootstrapModule(MultiPageModule);
157+
platform.bootstrapModule(LazyLoadModule);
126158
}
127159

128160
page.on('loaded', onLoadedHandler);

tests/e2e-tests/lazy-load-routing.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"use strict";
2+
var nsAppium = require("nativescript-dev-appium");
3+
4+
describe("lazy load routing", function () {
5+
this.timeout(360000);
6+
var driver;
7+
8+
before(function () {
9+
var caps = {
10+
browserName: '',
11+
'appium-version': '1.6',
12+
platformName: 'Android',
13+
platformVersion: '4.4.4',
14+
deviceName: 'Android Emulator',
15+
app: undefined // will be set later
16+
};
17+
driver = nsAppium.createDriver(caps);
18+
});
19+
20+
after(function () {
21+
return driver
22+
.quit()
23+
.finally(function () {
24+
console.log("Driver quit successfully");
25+
});
26+
});
27+
28+
it("loads default path", function () {
29+
return driver
30+
.waitForElementByAccessibilityId("first-lazy-load", 300000)
31+
.elementByAccessibilityId("first-lazy-load")
32+
.should.eventually.exist
33+
.text().should.eventually.equal("First: lazy-load")
34+
});
35+
36+
it("navigates and returns", function () {
37+
var expectedHookLog = [
38+
"first.init", // <-- load
39+
"second.init", // <-- forward (first component is not destroyed)
40+
"second.destroy"] // <-- back (first component is reused)
41+
.join(",");
42+
return driver
43+
.waitForElementByAccessibilityId("first-navigate-lazy-load", 300000)
44+
.elementByAccessibilityId("first-navigate-lazy-load")
45+
.should.eventually.exist
46+
.tap()
47+
.elementByAccessibilityId("second-lazy-load")
48+
.should.eventually.exist
49+
.text().should.eventually.equal("Second: lazy-load")
50+
.elementByAccessibilityId("second-navigate-back-lazy-load")
51+
.should.eventually.exist
52+
.tap()
53+
.elementByAccessibilityId("first-lazy-load")
54+
.should.eventually.exist
55+
.text().should.eventually.equal("First: lazy-load")
56+
.elementByAccessibilityId("hooks-log-lazy-load")
57+
.text().should.eventually.equal(expectedHookLog)
58+
});
59+
});

0 commit comments

Comments
 (0)