refactor(HMR): apply changes in application styles at runtime

This commit is contained in:
Vasil Chimev
2018-12-05 14:24:24 +02:00
parent 42a1491e6e
commit 790bcfb470
7 changed files with 49 additions and 57 deletions

View File

@@ -32,7 +32,14 @@ export function hasLaunched(): boolean {
export { Observable }; export { Observable };
import { UnhandledErrorEventData, iOSApplication, AndroidApplication, CssChangedEventData, LoadAppCSSEventData } from "."; import {
AndroidApplication,
CssChangedEventData,
getRootView,
iOSApplication,
LoadAppCSSEventData,
UnhandledErrorEventData
} from "./application";
export { UnhandledErrorEventData, CssChangedEventData, LoadAppCSSEventData }; export { UnhandledErrorEventData, CssChangedEventData, LoadAppCSSEventData };
@@ -73,8 +80,19 @@ export function setApplication(instance: iOSApplication | AndroidApplication): v
export function livesync(context?: HmrContext) { export function livesync(context?: HmrContext) {
events.notify(<EventData>{ eventName: "livesync", object: app }); events.notify(<EventData>{ eventName: "livesync", object: app });
const liveSyncCore = global.__onLiveSyncCore; const liveSyncCore = global.__onLiveSyncCore;
if (liveSyncCore) { let reapplyAppCss = false
liveSyncCore(context);
if (context) {
const fullFileName = getCssFileName();
const fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".") + 1);
const extensions = ["css", "scss"];
reapplyAppCss = extensions.some(ext => context.module === fileName.concat(ext));
}
if (reapplyAppCss) {
getRootView()._onCssStateChange();
} else if (liveSyncCore) {
liveSyncCore();
} }
} }

View File

@@ -18,7 +18,6 @@ export * from "./application-common";
import { createViewFromEntry } from "../ui/builder"; import { createViewFromEntry } from "../ui/builder";
import { ios as iosView, View } from "../ui/core/view"; import { ios as iosView, View } from "../ui/core/view";
import { Frame, NavigationEntry } from "../ui/frame"; import { Frame, NavigationEntry } from "../ui/frame";
import { loadCss } from "../ui/styling/style-scope";
import * as utils from "../utils/utils"; import * as utils from "../utils/utils";
import { profile, level as profilingLevel, Level } from "../profiling"; import { profile, level as profilingLevel, Level } from "../profiling";
@@ -162,7 +161,7 @@ class IOSApplication implements IOSApplicationDefinition {
this.setWindowContent(args.root); this.setWindowContent(args.root);
} else { } else {
this._window = UIApplication.sharedApplication.delegate.window; this._window = UIApplication.sharedApplication.delegate.window;
} }
} }
@profile @profile
@@ -226,21 +225,10 @@ class IOSApplication implements IOSApplicationDefinition {
} }
} }
public _onLivesync(context?: HmrContext): void { public _onLivesync(): void {
let executeLivesync = true; // If view can't handle livesync set window controller.
// HMR has context, livesync does not if (!this._rootView._onLivesync()) {
if (context) { this.setWindowContent();
if (context.module === getCssFileName()) {
loadCss(context.module);
this._rootView._onCssStateChange();
executeLivesync = false;
}
}
if (executeLivesync) {
// If view can't handle livesync set window controller.
if (!this._rootView._onLivesync()) {
this.setWindowContent();
}
} }
} }
@@ -276,8 +264,8 @@ exports.ios = iosApp;
setApplication(iosApp); setApplication(iosApp);
// attach on global, so it can be overwritten in NativeScript Angular // attach on global, so it can be overwritten in NativeScript Angular
(<any>global).__onLiveSyncCore = function __onLiveSyncCore(context?: HmrContext) { (<any>global).__onLiveSyncCore = function () {
iosApp._onLivesync(context); iosApp._onLivesync();
} }
let mainEntry: NavigationEntry; let mainEntry: NavigationEntry;
@@ -391,4 +379,4 @@ global.__onLiveSync = function __onLiveSync(context?: HmrContext) {
} }
livesync(context); livesync(context);
} }

View File

