Skip to content

Commit 7b300b4

Browse files
authored
Merge pull request NativeScript#312 from NativeScript/fast-livesync
Fast livesync
2 parents d2e9545 + 72be952 commit 7b300b4

File tree

10 files changed

+210
-44
lines changed

10 files changed

+210
-44
lines changed

nativescript-angular/application.ts

Lines changed: 95 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import './polyfills/console';
88
import {rendererLog, rendererError} from "./trace";
99
import {SanitizationService} from '@angular/core/src/security';
1010
import {isPresent, Type, print} from '@angular/core/src/facade/lang';
11-
import {ReflectiveInjector, coreLoadAndBootstrap, createPlatform,
11+
import {ReflectiveInjector, coreLoadAndBootstrap, createPlatform, EventEmitter,
1212
getPlatform, assertPlatform, ComponentRef, PlatformRef, PLATFORM_DIRECTIVES, PLATFORM_PIPES} from '@angular/core';
1313
import {bind, provide, Provider} from '@angular/core/src/di';
1414

@@ -30,6 +30,8 @@ import {NS_DIRECTIVES} from './directives';
3030
import {Page} from 'ui/page';
3131
import {TextView} from 'ui/text-view';
3232
import application = require('application');
33+
import {topmost, NavigationEntry} from "ui/frame";
34+
import {Observable} from "rxjs";
3335

3436
export type ProviderArray = Array<Type | Provider | any[]>;
3537

@@ -50,9 +52,20 @@ class ConsoleLogger {
5052
logGroupEnd() { }
5153
}
5254

55+
interface BootstrapParams {
56+
appComponentType: Type,
57+
customProviders?: ProviderArray,
58+
appOptions?: AppOptions
59+
}
60+
var bootstrapCache: BootstrapParams
61+
62+
var lastBootstrappedApp: WeakRef<ComponentRef<any>>;
63+
export const onBeforeLivesync = new EventEmitter<ComponentRef<any>>();
64+
export const onAfterLivesync = new EventEmitter<ComponentRef<any>>();
65+
5366
// See: https://github.com/angular/angular/commit/1745366530266d298306b995ecd23dabd8569e28
5467
export const NS_COMPILER_PROVIDERS: ProviderArray = [
55-
COMPILER_PROVIDERS,
68+
COMPILER_PROVIDERS,
5669
provide(CompilerConfig, {
5770
useFactory: (platformDirectives: any[], platformPipes: any[]) => {
5871
return new CompilerConfig({ platformDirectives, platformPipes });
@@ -103,7 +116,7 @@ export function bootstrap(appComponentType: any,
103116
// Http Setup
104117
// Since HTTP_PROVIDERS can be added with customProviders above, this must come after
105118
appProviders.push([
106-
provide(XSRFStrategy, { useValue: new NSXSRFStrategy()}),
119+
provide(XSRFStrategy, { useValue: new NSXSRFStrategy() }),
107120
NSFileSystem,
108121
provide(Http, {
109122
useFactory: (backend, options, nsFileSystem) => {
@@ -112,7 +125,7 @@ export function bootstrap(appComponentType: any,
112125
})
113126
]);
114127

115-
var platform = getPlatform();
128+
var platform = getPlatform();
116129
if (!isPresent(platform)) {
117130
platform = createPlatform(ReflectiveInjector.resolveAndCreate(platformProviders));
118131
}
@@ -122,46 +135,89 @@ export function bootstrap(appComponentType: any,
122135
return coreLoadAndBootstrap(appComponentType, appInjector);
123136
}
124137

138+
function createNavigationEntry(params: BootstrapParams, resolve: (comp: ComponentRef<any>) => void, reject: (e: Error) => void, isReboot: boolean) {
139+
const navEntry: NavigationEntry = {
140+
create: (): Page => {
141+
let page = new Page();
142+
if (params.appOptions) {
143+
page.actionBarHidden = params.appOptions.startPageActionBarHidden;
144+
}
145+
146+
let onLoadedHandler = function (args) {
147+
page.off('loaded', onLoadedHandler);
148+
//profiling.stop('application-start');
149+
rendererLog('Page loaded');
150+
151+
//profiling.start('ng-bootstrap');
152+
rendererLog('BOOTSTRAPPING...');
153+
bootstrap(params.appComponentType, params.customProviders).then((compRef) => {
154+
//profiling.stop('ng-bootstrap');
155+
rendererLog('ANGULAR BOOTSTRAP DONE.');
156+
lastBootstrappedApp = new WeakRef(compRef);
157+
resolve(compRef);
158+
}, (err) => {
159+
rendererError('ERROR BOOTSTRAPPING ANGULAR');
160+
let errorMessage = err.message + "\n\n" + err.stack;
161+
rendererError(errorMessage);
162+
163+
let view = new TextView();
164+
view.text = errorMessage;
165+
page.content = view;
166+
reject(err);
167+
});
168+
}
169+
170+
page.on('loaded', onLoadedHandler);
171+
172+
return page;
173+
}
174+
};
175+
176+
if (isReboot) {
177+
navEntry.animated = false;
178+
navEntry.clearHistory = true;
179+
}
180+
181+
return navEntry;
182+
}
183+
125184
export function nativeScriptBootstrap(appComponentType: any, customProviders?: ProviderArray, appOptions?: AppOptions): Promise<ComponentRef<any>> {
185+
bootstrapCache = { appComponentType, customProviders, appOptions };
186+
126187
if (appOptions && appOptions.cssFile) {
127188
application.cssFile = appOptions.cssFile;
128189
}
129190

130191
return new Promise((resolve, reject) => {
131-
application.start({
132-
create: (): Page => {
133-
let page = new Page();
134-
if (appOptions) {
135-
page.actionBarHidden = appOptions.startPageActionBarHidden;
136-
}
137-
138-
let onLoadedHandler = function (args) {
139-
page.off('loaded', onLoadedHandler);
140-
//profiling.stop('application-start');
141-
rendererLog('Page loaded');
142-
143-
//profiling.start('ng-bootstrap');
144-
rendererLog('BOOTSTRAPPING...');
145-
bootstrap(appComponentType, customProviders).then((appRef) => {
146-
//profiling.stop('ng-bootstrap');
147-
rendererLog('ANGULAR BOOTSTRAP DONE.');
148-
resolve(appRef);
149-
}, (err) => {
150-
rendererError('ERROR BOOTSTRAPPING ANGULAR');
151-
let errorMessage = err.message + "\n\n" + err.stack;
152-
rendererError(errorMessage);
153-
154-
let view = new TextView();
155-
view.text = errorMessage;
156-
page.content = view;
157-
reject(err);
158-
});
159-
}
160-
161-
page.on('loaded', onLoadedHandler);
162-
163-
return page;
164-
}
165-
});
192+
const navEntry = createNavigationEntry(bootstrapCache, resolve, reject, false);
193+
application.start(navEntry);
166194
})
167195
}
196+
197+
// Patch livesync
198+
const _baseLiveSync = global.__onLiveSync;
199+
global.__onLiveSync = function () {
200+
rendererLog("LiveSync Started")
201+
if (bootstrapCache) {
202+
onBeforeLivesync.next(lastBootstrappedApp ? lastBootstrappedApp.get() : null);
203+
204+
const frame = topmost();
205+
const newEntry = createNavigationEntry(
206+
bootstrapCache,
207+
compRef => onAfterLivesync.next(compRef),
208+
error => onAfterLivesync.error(error),
209+
true);
210+
211+
if (frame) {
212+
if (frame.currentPage && frame.currentPage.modal) {
213+
frame.currentPage.modal.closeModal();
214+
}
215+
frame.navigate(newEntry);
216+
}
217+
}
218+
else {
219+
_baseLiveSync();
220+
}
221+
}
222+
223+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module.exports = function ($usbLiveSyncService) {
2-
$usbLiveSyncService.forceExecuteFullSync = true;
2+
$usbLiveSyncService.forceExecuteFullSync = false;
33
};

ng-sample/app/app.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
//profiling.start('application-start');
77

88
// this import should be first in order to load some required settings (like globals and reflect-metadata)
9-
import { nativeScriptBootstrap } from "nativescript-angular/application";
9+
import { Router } from "@angular/router";
10+
import { nativeScriptBootstrap, onAfterLivesync, onBeforeLivesync } from "nativescript-angular/application";
1011
import { NS_ROUTER_PROVIDERS as NS_ROUTER_PROVIDERS_DEPRECATED } from "nativescript-angular/router-deprecated";
1112
import { NS_ROUTER_PROVIDERS } from "nativescript-angular/router";
1213
import { HTTP_PROVIDERS } from "@angular/http";
1314
import { rendererTraceCategory, routerTraceCategory, listViewTraceCategory } from "nativescript-angular/trace";
1415

1516
import trace = require("trace");
1617
// trace.setCategories(rendererTraceCategory);
17-
trace.setCategories(routerTraceCategory);
18+
// trace.setCategories(routerTraceCategory);
1819
// trace.setCategories(listViewTraceCategory);
1920
trace.enable();
2021

@@ -28,6 +29,7 @@ import {HttpTest} from "./examples/http/http-test";
2829
import {ActionBarTest} from "./examples/action-bar/action-bar-test";
2930
import {ModalTest} from "./examples/modal/modal-test";
3031
import {PlatfromDirectivesTest} from "./examples/platform-directives/platform-directives-test";
32+
import {LivesyncApp, LivesyncTestRouterProviders} from "./examples/livesync-test/livesync-test-app";
3133

3234
// router-deprecated
3335
import {NavigationTest} from "./examples/router-deprecated/navigation-test";
@@ -39,13 +41,14 @@ import { RouterOutletAppComponent, RouterOutletRouterProviders} from "./examples
3941
import { PageRouterOutletAppComponent, PageRouterOutletRouterProviders } from "./examples/router/page-router-outlet-test"
4042
import { PageRouterOutletNestedAppComponent, PageRouterOutletNestedRouterProviders } from "./examples/router/page-router-outlet-nested-test"
4143

42-
//nativeScriptBootstrap(RendererTest);
44+
45+
nativeScriptBootstrap(RendererTest);
4346
//nativeScriptBootstrap(TabViewTest);
4447
//nativeScriptBootstrap(Benchmark);
4548
// nativeScriptBootstrap(ListTest);
4649
// nativeScriptBootstrap(ListTestAsync);
4750
//nativeScriptBootstrap(ImageTest);
48-
nativeScriptBootstrap(HttpTest, [HTTP_PROVIDERS]);
51+
// nativeScriptBootstrap(HttpTest, [HTTP_PROVIDERS]);
4952
//nativeScriptBootstrap(ActionBarTest, [NS_ROUTER_PROVIDERS_DEPRECATED], { startPageActionBarHidden: false });
5053
//nativeScriptBootstrap(ActionBarTest, [NS_ROUTER_PROVIDERS_DEPRECATED]);
5154
//nativeScriptBootstrap(ModalTest);
@@ -60,3 +63,28 @@ nativeScriptBootstrap(HttpTest, [HTTP_PROVIDERS]);
6063
// nativeScriptBootstrap(NavigationTest, [NS_ROUTER_PROVIDERS_DEPRECATED]);
6164
// nativeScriptBootstrap(RouterOutletTest, [NS_ROUTER_PROVIDERS_DEPRECATED]);
6265
// nativeScriptBootstrap(LoginTest, [NS_ROUTER_PROVIDERS_DEPRECATED]);
66+
67+
68+
// Livesync test
69+
// var cahcedUrl: string;
70+
// onBeforeLivesync.subscribe((compRef) => {
71+
// console.log("------- onBeforeLivesync");
72+
// if (compRef) {
73+
// const router = <Router>compRef.injector.get(Router);
74+
// cahcedUrl = router.url;
75+
// console.log("------- Caching URL: " + cahcedUrl);
76+
// }
77+
// });
78+
79+
// onAfterLivesync.subscribe((compRef) => {
80+
// console.log("------- onAfterLivesync cachedUrl:");
81+
// const router = <Router>compRef.injector.get(Router);
82+
// router.events.subscribe(e => console.log(e.toString()));
83+
// if (router && cahcedUrl) {
84+
// setTimeout(() => { router.navigateByUrl(cahcedUrl); }, 0);
85+
// }
86+
// });
87+
88+
// nativeScriptBootstrap(LivesyncApp, [LivesyncTestRouterProviders]);
89+
90+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.title {
2+
font-size: 30;
3+
margin: 16;
4+
color: darkblue;
5+
}
6+
7+
button {
8+
horizontal-align: center;
9+
margin: 10;
10+
}
11+
12+
stack-layout {
13+
background-color: lightgreen;
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Component } from "@angular/core";
2+
import { ROUTER_DIRECTIVES } from '@angular/router';
3+
import { NS_ROUTER_DIRECTIVES} from "nativescript-angular/router"
4+
5+
@Component({
6+
selector: "first",
7+
directives: [ROUTER_DIRECTIVES, NS_ROUTER_DIRECTIVES],
8+
styleUrls: ["examples/livesync-test/first/first.component.css"],
9+
templateUrl: "examples/livesync-test/first/first.component.xml"
10+
})
11+
export class FirstComponent {
12+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<StackLayout>
2+
<Label text="First Page" class="title"></Label>
3+
<Button text="Go to second" nsRouterLink="second"></Button>
4+
</StackLayout>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Component } from "@angular/core";
2+
import { RouterConfig } from '@angular/router';
3+
import { NS_ROUTER_DIRECTIVES, nsProvideRouter} from "nativescript-angular/router"
4+
5+
import {FirstComponent} from "./first/first.component";
6+
import {SecondComponent} from "./second/second.component";
7+
8+
@Component({
9+
selector: 'livesync-app-test',
10+
directives: [NS_ROUTER_DIRECTIVES],
11+
template: `<page-router-outlet></page-router-outlet>`
12+
})
13+
export class LivesyncApp { }
14+
15+
const routes: RouterConfig = [
16+
{ path: "", component: FirstComponent },
17+
{ path: "second", component: SecondComponent },
18+
];
19+
20+
export const LivesyncTestRouterProviders = [
21+
nsProvideRouter(routes, { enableTracing: false })
22+
];
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.title {
2+
font-size: 30;
3+
margin: 16;
4+
color: darkgreen;
5+
}
6+
7+
button {
8+
horizontal-align: center;
9+
margin: 10;
10+
}
11+
12+
stack-layout {
13+
background-color: lightblue;
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Component } from "@angular/core";
2+
import { ROUTER_DIRECTIVES } from '@angular/router';
3+
import { NS_ROUTER_DIRECTIVES} from "nativescript-angular/router"
4+
5+
@Component({
6+
selector: "second",
7+
directives: [ROUTER_DIRECTIVES, NS_ROUTER_DIRECTIVES],
8+
styleUrls: ["examples/livesync-test/second/second.component.css"],
9+
templateUrl: "examples/livesync-test/second/second.component.xml"
10+
})
11+
export class SecondComponent {
12+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<StackLayout>
2+
<Label text="Second Page" class="title"></Label>
3+
<Button text="Go to first" nsRouterLink=""></Button>
4+
</StackLayout>

0 commit comments

Comments
 (0)