diff --git a/tns-core-modules/globals/globals.ts b/tns-core-modules/globals/globals.ts index a20af54d80..9e31f7b117 100644 --- a/tns-core-modules/globals/globals.ts +++ b/tns-core-modules/globals/globals.ts @@ -34,6 +34,31 @@ global.registerModule = function(name: string, loader: ModuleLoader): void { modules.set(name, loader); } +interface Context { + keys(): string[]; + (key: string): any; +} +interface ExtensionMap { + [originalFileExtension: string]: string; +} + +const defaultExtensionMap = { ".js": ".js", ".ts": ".js", ".css": ".css", ".scss": ".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]; + const registerName = base + registerExt; + if (registerName.startsWith("./") && registerName.endsWith(".js")) { + const jsNickName = registerName.substr(2, registerName.length - 5); + // This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc); + global.registerModule(jsNickName, () => context(key)); + } + global.registerModule(registerName, () => context(key)); + }); +} + global.moduleExists = function(name: string): boolean { return modules.has(name); } diff --git a/tns-core-modules/module.d.ts b/tns-core-modules/module.d.ts index c339fe8a5a..5fd5d161da 100644 --- a/tns-core-modules/module.d.ts +++ b/tns-core-modules/module.d.ts @@ -14,6 +14,20 @@ declare namespace NodeJS { android?: any; require(id: string): any; registerModule(name: string, loader: ((name: string) => any)): 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 + * + * 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: + * ``` + * { ".ts": ".js" } + * ``` + * Will resolve lookups for .js to the .ts file. + * 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. diff --git a/tns-core-modules/ui/builder/builder.ts b/tns-core-modules/ui/builder/builder.ts index 2676538a72..5be1744371 100644 --- a/tns-core-modules/ui/builder/builder.ts +++ b/tns-core-modules/ui/builder/builder.ts @@ -82,13 +82,13 @@ function loadCustomComponent(componentPath: string, componentName?: string, attr if (xmlFilePath) { // Custom components with XML - var jsFilePath = resolveFileName(fullComponentPathFilePathWithoutExt, "js"); var subExports = context; if (global.moduleExists(moduleName)) { // Component has registered code module. subExports = global.loadModule(moduleName); } else { + var jsFilePath = resolveFileName(fullComponentPathFilePathWithoutExt, "js"); if (jsFilePath) { // Component has code file. subExports = global.loadModule(jsFilePath) diff --git a/tns-core-modules/ui/builder/component-builder/component-builder.ts b/tns-core-modules/ui/builder/component-builder/component-builder.ts index fa1b0aed22..8462352322 100644 --- a/tns-core-modules/ui/builder/component-builder/component-builder.ts +++ b/tns-core-modules/ui/builder/component-builder/component-builder.ts @@ -11,6 +11,8 @@ import { profile } from "../../../profiling"; import * as debugModule from "../../../utils/debug"; import * as platform from "../../../platform"; +import * as filesystem from "../../../file-system"; + const UI_PATH = "ui/"; const MODULES = { "TabViewItem": "ui/tab-view", @@ -119,6 +121,13 @@ const applyComponentCss = profile("applyComponentCss", (instance: View, moduleNa if (typeof (instance).addCssFile === "function") {//instance instanceof Page) { if (moduleNamePath && !cssApplied) { + + const appPath = filesystem.knownFolders.currentApp().path; + const cssPathRelativeToApp = (moduleNamePath.startsWith(appPath) ? "./" + moduleNamePath.substr(appPath.length + 1) : moduleNamePath) + ".css"; + if (global.moduleExists(cssPathRelativeToApp)) { + (instance).addCssFile(cssPathRelativeToApp); + } + let cssFilePath = resolveFileName(moduleNamePath, "css"); if (cssFilePath) { (instance).addCssFile(cssFilePath); diff --git a/tns-core-modules/ui/styling/style-scope.ts b/tns-core-modules/ui/styling/style-scope.ts index 40783fe694..aaacb618f2 100644 --- a/tns-core-modules/ui/styling/style-scope.ts +++ b/tns-core-modules/ui/styling/style-scope.ts @@ -508,7 +508,7 @@ export class StyleScope { } this._reset(); - let parsedCssSelectors = cssString ? CSSSource.fromSource(cssString, this._keyframes, cssFileName) : CSSSource.fromFile(cssFileName, this._keyframes); + let parsedCssSelectors = cssString ? CSSSource.fromSource(cssString, this._keyframes, cssFileName) : CSSSource.fromURI(cssFileName, this._keyframes); this._css = this._css + parsedCssSelectors.source; this._localCssSelectors.push.apply(this._localCssSelectors, parsedCssSelectors.selectors); this._localCssSelectorVersion++;