import {Injector, bind, OpaqueToken, Binding} from 'angular2/di'; import { NumberWrapper, Type, isBlank, isPresent, BaseException, assertionsEnabled, print, stringify } from 'angular2/src/facade/lang'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Reflector, reflector} from 'angular2/src/reflection/reflection'; import { Parser, Lexer, ChangeDetection, DynamicChangeDetection, JitChangeDetection, Pipes, defaultPipes, PreGeneratedChangeDetection } from 'angular2/change_detection'; import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; import {ExceptionHandler} from 'angular2/src/core/exception_handler'; import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver'; import {ViewResolver} from 'angular2/src/core/compiler/view_resolver'; import {List, ListWrapper} from 'angular2/src/facade/collection'; import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {NgZone} from 'angular2/src/core/zone/ng_zone'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {XHR} from 'angular2/src/render/xhr'; import {XHRImpl} from 'angular2/src/render/xhr_impl'; import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; import {UrlResolver} from 'angular2/src/services/url_resolver'; import {AppRootUrl} from 'angular2/src/services/app_root_url'; import { ComponentRef, DynamicComponentLoader } from 'angular2/src/core/compiler/dynamic_component_loader'; import {Testability} from 'angular2/src/core/testability/testability'; import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool'; import {AppViewManager} from 'angular2/src/core/compiler/view_manager'; import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils'; import {AppViewListener} from 'angular2/src/core/compiler/view_listener'; import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory'; import {WorkerRenderer, WorkerCompiler} from './renderer'; import {Renderer, RenderCompiler} from 'angular2/src/render/api'; import {internalView} from 'angular2/src/core/compiler/view_ref'; import {MessageBroker} from 'angular2/src/web-workers/worker/broker'; import {WorkerMessageBus} from 'angular2/src/web-workers/worker/application'; import { appComponentRefPromiseToken, appComponentTypeToken } from 'angular2/src/core/application_tokens'; import {ApplicationRef} from 'angular2/src/core/application'; import {createNgZone} from 'angular2/src/core/application_common'; import {Serializer} from "angular2/src/web-workers/shared/serializer"; import {ON_WEBWORKER} from "angular2/src/web-workers/shared/api"; import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_proto_view_ref_store'; import { RenderViewWithFragmentsStore } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; import {WorkerExceptionHandler} from 'angular2/src/web-workers/worker/exception_handler'; var _rootInjector: Injector; // Contains everything that is safe to share between applications. var _rootBindings = [bind(Reflector).toValue(reflector)]; function _injectorBindings(appComponentType, bus: WorkerMessageBus, initData: StringMap): List> { var bestChangeDetection: Type = DynamicChangeDetection; if (PreGeneratedChangeDetection.isSupported()) { bestChangeDetection = PreGeneratedChangeDetection; } else if (JitChangeDetection.isSupported()) { bestChangeDetection = JitChangeDetection; } return [ bind(appComponentTypeToken) .toValue(appComponentType), bind(appComponentRefPromiseToken) .toFactory( (dynamicComponentLoader, injector) => { // TODO(rado): investigate whether to support bindings on root component. return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector) .then((componentRef) => { return componentRef; }); }, [DynamicComponentLoader, Injector]), bind(appComponentType).toFactory((ref) => ref.instance, [appComponentRefPromiseToken]), bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()), [ExceptionHandler]), Serializer, bind(WorkerMessageBus).toValue(bus), bind(MessageBroker) .toFactory((a, b) => new MessageBroker(a, b), [WorkerMessageBus, Serializer]), WorkerRenderer, bind(Renderer).toAlias(WorkerRenderer), WorkerCompiler, bind(RenderCompiler).toAlias(WorkerCompiler), bind(ON_WEBWORKER).toValue(true), RenderViewWithFragmentsStore, RenderProtoViewRefStore, ProtoViewFactory, AppViewPool, bind(APP_VIEW_POOL_CAPACITY).toValue(10000), AppViewManager, AppViewManagerUtils, AppViewListener, Compiler, CompilerCache, ViewResolver, bind(Pipes).toValue(defaultPipes), bind(ChangeDetection).toClass(bestChangeDetection), DirectiveResolver, Parser, Lexer, WorkerExceptionHandler, bind(ExceptionHandler).toAlias(WorkerExceptionHandler), bind(XHR).toValue(new XHRImpl()), ComponentUrlMapper, UrlResolver, StyleUrlResolver, DynamicComponentLoader, Testability, bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl'])) ]; } export function bootstrapWebworkerCommon( appComponentType: Type, bus: WorkerMessageBus, componentInjectableBindings: List> = null): Promise { var bootstrapProcess = PromiseWrapper.completer(); var zone = createNgZone(new WorkerExceptionHandler()); zone.run(() => { // TODO(rado): prepopulate template cache, so applications with only // index.html and main.js are possible. // var listenerId: int; listenerId = bus.source.addListener((message: StringMap) => { if (message["data"]["type"] !== "init") { return; } var appInjector = _createAppInjector(appComponentType, componentInjectableBindings, zone, bus, message["data"]["value"]); var compRefToken = PromiseWrapper.wrap(() => { try { return appInjector.get(appComponentRefPromiseToken); } catch (e) { throw e; } }); var tick = (componentRef) => { var appChangeDetector = internalView(componentRef.hostView).changeDetector; // retrieve life cycle: may have already been created if injected in root component var lc = appInjector.get(LifeCycle); lc.registerWith(zone, appChangeDetector); lc.tick(); // the first tick that will bootstrap the app bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector)); }; PromiseWrapper.then(compRefToken, tick, (err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); }); PromiseWrapper.catchError(compRefToken, (err) => { print(err); bootstrapProcess.reject(err, err.stack); }); bus.source.removeListener(listenerId); }); bus.sink.send({'type': "ready"}); }); return bootstrapProcess.promise; } function _createAppInjector(appComponentType: Type, bindings: List>, zone: NgZone, bus: WorkerMessageBus, initData: StringMap): Injector { if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings); var mergedBindings: any[] = isPresent(bindings) ? ListWrapper.concat(_injectorBindings(appComponentType, bus, initData), bindings) : _injectorBindings(appComponentType, bus, initData); mergedBindings.push(bind(NgZone).toValue(zone)); return _rootInjector.resolveAndCreateChild(mergedBindings); }