diff --git a/modules/aspnetcore-engine/src/interfaces/engine-options.ts b/modules/aspnetcore-engine/src/interfaces/engine-options.ts
index 790e278de..b51a8fbc0 100644
--- a/modules/aspnetcore-engine/src/interfaces/engine-options.ts
+++ b/modules/aspnetcore-engine/src/interfaces/engine-options.ts
@@ -2,8 +2,8 @@ import { IRequestParams } from "./request-params";
import { Type, NgModuleFactory, StaticProvider } from '@angular/core';
export interface IEngineOptions {
- appSelector: string;
- request: IRequestParams;
- ngModule: Type<{}> | NgModuleFactory<{}>;
- providers?: StaticProvider[];
-};
+ appSelector: string; // e.g.,
+ request: IRequestParams; // e.g., params
+ ngModule: Type<{}> | NgModuleFactory<{}>; // e.g., AppModule
+ providers?: StaticProvider[]; // StaticProvider[]
+}
diff --git a/modules/aspnetcore-engine/src/main.ts b/modules/aspnetcore-engine/src/main.ts
index db197040d..0aa73ad50 100644
--- a/modules/aspnetcore-engine/src/main.ts
+++ b/modules/aspnetcore-engine/src/main.ts
@@ -1,19 +1,80 @@
-import { Type, NgModuleFactory, NgModuleRef, ApplicationRef, CompilerFactory, Compiler } from '@angular/core';
-import { platformServer, platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server';
+import { Type, NgModuleFactory, CompilerFactory, Compiler } from '@angular/core';
+import { platformDynamicServer, BEFORE_APP_SERIALIZED, renderModuleFactory } from '@angular/platform-server';
import { ResourceLoader } from '@angular/compiler';
import { REQUEST, ORIGIN_URL } from './tokens';
import { FileLoader } from './file-loader';
import { IEngineOptions } from './interfaces/engine-options';
+import { DOCUMENT } from '@angular/platform-browser';
+
+/* @internal */
+export class UniversalData {
+ public static appNode = '';
+ public static title = '';
+ public static scripts = '';
+ public static styles = '';
+ public static meta = '';
+ public static links = '';
+}
+
+/* @internal */
+let appSelector = 'app-root'; // default
+
+/* @internal */
+function beforeAppSerialized(
+ doc: any /* TODO: type definition for Domino - DomAPI Spec (similar to "Document") */
+) {
+
+ return () => {
+ const STYLES = [];
+ const SCRIPTS = [];
+ const META = [];
+ const LINKS = [];
+
+ for (let i = 0; i < doc.head.children.length; i++) {
+ const element = doc.head.children[i];
+ const tagName = element.tagName.toUpperCase();
+
+ switch (tagName) {
+ case 'SCRIPT':
+ SCRIPTS.push(element.outerHTML);
+ break;
+ case 'STYLE':
+ STYLES.push(element.outerHTML);
+ break;
+ case 'LINK':
+ LINKS.push(element.outerHTML);
+ break;
+ case 'META':
+ META.push(element.outerHTML);
+ break;
+ default:
+ break;
+ }
+ }
+
+ UniversalData.title = doc.title;
+ UniversalData.appNode = doc.querySelector(appSelector).outerHTML;
+ UniversalData.scripts = SCRIPTS.join(' ');
+ UniversalData.styles = STYLES.join(' ');
+ UniversalData.meta = META.join(' ');
+ UniversalData.links = LINKS.join(' ');
+ };
+}
-import 'rxjs/add/operator/filter';
-import 'rxjs/add/operator/first';
export function ngAspnetCoreEngine(
options: IEngineOptions
): Promise<{ html: string, globals: { styles: string, title: string, meta: string, transferData?: {}, [key: string]: any } }> {
+ if (!options.appSelector) {
+ throw new Error(`appSelector is required! Pass in " appSelector: '' ", for your root App component.`);
+ }
+
+ // Grab the DOM "selector" from the passed in Template for example = "app-root"
+ appSelector = options.appSelector.substring(1, options.appSelector.indexOf('>'));
+
const compilerFactory: CompilerFactory = platformDynamicServer().injector.get(CompilerFactory);
const compiler: Compiler = compilerFactory.createCompiler([
{
@@ -34,133 +95,43 @@ export function ngAspnetCoreEngine(
options.providers = options.providers || [];
const extraProviders = options.providers.concat(
- options.providers,
- [
- {
- provide: INITIAL_CONFIG,
- useValue: {
- document: options.appSelector,
- url: options.request.url
- }
- },
- {
+ ...options.providers,
+ [{
provide: ORIGIN_URL,
useValue: options.request.origin
}, {
provide: REQUEST,
useValue: options.request.data.request
+ }, {
+ provide: BEFORE_APP_SERIALIZED,
+ useFactory: beforeAppSerialized, multi: true, deps: [ DOCUMENT ]
}
]
);
- const platform = platformServer(extraProviders);
-
getFactory(moduleOrFactory, compiler)
- .then((factory: NgModuleFactory<{}>) => {
-
- return platform.bootstrapModuleFactory(factory).then((moduleRef: NgModuleRef<{}>) => {
-
- const state: PlatformState = moduleRef.injector.get(PlatformState);
- const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
-
- appRef.isStable
- .filter((isStable: boolean) => isStable)
- .first()
- .subscribe(() => {
-
- // Fire the TransferState Cache
- const bootstrap = (<{ ngOnBootstrap?: Function }> moduleRef.instance).ngOnBootstrap;
- bootstrap && bootstrap();
-
- // The Document itself
- const AST_DOCUMENT = state.getDocument();
-
- // Strip out the Angular application
- const htmlDoc = state.renderToString();
-
- const APP_HTML = htmlDoc.substring(
- htmlDoc.indexOf('') + 6,
- htmlDoc.indexOf('')
- );
-
- // Strip out Styles / Meta-tags / Title
- // const STYLES = [];
- const META = [];
- const LINKS = [];
- let TITLE = '';
-
- let STYLES_STRING = htmlDoc.substring(
- htmlDoc.indexOf('`;
- // STYLES.push(styleTag);
- // }
-
- if (element.name === 'meta') {
- count = count + 1;
- let metaString = '\n`);
- }
-
- if (element.name === 'link') {
- let linkString = '\n`);
- }
- }
-
- // Return parsed App
- resolve({
- html: APP_HTML,
- globals: {
- styles: STYLES_STRING,
- title: TITLE,
- meta: META.join(' '),
- links: LINKS.join(' ')
- }
- });
-
- moduleRef.destroy();
-
- }, (err) => {
- reject(err);
- });
+ .then(factory => {
+ return renderModuleFactory(factory, {
+ document: options.appSelector,
+ url: options.request.url,
+ extraProviders: extraProviders
+ });
+ })
+ .then(() => {
+
+ resolve({
+ html: UniversalData.appNode,
+ globals: {
+ styles: UniversalData.styles,
+ title: UniversalData.title,
+ scripts: UniversalData.scripts,
+ meta: UniversalData.meta,
+ links: UniversalData.links
+ }
});
+ }, (err) => {
+ reject(err);
});
} catch (ex) {
@@ -168,14 +139,15 @@ export function ngAspnetCoreEngine(
}
});
-}
-/* ********************** Private / Internal ****************** */
+}
+/* @internal */
const factoryCacheMap = new Map, NgModuleFactory<{}>>();
function getFactory(
moduleOrFactory: Type<{}> | NgModuleFactory<{}>, compiler: Compiler
): Promise> {
+
return new Promise>((resolve, reject) => {
// If module has been compiled AoT
if (moduleOrFactory instanceof NgModuleFactory) {
diff --git a/tslint.json b/tslint.json
index fb9d90006..487c5186f 100644
--- a/tslint.json
+++ b/tslint.json
@@ -1,4 +1,5 @@
{
+ "defaultSeverity": "warning",
"rules": {
"comment-format": [true, "check-space"],
"class-name": true,