Skip to content

Commit beabe32

Browse files
committed
feat(util): system.js ng-module loader
system.js ng-module loader
1 parent 1dede23 commit beabe32

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

src/util/module-loader.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { ComponentFactoryResolver, Injectable, Injector, OpaqueToken, Type } from '@angular/core';
2+
import { NgModuleLoader } from './ng-module-loader';
3+
4+
export const LAZY_LOADED_TOKEN = new OpaqueToken('LZYCMP');
5+
6+
/**
7+
* @private
8+
*/
9+
@Injectable()
10+
export class ModuleLoader {
11+
12+
constructor(
13+
private _ngModuleLoader: NgModuleLoader,
14+
private _injector: Injector) {}
15+
16+
17+
load(modulePath: string): Promise<LoadedModule> {
18+
console.time(`ModuleLoader, load: ${modulePath}'`);
19+
20+
const splitString = modulePath.split(SPLITTER);
21+
22+
return this._ngModuleLoader.load(splitString[0], splitString[1])
23+
.then(loadedModule => {
24+
console.timeEnd(`ModuleLoader, load: ${modulePath}'`);
25+
const ref = loadedModule.create(this._injector);
26+
27+
return {
28+
componentFactoryResolver: ref.componentFactoryResolver,
29+
component: ref.injector.get(LAZY_LOADED_TOKEN)
30+
};
31+
});
32+
}
33+
}
34+
35+
const SPLITTER = '#';
36+
37+
38+
/**
39+
* @private
40+
*/
41+
export function provideModuleLoader(ngModuleLoader: NgModuleLoader, injector: Injector) {
42+
return new ModuleLoader(ngModuleLoader, injector);
43+
}
44+
45+
46+
export interface LoadedModule {
47+
componentFactoryResolver: ComponentFactoryResolver;
48+
component: Type<any>;
49+
};

src/util/ng-module-loader.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Compiler, Injectable, NgModuleFactory, Optional } from '@angular/core';
2+
3+
const FACTORY_CLASS_SUFFIX = 'NgFactory';
4+
5+
/**
6+
* Configuration for NgModuleLoader.
7+
* token.
8+
*
9+
* @experimental
10+
*/
11+
export abstract class NgModuleLoaderConfig {
12+
/**
13+
* Prefix to add when computing the name of the factory module for a given module name.
14+
*/
15+
factoryPathPrefix: string;
16+
17+
/**
18+
* Suffix to add when computing the name of the factory module for a given module name.
19+
*/
20+
factoryPathSuffix: string;
21+
}
22+
23+
const DEFAULT_CONFIG: NgModuleLoaderConfig = {
24+
factoryPathPrefix: '',
25+
factoryPathSuffix: '.ngfactory',
26+
};
27+
28+
/**
29+
* NgModuleFactoryLoader that uses SystemJS to load NgModuleFactory
30+
*/
31+
@Injectable()
32+
export class NgModuleLoader {
33+
private _config: NgModuleLoaderConfig;
34+
35+
constructor(private _compiler: Compiler, @Optional() config?: NgModuleLoaderConfig) {
36+
this._config = config || DEFAULT_CONFIG;
37+
}
38+
39+
load(modulePath: string, ngModuleExport: string) {
40+
const offlineMode = this._compiler instanceof Compiler;
41+
return offlineMode ? loadPrecompiledFactory(this._config, modulePath, ngModuleExport) : loadAndCompile(this._compiler, modulePath, ngModuleExport);
42+
}
43+
}
44+
45+
46+
function loadAndCompile(compiler: Compiler, modulePath: string, ngModuleExport: string): Promise<NgModuleFactory<any>> {
47+
if (!ngModuleExport) {
48+
ngModuleExport = 'default';
49+
}
50+
51+
return System.import(modulePath)
52+
.then((rawModule: any) => {
53+
const module = rawModule[ngModuleExport];
54+
if (!module) {
55+
throw new Error(`Module ${modulePath} does not export ${ngModuleExport}`);
56+
}
57+
return compiler.compileModuleAsync(module);
58+
});
59+
}
60+
61+
62+
function loadPrecompiledFactory(config: NgModuleLoaderConfig, modulePath: string, ngModuleExport: string): Promise<NgModuleFactory<any>> {
63+
let factoryClassSuffix = FACTORY_CLASS_SUFFIX;
64+
if (ngModuleExport === undefined) {
65+
ngModuleExport = 'default';
66+
factoryClassSuffix = '';
67+
}
68+
69+
return System.import(config.factoryPathPrefix + modulePath + config.factoryPathSuffix)
70+
.then((rawModule: any) => {
71+
const ngModuleFactory = rawModule[ngModuleExport + factoryClassSuffix];
72+
if (!ngModuleFactory) {
73+
throw new Error(`Module ${modulePath} does not export ${ngModuleExport}`);
74+
}
75+
return ngModuleFactory;
76+
});
77+
}

0 commit comments

Comments
 (0)