refactor: HMR and webpack improvements (#7462)

* chore: update project

* refactor: clear module-name cache on orientation

* feat: add custom component in qualifiers app

* feat: enable HMR for custom components

* refactor: remove redundant check

* chore: clean console.log
This commit is contained in:
Alexander Vakrilov
2019-07-08 11:11:14 +03:00
committed by GitHub
parent d8ef044469
commit 8756b3da16
77 changed files with 349 additions and 168 deletions

View File

@ -2,13 +2,17 @@
// Uncomment to add recyclerview-v7 dependency
//dependencies {
// compile 'com.android.support:recyclerview-v7:+'
// implementation 'com.android.support:recyclerview-v7:+'
//}
// If you want to add something to be applied before applying plugins' include.gradle files
// e.g. project.ext.googlePlayServicesVersion = "15.0.1"
// create a file named before-plugins.gradle in the current directory and place it there
android {
defaultConfig {
minSdkVersion 17
generatedDensities = []
applicationId = "org.nativescript.animation"
}
aaptOptions {
additionalParameters "--no-version-vectors"

View File

@ -10,10 +10,6 @@
android:largeScreens="true"
android:xlargeScreens="true"/>
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="__APILEVEL__"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
@ -28,7 +24,7 @@
<activity
android:name="com.tns.NativeScriptActivity"
android:label="@string/title_activity_kimera"
android:configChanges="keyboardHidden|orientation|screenSize"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode"
android:theme="@style/LaunchScreenTheme">
<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

View File

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">TestApp</string>
<string name="title_activity_kimera">TestApp</string>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>

View File

@ -1,5 +1,4 @@
.root-footer {
horizontal-align: middle;
color: black;
background-color: lightgreen
}

View File

@ -1,5 +1,4 @@
.root-footer {
horizontal-align: middle;
color: black;
background-color: lightpink;
}

View File

@ -1,3 +1,7 @@
import * as application from "tns-core-modules/application";
import { setCategories, categories, enable } from "tns-core-modules/trace";
setCategories(categories.Livesync);
enable();
application.run({ moduleName: "app-root" });

View File

@ -0,0 +1,5 @@
.custom-component {
color: navy;
font-weight: bold;
font-size: 20;
}

View File

@ -0,0 +1,5 @@
.custom-component {
color: darkolivegreen;
font-weight: bold;
font-size: 20;
}

View File

@ -0,0 +1,3 @@
export function onLoaded() {
console.log("---> Custom component LANDSCAPE loaded");
}

View File

@ -0,0 +1,3 @@
<StackLayout class="p-20" loaded="onLoaded">
<Label text="CUSTOM COMPONENT - LANDSCAPE" class="custom-component" />
</StackLayout>

View File

@ -0,0 +1,3 @@
export function onLoaded() {
console.log("---> Custom component DEFAULT loaded");
}

View File

@ -0,0 +1,3 @@
<StackLayout class="p-20" loaded="onLoaded">
<Label text="CUSTOM COMPONENT - DEFAULT" class="custom-component" />
</StackLayout>

View File

@ -0,0 +1,3 @@
import { fromObject } from "tns-core-modules/data/observable";
export const vm = fromObject({ prop: "property from VM" });

View File

@ -1,7 +1,17 @@
export function onNavigatedTo(args) {
console.log("---> [LANDSCAPE] onNavigatedTo");
import { topmost } from "tns-core-modules/ui/frame";
import { vm } from "./main-page-vm";
export function onNavigatingTo(args) {
console.log("---> [LANDSCAPE] onNavigatingTo");
args.object.page.bindingContext = vm;
}
export function tap(args) {
console.log("---> [LANDSCAPE] tap");
}
export function navigate(args) {
console.log("---> [LANDSCAPE] navigate");
topmost().navigate("other/other-page");
}

View File

@ -1,7 +1,13 @@
<Page navigatedTo="onNavigatedTo">
<Page navigatingTo="onNavigatingTo" xmlns:cc="components">
<StackLayout class="page-content">
<Label text="This is LANDSACPE page" />
<Button text="hey there" tap="navigate" />
<Button text="tap" tap="tap" />
<Button text="navigate" tap="navigate" />
<Label text="{{ prop }}" />
<cc:my-component />
</StackLayout>
</Page>

View File

@ -1,7 +1,17 @@
export function onNavigatedTo(args) {
console.log("---> [DEFAULT] onNavigatedTo");
import { topmost } from "tns-core-modules/ui/frame";
import { vm } from "./main-page-vm";
export function onNavigatingTo(args) {
console.log("---> [DEFAULT] onNavigatingTo");
args.object.page.bindingContext = vm;
}
export function tap(args) {
console.log("---> [DEFAULT] tap");
}
export function navigate(args) {
console.log("---> [DEFAULT] navigate");
topmost().navigate("other/other-page");
}

View File

@ -1,7 +1,13 @@
<Page navigatedTo="onNavigatedTo">
<Page navigatingTo="onNavigatingTo" xmlns:cc="components">
<StackLayout class="page-content">
<Label text="This is DEFAULT page" />
<Button text="hey there" tap="navigate" />
<Button text="tap" tap="tap" />
<Button text="navigate" tap="navigate" />
<Label text="{{ prop }}" />
<cc:my-component />
</StackLayout>
</Page>

View File

@ -0,0 +1,4 @@
.page-content {
padding: 20;
background-color: lightblue;
}

View File

@ -0,0 +1,4 @@
.page-content {
padding: 20;
background-color: lightcoral;
}

View File

@ -0,0 +1,15 @@
import { topmost } from "tns-core-modules/ui/frame";
export function onNavigatedTo(args) {
console.log("---> [LANDSCAPE other] onNavigatedTo");
}
export function tap(args) {
console.log("---> [LANDSCAPE other] tap");
}
export function navigate(args) {
console.log("---> [LANDSCAPE other] navigate");
topmost().navigate("main/main-page");
}

View File

@ -0,0 +1,12 @@
<Page navigatedTo="onNavigatedTo" xmlns:cc="components">
<StackLayout class="page-content">
<Label text="This is LANDSACPE other page" />
<Button text="tap" tap="tap" />
<Button text="navigate" tap="navigate" />
<cc:my-component />
</StackLayout>
</Page>

View File

@ -0,0 +1,15 @@
import { topmost } from "tns-core-modules/ui/frame";
export function onNavigatedTo(args) {
console.log("---> [DEFAULT other] onNavigatedTo");
}
export function tap(args) {
console.log("---> [DEFAULT other] tap");
}
export function navigate(args) {
console.log("---> [DEFAULT other] navigate");
topmost().navigate("main/main-page");
}

View File

@ -0,0 +1,11 @@
<Page navigatedTo="onNavigatedTo" xmlns:cc="components">
<StackLayout class="page-content">
<Label text="This is DEFAULT other page" />
<Button text="tap" tap="tap" />
<Button text="navigate" tap="navigate" />
<cc:my-component />
</StackLayout>
</Page>

View File

@ -2,7 +2,5 @@
"android": {
"v8Flags": "--expose_gc"
},
"main": "app.js",
"name": "tns-template-hello-world-ts",
"version": "3.4.0"
"main": "app.js"
}

View File

@ -179,25 +179,14 @@ module.exports = env => {
unitTesting,
appFullPath,
projectRoot,
registerModules: /(root|page|app)(\.(land|port|phone|tablet|minH\d+|minW\d+|minWH\d+))?\.(xml|css|js|ts|scss)$/ // NB: MODIFIED
}
},
].filter(loader => !!loader)
},
{
test: /(page|app)(\.(land|port|phone|tablet|minH\d+|minW\d+|minWH\d+))?\.ts$/,
use: "nativescript-dev-webpack/script-hot-loader"
},
{
test: /\.(css|scss)$/,
use: "nativescript-dev-webpack/style-hot-loader"
},
{
test: /\.(html|xml)$/,
use: "nativescript-dev-webpack/markup-hot-loader"
test: /\.(ts|css|scss|less|html|xml)$/,
use: "nativescript-dev-webpack/hmr/hot-loader"
},
{ test: /\.(html|xml)$/, use: "nativescript-dev-webpack/xml-namespace-loader" },

View File

@ -153,7 +153,7 @@ export function test_loadWithAttributes() {
}
export function test_parse_ShouldNotCrashWithoutExports() {
const xml = global.loadModule("xml-declaration/mainPage.xml");
const xml = global.loadModule("xml-declaration/mainPage.xml", true);
var v: view.View = builder.parse(xml);
TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";");
@ -831,7 +831,7 @@ export function test_NonExistingElementInTemplateError() {
}
export function test_EventInTemplate() {
var pageCode = global.loadModule("xml-declaration/template-builder-tests/event-in-template");
var pageCode = global.loadModule("xml-declaration/template-builder-tests/event-in-template", true);
var notified = false;
pageCode.test = (args) => {
notified = true;
@ -854,7 +854,7 @@ export function test_EventInTemplate() {
}
export function test_EventInCodelessFragment() {
var pageCode = global.loadModule("./xml-declaration/template-builder-tests/event-in-codeless-fragment");
var pageCode = global.loadModule("./xml-declaration/template-builder-tests/event-in-codeless-fragment", true);
var notified = false;
pageCode.setCallback((args) => {

View File

@ -185,7 +185,7 @@ export var test_XmlParser_NamespacesTest = function () {
};
export function test_MultiParserTemplate() {
const xml = global.loadModule("xml-parser-tests/itemTemplates.xml");
const xml = global.loadModule("xml-parser-tests/itemTemplates.xml", true);
const view: any = builder.parse(xml);
TKUnit.assertNotNull(view.items);

View File

@ -1,5 +1,7 @@
// Required by TypeScript compiler
require("./ts-helpers");
import "./ts-helpers";
import "./register-module-helpers";
// This method iterates all the keys in the source exports object and copies them to the destination exports one.
// Note: the method will not check for naming collisions and will override any already existing entries in the destination exports.
@ -12,110 +14,6 @@ global.moduleMerge = function (sourceExports: any, destExports: any) {
import * as timerModule from "../timer";
import * as dialogsModule from "../ui/dialogs";
type ModuleLoader = (name?: string) => any;
const modules: Map<string, ModuleLoader> = new Map<string, ModuleLoader>();
(<any>global).moduleResolvers = [global.require];
global.registerModule = function (name: string, loader: ModuleLoader): void {
// console.log("[global.registerModule]", name);
modules.set(name, loader);
};
global._unregisterModule = function (name: string): void {
// console.log("[global._unregisterModule]", name);
modules.delete(name);
};
interface Context {
keys(): string[];
(key: string): any;
}
interface ExtensionMap {
[originalFileExtension: string]: string;
}
const defaultExtensionMap = {
".js": ".js",
".ts": ".js",
".css": ".css",
".scss": ".css",
".less": ".css",
".sass": ".css",
".xml": ".xml"
};
global.registerWebpackModules = function registerWebpackModules(context: Context, extensionMap: ExtensionMap = {}) {
context.keys().forEach(key => {
const extDotIndex = key.lastIndexOf(".");
const base = key.substr(0, extDotIndex);
const originalExt = key.substr(extDotIndex);
const registerExt = extensionMap[originalExt] || defaultExtensionMap[originalExt] || originalExt;
// We prefer source files for webpack scenarios before compilation leftovers,
// e. g. if we get a .js and .ts for the same module, the .js is probably the compiled version of the .ts file,
// so we register the .ts with higher priority, similar is the case with us preferring the .scss to .css
const isSourceFile = originalExt !== registerExt;
const registerName = base + registerExt;
if (registerName.startsWith("./") && registerName.endsWith(".js")) {
const jsNickNames = [
// This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc);
registerName.substr(2, registerName.length - 5),
// This is for supporting module names like "./main/main-page"
registerName.substr(0, registerName.length - 3),
// This is for supporting module names like "main/main-page.js"
registerName.substr(2),
];
jsNickNames.forEach(jsNickName => {
if (isSourceFile || !global.moduleExists(jsNickName)) {
global.registerModule(jsNickName, () => context(key));
}
});
} else if (registerName.startsWith("./")) {
const moduleNickNames = [
// This is for supporting module names like "main/main-page.xml"
registerName.substr(2),
];
moduleNickNames.forEach(moduleNickName => {
if (!global.moduleExists(moduleNickName)) {
global.registerModule(moduleNickName, () => context(key));
}
});
}
if (isSourceFile || !global.moduleExists(registerName)) {
global.registerModule(registerName, () => context(key));
}
});
};
global.moduleExists = function (name: string): boolean {
return modules.has(name);
};
global.loadModule = function (name: string): any {
const loader = modules.get(name);
if (loader) {
return loader(name);
}
for (let resolver of (<any>global).moduleResolvers) {
const result = resolver(name);
if (result) {
modules.set(name, () => result);
return result;
}
}
};
global.getRegisteredModules = function (): string[] {
return Array.from(modules.keys());
};
global.zonedCallback = function (callback: Function): Function {
if ((<any>global).zone) {
// Zone v0.5.* style callback wrapping

View File

@ -0,0 +1,127 @@
type ModuleLoader = (name?: string) => any;
interface Context {
keys(): string[];
(key: string): any;
}
interface ExtensionMap {
[originalFileExtension: string]: string;
}
const modules: Map<string, { moduleId: string, loader: ModuleLoader }> = new Map<string, { moduleId: string, loader: ModuleLoader }>();
const modulesLoadedForUI = new Set<string>();
const defaultExtensionMap: ExtensionMap = {
".js": ".js",
".ts": ".js",
".css": ".css",
".scss": ".css",
".less": ".css",
".sass": ".css",
".xml": ".xml"
};
// Cast to <any> because moduleResolvers is read-only in definitions
(<any>global).moduleResolvers = [global.require];
global.registerModule = function (name: string, loader: ModuleLoader): void {
modules.set(name, { loader, moduleId: name });
};
global._unregisterModule = function _unregisterModule(name: string): void {
modules.delete(name);
};
global._isModuleLoadedForUI = function _isModuleLoadedForUI(moduleName: string): boolean {
return modulesLoadedForUI.has(moduleName);
};
global.registerWebpackModules = function registerWebpackModules(context: Context, extensionMap: ExtensionMap = {}) {
context.keys().forEach(moduleId => {
const extDotIndex = moduleId.lastIndexOf(".");
const base = moduleId.substr(0, extDotIndex);
const originalExt = moduleId.substr(extDotIndex);
const registerExt = extensionMap[originalExt] || defaultExtensionMap[originalExt] || originalExt;
// We prefer source files for webpack scenarios before compilation leftovers,
// e. g. if we get a .js and .ts for the same module, the .js is probably the compiled version of the .ts file,
// so we register the .ts with higher priority, similar is the case with us preferring the .scss to .css
const isSourceFile = originalExt !== registerExt;
const registerName = base + registerExt;
const registerWithName = (nickName: string) => {
modules.set(nickName, {
moduleId,
loader: () => {
return context(moduleId);
}
});
};
if (registerName.startsWith("./") && registerName.endsWith(".js")) {
const jsNickNames = [
// This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc);
registerName.substr(2, registerName.length - 5),
// This is for supporting module names like "./main/main-page"
registerName.substr(0, registerName.length - 3),
// This is for supporting module names like "main/main-page.js"
registerName.substr(2),
];
jsNickNames.forEach(jsNickName => {
if (isSourceFile || !global.moduleExists(jsNickName)) {
registerWithName(jsNickName);
}
});
} else if (registerName.startsWith("./")) {
const moduleNickNames = [
// This is for supporting module names like "main/main-page.xml"
registerName.substr(2),
];
moduleNickNames.forEach(moduleNickName => {
if (!global.moduleExists(moduleNickName)) {
registerWithName(moduleNickName);
}
});
}
if (isSourceFile || !global.moduleExists(registerName)) {
registerWithName(registerName);
}
});
};
global.moduleExists = function moduleExists(name: string): boolean {
return modules.has(name);
};
global.loadModule = function loadModule(name: string, isUIModule: boolean = false): any {
const moduleInfo = modules.get(name);
if (moduleInfo) {
if (isUIModule) {
modulesLoadedForUI.add(moduleInfo.moduleId);
}
const result = moduleInfo.loader(name);
if (result.enableAutoAccept) {
result.enableAutoAccept();
}
return result;
}
for (let resolver of (<any>global).moduleResolvers) {
const result = resolver(name);
if (result) {
modules.set(name, { moduleId: name, loader: () => result });
return result;
}
}
};
global.getRegisteredModules = function getRegisteredModules(): string[] {
return Array.from(modules.keys());
};

View File

@ -68,3 +68,6 @@ export function _setResolver(resolver: ModuleNameResolver) {
}
appCommonModule.on("livesync", args => clearCache());
appCommonModule.on("orientationChanged", args => {
resolverInstance = undefined;
});

View File

@ -14,12 +14,14 @@ declare namespace NodeJS {
interface Global {
android?: any;
require(id: string): any;
moduleMerge(sourceExports: any, destExports: any): void;
registerModule(name: string, loader: ((name: string) => any)): void;
_unregisterModule(name: string): void;
/**
* Register all modules from a webpack context.
* The context is one created using the following webpack utility:
* https://webpack.github.io/docs/context.html
* https://webpack.js.org/guides/dependency-management/#requirecontext
*
* The extension map is optional, modules in the webpack context will have their original file extension (e.g. may be ".ts" or ".scss" etc.),
* while the built-in module builders in {N} will look for ".js", ".css" or ".xml" files. Adding a map such as:
@ -27,9 +29,10 @@ declare namespace NodeJS {
* { ".ts": ".js" }
* ```
* Will resolve lookups for .js to the .ts file.
* By default scss, and ts files are mapped.
* By default scss and ts files are mapped.
*/
registerWebpackModules(context: { keys(): string[], (key: string): any }, extensionMap?: { [originalFileExtension: string]: string });
/**
* The NativeScript XML builder, style-scope, application modules use various resources such as:
* app.css, page.xml files and modules during the application life-cycle.
@ -43,15 +46,34 @@ declare namespace NodeJS {
* By default the only member of the array is global.require, as last resort - if it fails to find a module it will throw.
*/
readonly moduleResolvers: ModuleResolver[];
loadModule(name: string): any;
/**
*
* @param name Name of the module to be loaded
* @param loadForUI Is this UI module is being loaded for UI from tns-core-modules/builder.
* Xml, css/scss and js/ts modules for pages and custom-components should load with loadForUI=true.
* Passing "true" will enable the HMR mechanics this module. Default value is false.
*/
loadModule(name: string, loadForUI? : boolean): any;
/**
* Checks if the module has been registered with `registerModule` or in `registerWebpackModules`
* @param name Name of the module
*/
moduleExists(name: string): boolean;
moduleMerge(sourceExports: any, destExports: any): void;
getRegisteredModules(): string[];
_unregisterModule(name: string): void;
_isModuleLoadedForUI(moduleName: string): boolean;
onGlobalLayoutListener: any;
zonedCallback(callback: Function): Function;
Reflect?: any;
Deprecated(target: Object, key?: string | symbol, descriptor?: any): any;
Experimental(target: Object, key?: string | symbol, descriptor?: any): any;
__native?: any;
__inspector?: any;
__extends: any;

View File

@ -59,7 +59,7 @@ export const createViewFromEntry = profile("createViewFromEntry", (entry: ViewEn
} else if (entry.moduleName) {
const moduleName = sanitizeModuleName(entry.moduleName);
const resolvedCodeModuleName = resolveModuleName(moduleName, ""); //`${moduleName}.xml`;
let moduleExports = resolvedCodeModuleName ? global.loadModule(resolvedCodeModuleName) : null;
let moduleExports = resolvedCodeModuleName ? global.loadModule(resolvedCodeModuleName, true) : null;
if (moduleExports && moduleExports.createPage) {
// Exports has a createPage() method
@ -87,7 +87,7 @@ function loadInternal(moduleName: string, moduleExports: any): ComponentModule {
const resolvedXmlModule = resolveModuleName(moduleName, "xml");
if (resolvedXmlModule) {
const text = global.loadModule(resolvedXmlModule);
const text = global.loadModule(resolvedXmlModule, true);
componentModule = parseInternal(text, moduleExports, resolvedXmlModule, moduleName);
}
@ -129,7 +129,7 @@ function loadCustomComponent(componentNamespace: string, componentName?: string,
let subExports = context;
if (resolvedCodeModuleName) {
// Component has registered code module.
subExports = global.loadModule(resolvedCodeModuleName);
subExports = global.loadModule(resolvedCodeModuleName, true);
}
// Pass the parent page down the chain in case of custom components nested on many levels. Use the context for piggybacking.

View File

@ -36,14 +36,16 @@ const createComponentInstance = profile("createComponentInstance", (elementName:
try {
if (typeof namespace === "string") {
resolvedModuleName = resolveModuleName(namespace, "");
instanceModule = global.loadModule(resolvedModuleName, true);
} else {
// load module from tns-core-modules/ui or mapped paths
resolvedModuleName = MODULES[elementName] || UI_PATH +
(elementName.toLowerCase().indexOf("layout") !== -1 ? "layouts/" : "") +
elementName.split(/(?=[A-Z])/).join("-").toLowerCase();
}
instanceModule = global.loadModule(resolvedModuleName);
// don't register core modules for HMR self-accept
instanceModule = global.loadModule(resolvedModuleName, false);
}
// Get the component type from module.
const instanceType = instanceModule[elementName] || Object;
@ -64,7 +66,7 @@ const getComponentModuleExports = profile("getComponentModuleExports", (instance
if (codeFileAttribute) {
const resolvedCodeFileModule = resolveModuleName(sanitizeModuleName(codeFileAttribute), "");
if (resolvedCodeFileModule) {
moduleExports = global.loadModule(resolvedCodeFileModule);
moduleExports = global.loadModule(resolvedCodeFileModule, true);
(<any>instance).exports = moduleExports;
} else {
throw new Error(`Code file with path "${codeFileAttribute}" cannot be found! Looking for webpack module with name "${resolvedCodeFileModule}"`);

View File

@ -192,6 +192,18 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
return true;
}
// Handle script/markup changes in custom components by falling back to page refresh
if (viewMatchesModuleContext(this, context, ["markup", "script"]) &&
this.page &&
this.page.frame) {
if (traceEnabled()) {
traceWrite(`Change Handled: Changing ${context.type} for ${this} inside ${this.page}`, traceCategories.Livesync);
}
return this.page.frame._handleLivesync({ type: context.type, path: this.page._moduleName });
}
return false;
}

View File

@ -9,7 +9,7 @@ import { createViewFromEntry } from "../builder";
import { profile } from "../../profiling";
import { frameStack, topmost as frameStackTopmost, _pushInFrameStack, _popFromFrameStack, _removeFromFrameStack } from "./frame-stack";
import { getModuleName } from "../../utils/utils";
import { sanitizeModuleName } from "../builder/module-name-sanitizer";
export * from "../core/view";
export enum NavigationType {
@ -608,7 +608,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
traceWrite(`Change Handled: Replacing page ${context.path}`, traceCategories.Livesync);
this.replacePage(context);
this.replacePage(context.path);
return true;
}
@ -653,9 +653,9 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
return true;
}
protected replacePage(context: ModuleContext): void {
protected replacePage(pagePath: string): void {
const currentBackstackEntry = this._currentEntry;
const contextModuleName = getModuleName(context.path);
const contextModuleName = sanitizeModuleName(pagePath);
const newPage = <Page>createViewFromEntry({ moduleName: contextModuleName });
const newBackstackEntry: BackstackEntry = {

View File

@ -83,7 +83,7 @@ class CSSSource {
let appRelativeUri = CSSSource.pathRelativeToApp(uri);
try {
const cssOrAst = global.loadModule(appRelativeUri);
const cssOrAst = global.loadModule(appRelativeUri, true);
if (cssOrAst) {
if (typeof cssOrAst === "string") {
// raw-loader

View File

@ -1,5 +1,6 @@
import * as types from "./types";
import { dispatchToMainThread, isMainThread } from "./mainthread-helper";
import { sanitizeModuleName } from "../ui/builder/module-name-sanitizer";
export * from "./mainthread-helper";
@ -35,7 +36,7 @@ export function convertString(value: any): any {
export function getModuleName(path: string): string {
let moduleName = path.replace("./", "");
return moduleName.substring(0, moduleName.lastIndexOf("."));
return sanitizeModuleName(moduleName);
}
export module layoutCommon {