Skip to content

Commit 9af7f3d

Browse files
author
Alexander Vakrilov
authored
Merge pull request #544 from NativeScript/module-factory-loader
Add ns-module-factory-loader
2 parents 6b33ee5 + 0f6b740 commit 9af7f3d

File tree

6 files changed

+123
-30
lines changed

6 files changed

+123
-30
lines changed

Diff for: nativescript-angular/nativescript.module.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ import {
1717
NgModule, NO_ERRORS_SCHEMA,
1818
} from "@angular/core";
1919
import {
20-
defaultPageProvider, defaultFrameProvider, defaultDeviceProvider
20+
defaultPageProvider,
21+
defaultFrameProvider,
22+
defaultDeviceProvider
2123
} from "./platform-providers";
2224
import { NS_DIRECTIVES } from "./directives";
2325

@@ -36,6 +38,7 @@ export function errorHandlerFactory() {
3638
defaultFrameProvider,
3739
defaultPageProvider,
3840
defaultDeviceProvider,
41+
3942
NativeScriptRootRenderer,
4043
{ provide: RootRenderer, useClass: NativeScriptRootRenderer },
4144
NativeScriptRenderer,

Diff for: nativescript-angular/platform-common.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
EventEmitter,
1616
Provider,
1717
Sanitizer,
18-
OpaqueToken,
18+
OpaqueToken
1919
} from "@angular/core";
2020

2121
// Work around a TS bug requiring an import of OpaqueToken without using it

Diff for: nativescript-angular/router.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NgModule, ModuleWithProviders, NO_ERRORS_SCHEMA } from "@angular/core";
1+
import { NgModule, ModuleWithProviders, NO_ERRORS_SCHEMA, NgModuleFactoryLoader } from "@angular/core";
22
import { RouterModule, Routes, ExtraOptions } from "@angular/router";
33
import { LocationStrategy, PlatformLocation } from "@angular/common";
44
import { NSRouterLink } from "./router/ns-router-link";
@@ -11,6 +11,7 @@ export { routerTraceCategory } from "./trace";
1111
export { PageRoute } from "./router/page-router-outlet";
1212
export { RouterExtensions } from "./router/router-extensions";
1313
import { NativeScriptModule } from "./nativescript.module";
14+
import { NsModuleFactoryLoader } from "./router/ns-module-factory-loader";
1415

