Skip to content

Commit 72be952

Browse files
author
vakrilov
committed
Fast livesync support for angular apps
1 parent f6c7036 commit 72be952

File tree

3 files changed

+128
-44
lines changed

3 files changed

+128
-44
lines changed

nativescript-angular/application.ts

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

@@ -28,6 +28,8 @@ import {NS_DIRECTIVES} from './directives';
2828
import {Page} from 'ui/page';
2929
import {TextView} from 'ui/text-view';
3030
import application = require('application');
31+
import {topmost, NavigationEntry} from "ui/frame";
32+
import {Observable} from "rxjs";
3133

3234
export type ProviderArray = Array<Type | Provider | any[]>;
3335

@@ -48,9 +50,20 @@ class ConsoleLogger {
4850
logGroupEnd() { }
4951
}
5052

53+
interface BootstrapParams {
54+
appComponentType: Type,
55+
customProviders?: ProviderArray,
56+
appOptions?: AppOptions
57+
}
58+
var bootstrapCache: BootstrapParams
59+
60+
var lastBootstrappedApp: WeakRef<ComponentRef<any>>;
61+
export const onBeforeLivesync = new EventEmitter<ComponentRef<any>>();
62+
export const onAfterLivesync = new EventEmitter<ComponentRef<any>>();
63+
5164
// See: https://github.com/angular/angular/commit/1745366530266d298306b995ecd23dabd8569e28
5265
export const NS_COMPILER_PROVIDERS: ProviderArray = [
53-
COMPILER_PROVIDERS,
66+
COMPILER_PROVIDERS,
5467
provide(CompilerConfig, {
5568
useFactory: (platformDirectives: any[], platformPipes: any[]) => {
5669
return new CompilerConfig({ platformDirectives, platformPipes });
@@ -101,7 +114,7 @@ export function bootstrap(appComponentType: any,
101114
// Http Setup
102115
// Since HTTP_PROVIDERS can be added with customProviders above, this must come after
103116
appProviders.push([
104-
provide(XSRFStrategy, { useValue: new NSXSRFStrategy()}),
117+
provide(XSRFStrategy, { useValue: new NSXSRFStrategy() }),
105118
NSFileSystem,
106119
provide(Http, {
107120
useFactory: (backend, options, nsFileSystem) => {
@@ -110,7 +123,7 @@ export function bootstrap(appComponentType: any,
110123
})
111124
]);
112125

113-
var platform = getPlatform();
126+
var platform = getPlatform();
114127
if (!isPresent(platform)) {
115128
platform = createPlatform(ReflectiveInjector.resolveAndCreate(platformProviders));
116129
}
@@ -120,46 +133,89 @@ export function bootstrap(appComponentType: any,
120133
return coreLoadAndBootstrap(appComponentType, appInjector);
121134
}
122135

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

128189
return new Promise((resolve, reject) => {
129-
application.start({
130-
create: (): Page => {
131-
let page = new Page();
132-
if (appOptions) {
133-
page.actionBarHidden = appOptions.startPageActionBarHidden;
134-
}
135-
136-
let onLoadedHandler = function (args) {
137-
page.off('loaded', onLoadedHandler);
138-
//profiling.stop('application-start');
139-
rendererLog('Page loaded');
140-
141-
//profiling.start('ng-bootstrap');
142-
rendererLog('BOOTSTRAPPING...');
143-
bootstrap(appComponentType, customProviders).then((appRef) => {
144-
//profiling.stop('ng-bootstrap');
145-
rendererLog('ANGULAR BOOTSTRAP DONE.');
146-
resolve(appRef);
147-
}, (err) => {
148-
rendererError('ERROR BOOTSTRAPPING ANGULAR');
149-
let errorMessage = err.message + "\n\n" + err.stack;
150-
rendererError(errorMessage);
151-
152-
let view = new TextView();
153-
view.text = errorMessage;
154-
page.content = view;
155-
reject(err);
156-
});
157-
}
158-
159-
page.on('loaded', onLoadedHandler);
160-
161-
return page;
162-
}
163-
});
190+
const navEntry = createNavigationEntry(bootstrapCache, resolve, reject, false);
191+
application.start(navEntry);
164192
})
165193
}
194+
195+
// Patch livesync
196+
const _baseLiveSync = global.__onLiveSync;
197+
global.__onLiveSync = function () {
198+
rendererLog("LiveSync Started")
199+
if (bootstrapCache) {
200+
onBeforeLivesync.next(lastBootstrappedApp ? lastBootstrappedApp.get() : null);
201+
202+
const frame = topmost();
203+
const newEntry = createNavigationEntry(
204+
bootstrapCache,
205+
compRef => onAfterLivesync.next(compRef),
206+
error => onAfterLivesync.error(error),
207+
true);
208+
209+
if (frame) {
210+
if (frame.currentPage && frame.currentPage.modal) {
211+
frame.currentPage.modal.closeModal();
212+
}
213+
frame.navigate(newEntry);
214+
}
215+
}
216+
else {
217+
_baseLiveSync();
218+
}
219+
}
220+
221+
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+

0 commit comments

Comments
 (0)