Skip to content

Commit

Permalink
feat(util): system.js ng-module loader
Browse files Browse the repository at this point in the history
system.js ng-module loader
  • Loading branch information
danbucholtz committed Mar 2, 2017
1 parent 1dede23 commit beabe32
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/util/module-loader.ts
@@ -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>;
};
77 changes: 77 additions & 0 deletions src/util/ng-module-loader.ts
@@ -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;
});
}

0 comments on commit beabe32

Please sign in to comment.