1516
@NgModule({
1617
declarations: [
@@ -39,7 +40,14 @@ import { NativeScriptModule } from "./nativescript.module";
3940
})
4041
export class NativeScriptRouterModule {
4142
static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders {
42-
return RouterModule.forRoot(routes, config);
43+
let moduleWithProviders = RouterModule.forRoot(routes, config);
44+
45+
// Override the stock SystemJsNgModuleLoader
46+
moduleWithProviders.providers.push(
47+
{ provide: NgModuleFactoryLoader, useClass: NsModuleFactoryLoader },
48+
);
49+
50+
return moduleWithProviders;
4351
}
4452

4553
static forChild(routes: Routes): ModuleWithProviders {
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import {
2+
Injectable,
3+
Compiler,
4+
NgModuleFactory,
5+
NgModuleFactoryLoader
6+
} from "@angular/core";
7+
8+
import { path, knownFolders } from "file-system";
9+
10+
declare var System: any;
11+
const SEPARATOR = "#";
12+
const FACTORY_CLASS_SUFFIX = "NgFactory";
13+
const FACTORY_PATH_SUFFIX = ".ngfactory";
14+
15+
@Injectable()
16+
export class NsModuleFactoryLoader implements NgModuleFactoryLoader {
17+
private offlineMode: boolean;
18+
19+
constructor(private compiler: Compiler) {
20+
this.offlineMode = compiler instanceof Compiler;
21+
}
22+
23+
load(path: string): Promise<NgModuleFactory<any>> {
24+
let {modulePath, exportName} = this.splitPath(path);
25+
26+
if (this.offlineMode) {
27+
return this.loadFactory(modulePath, exportName);
28+
} else {
29+
return this.loadAndCompile(modulePath, exportName);
30+
}
31+
}
32+
33+
private loadFactory(modulePath: string, exportName: string): Promise<NgModuleFactory<any>> {
34+
modulePath = factoryModulePath(modulePath);
35+
exportName = factoryExportName(exportName);
36+
37+
return System.import(modulePath)
38+
.then((module: any) => module[exportName])
39+
.then((factory: any) => checkNotEmpty(factory, modulePath, exportName));
40+
}
41+
42+
private loadAndCompile(modulePath: string, exportName: string): Promise<NgModuleFactory<any>> {
43+
modulePath = getAbsolutePath(modulePath);
44+
45+
let loadedModule = require(modulePath)[exportName];
46+
checkNotEmpty(loadedModule, modulePath, exportName);
47+
48+
return Promise.resolve(this.compiler.compileModuleAsync(loadedModule));
49+
}
50+
51+
private splitPath(path: string): {modulePath: string, exportName: string} {
52+
let [modulePath, exportName] = path.split(SEPARATOR);
53+
54+
if (typeof exportName === "undefined") {
55+
exportName = "default";
56+
}
57+
58+
return {modulePath, exportName};
59+
}
60+
}
61+
62+
function getAbsolutePath(relativePath: string) {
63+
return path.normalize(path.join(knownFolders.currentApp().path, relativePath));
64+
}
65+
66+
function factoryModulePath(modulePath) {
67+
return `${modulePath}${FACTORY_PATH_SUFFIX}`;
68+
}
69+
70+
function factoryExportName(exportName) {
71+
return exportName === "default" ?
72+
exportName :
73+
`${exportName}${FACTORY_CLASS_SUFFIX}`;
74+
}
75+
76+
function checkNotEmpty(value: any, modulePath: string, exportName: string): any {
77+
if (!value) {
78+
throw new Error(`Cannot find '${exportName}' in '${modulePath}'`);
79+
}
80+
81+
return value;
82+
}

Diff for: tests/app/lazy-load-main.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ export class LazyLoadMain {
1313
export const routes = [
1414
{ path: "", redirectTo: "first/lazy-load", pathMatch: "full" },
1515
{ path: "first/:id", component: FirstComponent },
16-
{ path: "second", loadChildren: () => require("./lazy-loaded.module")["SecondModule"] }
16+
{ path: "second", loadChildren: "./lazy-loaded.module#SecondModule" }
1717
];

Diff for: tests/app/main.ts

+25-25
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@
22
import { NativeScriptModule, platformNativeScriptDynamic } from "nativescript-angular/platform";
33
import { NativeScriptRouterModule } from "nativescript-angular/router";
44
import { NativeScriptFormsModule } from "nativescript-angular/forms";
5-
import {AppComponent} from "./app.component";
6-
import {GestureComponent} from "./snippets/gestures.component";
7-
import {LayoutsComponent} from "./snippets/layouts.component";
8-
import {IconFontComponent} from "./snippets/icon-font.component";
9-
import {APP_ROOT_VIEW} from "nativescript-angular/platform-providers";
10-
import {Page} from "ui/page";
11-
import {StackLayout} from "ui/layouts/stack-layout";
5+
import { AppComponent } from "./app.component";
6+
import { GestureComponent } from "./snippets/gestures.component";
7+
import { LayoutsComponent } from "./snippets/layouts.component";
8+
import { IconFontComponent } from "./snippets/icon-font.component";
9+
import { APP_ROOT_VIEW } from "nativescript-angular/platform-providers";
10+
import { Page } from "ui/page";
11+
import { StackLayout } from "ui/layouts/stack-layout";
1212

1313
import * as application from "application";
1414
import "ui/styling/style";
1515
import "ui/frame";
16-
import {HOOKS_LOG} from "./base.component";
17-
import {MultiPageMain, routes as multiPageRoutes} from "./multi-page-main.component";
18-
import {SinglePageMain, routes as singlePageRoutes} from "./single-page-main.component";
19-
import {LazyLoadMain, routes as lazyLoadRoutes} from "./lazy-load-main";
20-
import {FirstComponent} from "./first.component";
21-
import {SecondComponent} from "./second.component";
16+
import { HOOKS_LOG } from "./base.component";
17+
import { MultiPageMain, routes as multiPageRoutes } from "./multi-page-main.component";
18+
import { SinglePageMain, routes as singlePageRoutes } from "./single-page-main.component";
19+
import { LazyLoadMain, routes as lazyLoadRoutes } from "./lazy-load-main";
20+
import { FirstComponent } from "./first.component";
21+
import { SecondComponent } from "./second.component";
2222
import { OpaqueToken, NgModule } from "@angular/core";
2323

24-
import {PageNavigationApp} from "./snippets/navigation/page-outlet";
25-
import {NavigationApp} from "./snippets/navigation/router-outlet";
24+
import { PageNavigationApp } from "./snippets/navigation/page-outlet";
25+
import { NavigationApp } from "./snippets/navigation/router-outlet";
2626

2727
import { rendererTraceCategory, routerTraceCategory } from "nativescript-angular/trace";
2828

29-
import {BehaviorSubject} from "rxjs";
29+
import { BehaviorSubject } from "rxjs";
3030

3131
import trace = require("trace");
3232
// trace.setCategories(rendererTraceCategory + "," + routerTraceCategory);
@@ -36,15 +36,15 @@ trace.enable();
3636
// nativeScriptBootstrap(GestureComponent);
3737
// nativeScriptBootstrap(LayoutsComponent);
3838
// nativeScriptBootstrap(IconFontComponent);
39-
const platform = platformNativeScriptDynamic({bootInExistingPage: true});
39+
const platform = platformNativeScriptDynamic({ bootInExistingPage: true });
4040
const root = new StackLayout();
41-
const rootViewProvider = {provide: APP_ROOT_VIEW, useValue: root};
41+
const rootViewProvider = { provide: APP_ROOT_VIEW, useValue: root };
4242
const singlePageHooksLog = new BehaviorSubject([]);
43-
const singlePageHooksLogProvider = {provide: HOOKS_LOG, useValue: singlePageHooksLog};
43+
const singlePageHooksLogProvider = { provide: HOOKS_LOG, useValue: singlePageHooksLog };
4444
const multiPageHooksLog = new BehaviorSubject([]);
45-
const multiPageHooksLogProvider = {provide: HOOKS_LOG, useValue: multiPageHooksLog};
45+
const multiPageHooksLogProvider = { provide: HOOKS_LOG, useValue: multiPageHooksLog };
4646
const lazyLoadHooksLog = new BehaviorSubject([]);
47-
const lazyLoadHooksLogProvider = {provide: HOOKS_LOG, useValue: lazyLoadHooksLog};
47+
const lazyLoadHooksLogProvider = { provide: HOOKS_LOG, useValue: lazyLoadHooksLog };
4848

4949
@NgModule({
5050
bootstrap: [
@@ -76,7 +76,7 @@ const lazyLoadHooksLogProvider = {provide: HOOKS_LOG, useValue: lazyLoadHooksLog
7676
singlePageHooksLogProvider,
7777
]
7878
})
79-
class SinglePageModule {}
79+
class SinglePageModule { }
8080

8181
@NgModule({
8282
bootstrap: [
@@ -108,7 +108,7 @@ class SinglePageModule {}
108108
multiPageHooksLogProvider,
109109
]
110110
})
111-
class MultiPageModule {}
111+
class MultiPageModule { }
112112

113113
@NgModule({
114114
bootstrap: [
@@ -137,14 +137,14 @@ class MultiPageModule {}
137137
lazyLoadHooksLogProvider,
138138
]
139139
})
140-
class LazyLoadModule {}
140+
class LazyLoadModule { }
141141

142142
application.start({
143143
create: (): Page => {
144144
const page = new Page();
145145
page.content = root;
146146

147-
let onLoadedHandler = function(args) {
147+
let onLoadedHandler = function (args) {
148148
page.off('loaded', onLoadedHandler);
149149
//profiling.stop('application-start');
150150
console.log('Page loaded');

0 commit comments

Comments
 (0)