@@ -52,7 +52,7 @@ declare namespace NodeJS {
__inspector?: any; __inspector?: any;
__extends: any; __extends: any;
__onLiveSync: (context?: { type: string, module: string }) => void; __onLiveSync: (context?: { type: string, module: string }) => void;
__onLiveSyncCore: (context?: { type: string, module: string }) => void; __onLiveSyncCore: () => void;
__onUncaughtError: (error: NativeScriptError) => void; __onUncaughtError: (error: NativeScriptError) => void;
TNS_WEBPACK?: boolean; TNS_WEBPACK?: boolean;
__requireOverride?: (name: string, dir: string) => any; __requireOverride?: (name: string, dir: string) => any;

View File

@@ -17,7 +17,6 @@ import {
_updateTransitions, _reverseTransitions, _clearEntry, _clearFragment, AnimationType _updateTransitions, _reverseTransitions, _clearEntry, _clearFragment, AnimationType
} from "./fragment.transitions"; } from "./fragment.transitions";
import { loadCss } from "../styling/style-scope";
import { profile } from "../../profiling"; import { profile } from "../../profiling";
// TODO: Remove this and get it from global to decouple builder for angular // TODO: Remove this and get it from global to decouple builder for angular
@@ -83,24 +82,13 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener {
return attachStateChangeListener; return attachStateChangeListener;
} }
export function reloadPage(context?: HmrContext): void { export function reloadPage(): void {
const activity = application.android.foregroundActivity; const activity = application.android.foregroundActivity;
const callbacks: AndroidActivityCallbacks = activity[CALLBACKS]; const callbacks: AndroidActivityCallbacks = activity[CALLBACKS];
const rootView: View = callbacks.getRootView(); const rootView: View = callbacks.getRootView();
let executeLivesync = true; if (!rootView || !rootView._onLivesync()) {
// HMR has context, livesync does not callbacks.resetActivityContent(activity);
if (context) {
if (context.module === application.getCssFileName()) {
loadCss(context.module);
rootView._onCssStateChange();
executeLivesync = false;
}
}
if (executeLivesync) {
if (!rootView || !rootView._onLivesync()) {
callbacks.resetActivityContent(activity);
}
} }
} }
@@ -481,19 +469,19 @@ export class Frame extends FrameBase {
switch (this.actionBarVisibility) { switch (this.actionBarVisibility) {
case "never": case "never":
return false; return false;
case "always": case "always":
return true; return true;
default: default:
if (page.actionBarHidden !== undefined) { if (page.actionBarHidden !== undefined) {
return !page.actionBarHidden; return !page.actionBarHidden;
} }
if (this._android && this._android.showActionBar !== undefined) { if (this._android && this._android.showActionBar !== undefined) {
return this._android.showActionBar; return this._android.showActionBar;
} }
return true; return true;
} }
} }
@@ -858,14 +846,14 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
// parent while its supposed parent believes it properly removed its children; in order to "force" the child to // parent while its supposed parent believes it properly removed its children; in order to "force" the child to
// lose its parent we temporarily add it to the parent, and then remove it (addViewInLayout doesn't trigger layout pass) // lose its parent we temporarily add it to the parent, and then remove it (addViewInLayout doesn't trigger layout pass)
const nativeView = page.nativeViewProtected; const nativeView = page.nativeViewProtected;
if (nativeView != null) { if (nativeView != null) {
const parentView = nativeView.getParent(); const parentView = nativeView.getParent();
if (parentView instanceof android.view.ViewGroup) { if (parentView instanceof android.view.ViewGroup) {
if (parentView.getChildCount() === 0) { if (parentView.getChildCount() === 0) {
parentView.addViewInLayout(nativeView, -1, new org.nativescript.widgets.CommonLayoutParams()); parentView.addViewInLayout(nativeView, -1, new org.nativescript.widgets.CommonLayoutParams());
} }
parentView.removeView(nativeView); parentView.removeView(nativeView);
} }
} }
@@ -1210,4 +1198,4 @@ export function setActivityCallbacks(activity: android.support.v7.app.AppCompatA
export function setFragmentCallbacks(fragment: android.support.v4.app.Fragment): void { export function setFragmentCallbacks(fragment: android.support.v4.app.Fragment): void {
fragment[CALLBACKS] = new FragmentCallbacksImplementation(); fragment[CALLBACKS] = new FragmentCallbacksImplementation();
} }

View File

@@ -103,8 +103,11 @@ export class PageBase extends ContentView implements PageDefinition {
public onNavigatingTo(context: any, isBackNavigation: boolean, bindingContext?: any) { public onNavigatingTo(context: any, isBackNavigation: boolean, bindingContext?: any) {
this._navigationContext = context; this._navigationContext = context;
if (!this._cssState.isSelectorsLatestVersionApplied()) { if (isBackNavigation && this._styleScope) {
this._onCssStateChange(); this._styleScope.ensureSelectors();
if (!this._cssState.isSelectorsLatestVersionApplied()) {
this._onCssStateChange();
}
} }
//https://github.com/NativeScript/NativeScript/issues/731 //https://github.com/NativeScript/NativeScript/issues/731

View File

@@ -307,7 +307,7 @@ function onLiveSync(args: applicationCommon.CssChangedEventData): void {
loadCss(applicationCommon.getCssFileName()); loadCss(applicationCommon.getCssFileName());
} }
export const loadCss = profile(`"style-scope".loadCss`, (cssFile: string) => { const loadCss = profile(`"style-scope".loadCss`, (cssFile: string) => {
if (!cssFile) { if (!cssFile) {
return undefined; return undefined;
} }
@@ -369,12 +369,7 @@ export class CssState {
} }
public isSelectorsLatestVersionApplied(): boolean { public isSelectorsLatestVersionApplied(): boolean {
if (this._appliedSelectorsVersion && this.view._styleScope) { return this.view._styleScope._getSelectorsVersion() === this._appliedSelectorsVersion;
this.view._styleScope.ensureSelectors();
return this.view._styleScope._getSelectorsVersion() === this._appliedSelectorsVersion;
} else {
return true;
}
} }
public onLoaded(): void { public onLoaded(): void {

View File

@@ -26,4 +26,4 @@
"tns-core-modules/*": ["tns-core-modules/*"] "tns-core-modules/*": ["tns-core-modules/*"]
} }
} }
} }