/// // import * as electron from "electron"; import * as _ from "lodash"; import IpcRendererEvent = Electron.Event; import {AngularLoadContext} from "../angular-load-context.class"; import Config = SystemJSLoader.Config; import {ElegularWindowOptions} from "../../angular-options"; import * as path from "path"; /** * Loaded in a window. Will be run in a client. */ class ElegularWindowRenderer { _ipcRenderer: Electron.IpcRenderer; private _angularLoadContext: AngularLoadContext; constructor() { this._ipcRenderer = electron.ipcRenderer; // After the window is displayed this._ipcRenderer.once("angular-load", (event: IpcRendererEvent, angularLoadContext: AngularLoadContext) => { this._angularLoadContext = angularLoadContext; ElegularWindowRenderer.createAllScriptSync(...this._angularLoadContext.nodeModulePaths).then(async () => { let baseNode = window.document.createElement("base"); if (!this._angularLoadContext.angularModulePath.startsWith("file:///")) { this._angularLoadContext.angularModulePath = "file:///" + this._angularLoadContext.angularModulePath; } baseNode.href = this._angularLoadContext.angularModulePath; window.document.head.appendChild(baseNode); let elegularWindowOptions : ElegularWindowOptions = angularLoadContext.elegularWindowOptions; this.initializeSystemJS(elegularWindowOptions.systemJsConfig); let moduleClass; let moduleDecorator; let relativePath = path.dirname(document.location.href); relativePath = path.relative(relativePath, angularLoadContext.angularModulePath); relativePath = relativePath.replace(/\\/g, "/"); let moduleContainer = await this.loadFileAsync(relativePath); for (let propName in moduleContainer) { //noinspection JSUnfilteredForInLoop let prop = moduleContainer[propName]; if (_.isFunction(prop)) { let list: any[] = Reflect.getMetadata("annotations", prop); if (moduleDecorator = _.find(list, value => { return value.constructor.name === "DecoratorFactory" && value.hasOwnProperty("bootstrap"); })) { ElegularWindowRenderer._analyzeBootstrap(...moduleDecorator.bootstrap); moduleClass = prop; break; } } } if (moduleClass) { let elegularModuleClass = (await this.loadFileAsync("../../service/elegular.module.js")).ElegularModule; if (moduleDecorator.imports == null) { moduleDecorator.imports = []; } moduleDecorator.imports.push(elegularModuleClass); if (moduleDecorator.providers == null) { moduleDecorator.providers = []; } let elegularWindowRefConstructor = (await this.loadFileAsync("../../service/elegular-window-ref.service.js")).ElegularWindowRef; moduleDecorator.providers.push({ provide: elegularWindowRefConstructor, useValue: new elegularWindowRefConstructor(angularLoadContext.windowId) }); if (elegularWindowOptions.isProductionMode){ let enableProdMode = (await this.loadFileAsync("@angular/core")).enableProdMode; enableProdMode(); } let angularPlatform = await this.loadFileAsync("@angular/platform-browser-dynamic"); angularPlatform.platformBrowserDynamic().bootstrapModule(moduleClass); } else { console.error("Angular module not found(bootstrap property of NgModule must set)"); } }); }) } private async loadFileAsync(moduleName: string): Promise { if (this.isUseSystemJS()) { return SystemJS.import(moduleName); } else { return new Promise(resolve => { resolve(require(moduleName)); }); } } private isUseSystemJS(): boolean { let systemJsConfig = this._angularLoadContext.elegularWindowOptions.systemJsConfig; if (!systemJsConfig || systemJsConfig.isUseSystemJS !== false) { if (SystemJS) { return true; } } return false; } private initializeSystemJS(modularSystemJsConfig: Config) { if (this.isUseSystemJS()) { console.log("Using SystemJS."); SystemJS.config(this.combineSystemJsConfig(modularSystemJsConfig)); } else { console.log("Using CommonJS."); } } static createAllScriptSync(...pathList: string[]): Promise { let promiseList: Promise[] = []; for (let path of pathList) { promiseList.push(ElegularWindowRenderer.createScript(path)); } return Promise.all(promiseList); } static createScript(path: string): Promise { let script = document.createElement("script"); script.setAttribute("type", "text/javascript"); script.setAttribute("src", path); let promise: Promise = new Promise((resolve) => { script.onload = () => { resolve(); }; }); let heads = document.getElementsByTagName("head"); if (heads.length) heads[0].appendChild(script); else document.documentElement.appendChild(script); return promise; } private static _analyzeBootstrap(...bootstrapList): void { for (let b of bootstrapList) { if (_.isFunction(b)) { let annotations = Reflect.getMetadata("annotations", b); for (let annotation of annotations) { if (annotation.constructor.name === "DecoratorFactory") { annotation.selector = "elegular-window"; } } } } } private combineSystemJsConfig(modularSystemJsConfig: Config): Config { let config = this._defaultSystemJsConfig; if (modularSystemJsConfig && modularSystemJsConfig.map) { let modularMap = modularSystemJsConfig.map; for (let key in modularMap) { if (modularMap.hasOwnProperty(key)) { config.map[key] = modularMap[key]; } } } return config; } private _defaultSystemJsConfig: Config = { baseURL: '../../../../', paths: { // paths serve as alias 'npm:': '../../../../' }, // map tells the System loader where to look for things map: { // angular bundles '@angular/core': 'npm:@angular/core/bundles/core.umd.js', '@angular/common': 'npm:@angular/common/bundles/common.umd.js', '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', 'elegular/client': 'npm:elegular/client.js', 'electron': 'npm:elegular/src/client/electron-static.class.js', // other libraries 'rxjs': 'npm:rxjs', }, // packages tells the System loader how to load when no filename and/or no extension packages: { "": { defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' } } }; } // Call the constructor to activate the renderer. new ElegularWindowRenderer();