-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(util): system.js ng-module loader
system.js ng-module loader
- Loading branch information
1 parent
1dede23
commit beabe32
Showing
2 changed files
with
126 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { ComponentFactoryResolver, Injectable, Injector, OpaqueToken, Type } from '@angular/core'; | ||
import { NgModuleLoader } from './ng-module-loader'; | ||
|
||
export const LAZY_LOADED_TOKEN = new OpaqueToken('LZYCMP'); | ||
|
||
/** | ||
* @private | ||
*/ | ||
@Injectable() | ||
export class ModuleLoader { | ||
|
||
constructor( | ||
private _ngModuleLoader: NgModuleLoader, | ||
private _injector: Injector) {} | ||
|
||
|
||
load(modulePath: string): Promise<LoadedModule> { | ||
console.time(`ModuleLoader, load: ${modulePath}'`); | ||
|
||
const splitString = modulePath.split(SPLITTER); | ||
|
||
return this._ngModuleLoader.load(splitString[0], splitString[1]) | ||
.then(loadedModule => { | ||
console.timeEnd(`ModuleLoader, load: ${modulePath}'`); | ||
const ref = loadedModule.create(this._injector); | ||
|
||
return { | ||
componentFactoryResolver: ref.componentFactoryResolver, | ||
component: ref.injector.get(LAZY_LOADED_TOKEN) | ||
}; | ||
}); | ||
} | ||
} | ||
|
||
const SPLITTER = '#'; | ||
|
||
|
||
/** | ||
* @private | ||
*/ | ||
export function provideModuleLoader(ngModuleLoader: NgModuleLoader, injector: Injector) { | ||
return new ModuleLoader(ngModuleLoader, injector); | ||
} | ||
|
||
|
||
export interface LoadedModule { | ||
componentFactoryResolver: ComponentFactoryResolver; | ||
component: Type<any>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { Compiler, Injectable, NgModuleFactory, Optional } from '@angular/core'; | ||
|
||
const FACTORY_CLASS_SUFFIX = 'NgFactory'; | ||
|
||
/** | ||
* Configuration for NgModuleLoader. | ||
* token. | ||
* | ||
* @experimental | ||
*/ | ||
export abstract class NgModuleLoaderConfig { | ||
/** | ||
* Prefix to add when computing the name of the factory module for a given module name. | ||
*/ | ||
factoryPathPrefix: string; | ||
|
||
/** | ||
* Suffix to add when computing the name of the factory module for a given module name. | ||
*/ | ||
factoryPathSuffix: string; | ||
} | ||
|
||
const DEFAULT_CONFIG: NgModuleLoaderConfig = { | ||
factoryPathPrefix: '', | ||
factoryPathSuffix: '.ngfactory', | ||
}; | ||
|
||
/** | ||
* NgModuleFactoryLoader that uses SystemJS to load NgModuleFactory | ||
*/ | ||
@Injectable() | ||
export class NgModuleLoader { | ||
private _config: NgModuleLoaderConfig; | ||
|
||
constructor(private _compiler: Compiler, @Optional() config?: NgModuleLoaderConfig) { | ||
this._config = config || DEFAULT_CONFIG; | ||
} | ||
|
||
load(modulePath: string, ngModuleExport: string) { | ||
const offlineMode = this._compiler instanceof Compiler; | ||
return offlineMode ? loadPrecompiledFactory(this._config, modulePath, ngModuleExport) : loadAndCompile(this._compiler, modulePath, ngModuleExport); | ||
} | ||
} | ||
|
||
|
||
function loadAndCompile(compiler: Compiler, modulePath: string, ngModuleExport: string): Promise<NgModuleFactory<any>> { | ||
if (!ngModuleExport) { | ||
ngModuleExport = 'default'; | ||
} | ||
|
||
return System.import(modulePath) | ||
.then((rawModule: any) => { | ||
const module = rawModule[ngModuleExport]; | ||
if (!module) { | ||
throw new Error(`Module ${modulePath} does not export ${ngModuleExport}`); | ||
} | ||
return compiler.compileModuleAsync(module); | ||
}); | ||
} | ||
|
||
|
||
function loadPrecompiledFactory(config: NgModuleLoaderConfig, modulePath: string, ngModuleExport: string): Promise<NgModuleFactory<any>> { | ||
let factoryClassSuffix = FACTORY_CLASS_SUFFIX; | ||
if (ngModuleExport === undefined) { | ||
ngModuleExport = 'default'; | ||
factoryClassSuffix = ''; | ||
} | ||
|
||
return System.import(config.factoryPathPrefix + modulePath + config.factoryPathSuffix) | ||
.then((rawModule: any) => { | ||
const ngModuleFactory = rawModule[ngModuleExport + factoryClassSuffix]; | ||
if (!ngModuleFactory) { | ||
throw new Error(`Module ${modulePath} does not export ${ngModuleExport}`); | ||
} | ||
return ngModuleFactory; | ||
}); | ||
} |