diff --git a/modules/angular2/docs/web_workers/web_workers.md b/modules/angular2/docs/web_workers/web_workers.md index 9ce10f5847..7d2135443b 100644 --- a/modules/angular2/docs/web_workers/web_workers.md +++ b/modules/angular2/docs/web_workers/web_workers.md @@ -19,8 +19,10 @@ better framerate and UX for applications. ## Bootstrapping a WebWorker Application Bootstrapping a WebWorker application is not much different than bootstrapping a normal application. -The primary difference is that you don't pass your root component directly to ```bootstrap```. -Instead you pass the name of a background script that calls ```bootstrapWebWorker``` with your root component. +The main difference is that you need to do the bootstrap process on both the worker and render thread. +Unlike in a standard Angular2 application you don't bootstrap your main component on the render thread. +Instead you initialize a new application injector with the WORKER_APP_PLATFORM providers and provide the name +of your WebWorker script. See the example below for details: ### Example To bootstrap Hello World in a WebWorker we do the following in TypeScript @@ -39,8 +41,11 @@ To bootstrap Hello World in a WebWorker we do the following in TypeScript ``` ```TypeScript // index.js -import {bootstrap} from "angular2/web_worker/ui"; -bootstrap("loader.js"); +import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT} from "angular2/platform/worker_render"; +import {platform} from "angular2/core"; + +platform([WORKER_RENDER_PLATFORM]) +.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"}); ``` ```JavaScript // loader.js @@ -49,7 +54,9 @@ System.import("app"); ``` ```TypeScript // app.ts -import {Component, View, bootstrapWebWorker} from "angular2/web_worker/worker"; +import {Component, View, platform} from "angular2/core"; +import {WORKER_APP_PLATFORM, setupWebWorker} from "angular2/platform/worker_app"; + @Component({ selector: "hello-world" }) @@ -60,21 +67,19 @@ export class HelloWorld { name: string = "Jane"; } -bootstrapWebWorker(HelloWorld); +platform([WORKER_APP_PLATFORM]) +.asyncApplication(setupWebWorker, optionalProviders?) +.then((ref) => ref.bootstrap(RootComponent)); ``` There's a few important things to note here: -* On the UI side we import all angular types from `angular2/web_worker/ui` and on the worker side we import from -`angular2/web_worker/worker`. These modules include all the typings in the WebWorker bundle. By importing from -these URLs instead of `angular2/angular2` we can statically ensure that our app does not reference a type that -doesn't exist in the context it's mean to execute in. For example, if we tried to import DomRenderer in the Worker -or NgFor on the UI we would get a compiler error. * The UI loads angular from the file `angular2/web_worker/ui.js` and the Worker loads angular from `angular2/web_worker/worker.js`. These bundles are created specifically for using WebWorkers and should be used instead of the normal angular2.js file. Both files contain subsets of the angular2 codebase that is designed to run specifically on the UI or Worker. Additionally, they contain the core messaging infrastructure used to communicate between the Worker and the UI. This messaging code is not in the standard angular2.js file. -* We pass `loader.js` to bootstrap and not `app.ts`. You can think of `loader.js` as the `index.html` of the -Worker. Since WebWorkers share no memory with the UI we need to reload the angular2 dependencies before +* We pass `loader.js` to our application injector using the WORKER_SCRIPT symbol. This tells angular that our WebWorkers's init script is located at `loader.js`. +You can think of `loader.js` as the index.html file for the WebWorker. +Since WebWorkers share no memory with the UI we need to reload the angular2 dependencies before bootstrapping our application. We do this with `importScripts`. Additionally, we need to do this in a different file than `app.ts` because our module loader (System.js in this example) has not been loaded yet, and `app.ts` will be compiled with a `System.define` call at the top. @@ -93,17 +98,18 @@ For reference, here's the same HelloWorld example in Dart. ``` ```Dart // index.dart -import "package:angular2/web_worker/ui.dart"; -import "package:angular2/src/core/reflection/reflection.dart"; -import "package:angular2/src/core/reflection/reflection_capabilities.dart"; +import "angular2/core.dart"; +import "angular2/platform/worker_render.dart"; main() { - reflector.reflectionCapabilities = new ReflectionCabilities(); - bootstrap("app.dart"); + platform([WORKER_RENDER_PLATFORM]) + .asyncApplication(initIsolate("my_worker.dart")); } ``` ```Dart -import "package:angular2/web_worker/worker.dart"; +// background_index.dart +import "angular2/core.dart"; +import "angular2/platform/worker_app.dart"; import "package:angular2/src/core/reflection/reflection.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; @@ -119,14 +125,16 @@ class HelloWorld { main(List args, SendPort replyTo) { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrapWebWorker(replyTo, HelloWorld); + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupIsolate(replyTo)) + .then((ref) => ref.bootstrap(RootComponent)); } ``` This code is nearly the same as the TypeScript version with just a couple key differences: * We don't have a `loader.js` file. Dart applications don't need this file because you don't need a module loader. * We pass a `SendPort` to `bootstrapWebWorker`. Dart applications use the Isolate API, which communicates via -Dart's Port abstraction. When you call `bootstrap` from the UI thread, angular starts a new Isolate to run +Dart's Port abstraction. When you call `setupIsolate` from the UI thread, angular starts a new Isolate to run your application logic. When Dart starts a new Isolate it passes a `SendPort` to that Isolate so that it can communicate with the Isolate that spawned it. You need to pass this `SendPort` to `bootstrapWebWorker` so that Angular can communicate with the UI. @@ -136,6 +144,8 @@ but should use the angular 2 transformer to remove it in your final JS code. Not with running the transformer on your UI code (#3971). You can (and should) pass the file where you call `bootstrapWebWorker` as an entry point to the transformer, but you should not pass your UI index file to the transformer until that bug is fixed. +* In dart we call `asyncApplication` instead of `application` because starting an isolate in Dart is asyncronous + whereas starting a new WebWorker in JavaScript is a synchronous operation. ## Writing WebWorker Compatible Components You can do almost everything in a WebWorker component that you can do in a typical Angular 2 Component. @@ -202,17 +212,22 @@ can make it easy to catch tricky browser compatibility issues. [MessageBroker](#using-the-messagebroker-in-your-application). However, if you want to control the messaging protocol yourself you can use the MessageBus directly. +You can obtain the MessageBus on both the render and worker thread through DI. To use the MessageBus you need to initialize a new channel on both the UI and WebWorker. In TypeScript that would look like this: ```TypeScript // index.ts, which is running on the UI. -var instance = bootstrap("loader.js"); -var bus = instance.bus; +import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT, MessageBus} from "angular2/platform/worker_render"; +import {platform} from "angular2/core"; + +let appRef = platform([WORKER_RENDER_PLATFORM]) +.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"}); +let bus = appRef.injector.get(MessageBus); bus.initChannel("My Custom Channel"); ``` ```TypeScript // background_index.ts, which is running on the WebWorker -import {MessageBus} from 'angular2/web_worker/worker'; +import {MessageBus} from 'angular2/platform/worker_app'; @Component({...}) @View({...}) export class MyComponent { @@ -226,15 +241,19 @@ Once the channel has been initialized either side can use the `from` and `to` me and receive messages. Both methods return EventEmitter. Expanding on the example from earlier: ```TypeScript // index.ts, which is running on the UI. -import {bootstrap} from 'angular2/web_worker/ui'; -var instance = bootstrap("loader.js"); -var bus = instance.bus; +import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT, MessageBus} from "angular2/platform/worker_render"; +import {platform} from "angular2/core"; + +let appRef = platform([WORKER_RENDER_PLATFORM]) +.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"}); +let bus = appRef.injector.get(MessageBus); bus.initChannel("My Custom Channel"); -bus.to("My Custom Channel").emit("hello from the UI"); +bus.to("My Custom Channel").emit("Hello from the UI"); ``` ```TypeScript // background_index.ts, which is running on the WebWorker -import {MessageBus, Component, View} from 'angular2/web_worker/worker'; +import {Component, View} from 'angular2/core'; +import {MessageBus} from 'angular2/platform/worker_app'; @Component({...}) @View({...}) export class MyComponent { @@ -253,16 +272,21 @@ This example is nearly identical in Dart, and is included below for reference: import 'package:angular2/web_workers/ui.dart'; main() { - var instance = bootstrap("background_index.dart"); - var bus = instance.bus; - bus.initChannel("My Custom Channel"); - bus.to("My Custom Channel").add("hello from the UI"); + import "angular2/core.dart"; + import "angular2/platform/worker_render.dart"; + + platform([WORKER_RENDER_PLATFORM]) + .asyncApplication(initIsolate("my_worker.dart")).then((ref) { + var bus = ref.injector.get(MessageBus); + bus.initChannel("My Custom Channel"); + bus.to("My Custom Channel").add("hello from the UI"); + }); } ``` ```Dart // background_index.dart, which is running on the WebWorker -import 'package:angular2/web_worker/worker.dart'; +import 'package:angular2/platform/worker_app.dart'; @Component(...) @View(...) class MyComponent { @@ -298,7 +322,7 @@ change detection. Generally, you want your channels to run inside the zone unles they need to run outside the zone. ### Implementing and Using a Custom MessageBus -**Note:** Implementing and using a Custom MessageBus is experimental and requires importing from private APIs. +**Note:** Implementing and using a Custom MessageBus is experimental and the APIs may change. If you want to drive your application from something other than a WebWorker you can implement a custom message bus. Implementing a custom message bus just means creating a class that fulfills the API specified by the @@ -338,54 +362,97 @@ class JsonMessageBusSource extends GenericMessageBuSource { } ``` -Once you've implemented your custom MessageBus in either TypeScript or Dart, you can tell angular to use it like -so: +Once you've implemented your custom MessageBus in either TypeScript or Dart, you must provide it through DI +during bootstrap like so: + In TypeScript: ```TypeScript // index.ts, running on the UI side -import {bootstrapUICommon} from 'angular2/src/web_workers/ui/impl'; +import {platform, Provider, APP_INITIALIZER, Injector} from 'angular2/core'; +import { + WORKER_RENDER_PLATFORM, + WORKER_RENDER_APP_COMMON, + initializeGenericWorkerRenderer, + MessageBus +} from 'angular2/platform/worker_render'; + var bus = new MyAwesomeMessageBus(); -bootstrapUICommon(bus); +platform([WORKER_RENDER_PLATFORM]) +.application([WORKER_RENDER_APP_COMMON, new Provider(MessageBus, {useValue: bus}), + new Provider(APP_INITIALIZER, { + useFactory: (injector) => () => initializeGenericWorkerRenderer(injector), + deps: [Injector], + multi: true + }) +]); ``` ```TypeScript // background_index.ts, running on the application side -import {bootstrapWebWorkerCommon} from 'angular2/src/web_workers/worker/application_common'; +import {WORKER_APP_PLATFORM, genericWorkerAppProviders} from "angular2/platform/worker_app"; +import {NgZone, platform, Provider} from "angular/core"; import {MyApp} from './app'; -var bus = new MyAwesomeMessageBus(); -bootstrapWebWorkerCommon(MyApp, bus); + +platform([WORKER_APP_PLATFORM_PROVIDERS]) +.asyncApplication(initAppThread, optionalProviders?) +.then((ref) => ref.bootstrap(MyApp)); + +function initAppThread(zone: NgZone): Promise> { + /** + * Do initializtion work here to set up the app thread and MessageBus + * Once you have a working MessageBus that communicates with the render thread you should call genericWorkerAppProviders + * to get a list of Providers. + */ + var bus = new MyAwesomeMessageBus(); + return genericWorkerAppProviders(myBus, zone); +} ``` In Dart: ```Dart // index.dart, running on the UI side -import 'package:angular2/src/web_workers/ui/impl.dart' show bootstrapUICommon; -import "package:angular2/src/core/reflection/reflection.dart"; -import "package:angular2/src/core/reflection/reflection_capabilities.dart"; +import 'package:angular2/core.dart'; +import 'package:angular2/platform/worker_render.dart'; main() { - reflector.reflectionCapabilities = new ReflectionCapabilities(); var bus = new MyAwesomeMessageBus(); - bootstrapUiCommon(bus); + platform([WORKER_RENDER_PLATFORM]) + .application([WORKER_RENDER_APP_COMMON, new Provider(MessageBus, useValue: bus), + new Provider(APP_INITIALIZER, + useFactory: (injector) => () => initializeGenericWorkerRenderer(injector), + deps: [Injector], + multi: true + ) + ]); } + ``` ```Dart // background_index.dart, running on the application side -import "package:angular2/src/web_workers/worker/application_common.dart" show bootstrapWebWorkerCommon; -import "package:angular2/src/core/reflection/reflection.dart"; -import "package:angular2/src/core/reflection/reflection_capabilities.dart"; +import "package:angular2/platform/worker_app.dart"; +import "package:angular2/core.dart"; import "./app.dart" show MyApp; main() { - reflector.reflectionCapabilities = new ReflectionCapabilities(); - var bus = new MyAwesomeMessageBus(); - bootstrapWebWorkerCommon(MyApp, bus); + reflector.reflectionCapabilities = new ReflectionCapabilities(); + platform([WORKER_APP_PLATFORM_PROVIDERS]) + .asyncApplication(initAppThread, optionalProviders?) + .then((ref) => ref.bootstrap(MyApp)); +} + + +Future initAppThread(NgZone zone) { + var bus = new MyAwesomeMessageBus(); + return genericWorkerAppProviders(myBus, zone); } ``` -Notice how we call `bootstrapUICommon` instead of `bootstrap` from the UI side. `bootstrap` spans a new WebWorker -/ Isolate and attaches the default angular MessageBus to it. If you're using a custom MessageBus you are -responsible for setting up the application side and initiating communication with it. `bootstrapUICommon` assumes -that the given MessageBus is already set up and can communicate with the application. -Similarly, we call `bootstrapWebWorkerCommon` instead of `boostrapWebWorker` from the application side. This is -because `bootstrapWebWorker` assumes you're using the default angular MessageBus and initializes a new one for you. +Notice how we use the `WORKER_RENDER_APP_COMMON` providers instead of the `WORKER_RENDER_APP` providers on the render thread. +This is because the `WORKER_RENDER_APP` providers include an application initializer that starts a new WebWorker/Isolate. +The `WORKER_RENDER_APP_COMMON` providers make no assumption about where your application code lives. +However, we now need to provide our own app initializer. At the very least this initializer needs to call `initializeGenericWorkerRenderer`. +This function performs necessary setup work to bootstrap the application. + +Similarly we don&t call `setupWebWorker` or `setupIsolate` from the application thread. +Instead we have our own initilization method that sets up our MessageBus and calls `genericWorkerAppProviders` +to finish setting up the application injector. ## MessageBroker The MessageBroker is a higher level messaging abstraction that sits on top of the MessageBus. It is used when you @@ -407,18 +474,21 @@ MessageBrokers in an application. For a more complete example, check out the `We #### Using the MessageBroker in TypeScript ```TypeScript // index.ts, which is running on the UI with a method that we want to expose to a WebWorker -import {bootstrap} from 'angular2/web_worker/ui'; +import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT, ServiceMessageBrokerFactory} from "angular2/platform/worker_render"; +import {platform} from "angular2/core"; -var instance = bootstrap("loader.js"); -var broker = instance.app.createServiceMessageBroker("My Broker Channel"); +let appRef = platform([WORKER_RENDER_PLATFORM]) +.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"}); +let injector = instance.injector; +var broker = injector.get(ServiceMessageBrokerFactory).createMessageBroker("My Broker Channel"); // assume we have some function doCoolThings that takes a string argument and returns a Promise broker.registerMethod("awesomeMethod", [PRIMITIVE], (arg1: string) => doCoolThing(arg1), PRIMITIVE); ``` ```TypeScript // background.ts, which is running on a WebWorker and wants to execute a method on the UI -import {Component, View, ClientMessageBrokerFactory, PRIMITIVE, UiArguments, FnArgs} -from 'angular2/web_worker/worker'; +import {Component, View} from 'angular2/core'; +import {ClientMessageBrokerFactory, PRIMITIVE, UiArguments, FnArgs} from 'angular2/platform/worker_app'; @Component(...) @View(...) @@ -437,20 +507,24 @@ export class MyComponent { #### Using the MessageBroker in Dart ```Dart // index.dart, which is running on the UI with a method that we want to expose to a WebWorker -import 'package:angular2/web_worker/ui.dart'; +import "angular2/core.dart"; +import "angular2/platform/worker_render.dart"; main() { - var instance = bootstrap("background.dart"); - var broker = instance.app.createServiceMessageBroker("My Broker Channel"); + platform([WORKER_RENDER_PLATFORM]) + .asyncApplication(initIsolate("my_worker.dart")).then((ref) { + var broker = ref.injector.get(ServiceMessageBrokerFactory).createMessageBroker("My Broker Channel"); - // assume we have some function doCoolThings that takes a String argument and returns a Future - broker.registerMethod("awesomeMethod", [PRIMITIVE], (String arg1) => doCoolThing(arg1), PRIMITIVE); + // assume we have some function doCoolThings that takes a String argument and returns a Future + broker.registerMethod("awesomeMethod", [PRIMITIVE], (String arg1) => doCoolThing(arg1), PRIMITIVE); + }); } ``` ```Dart // background.dart, which is running on a WebWorker and wants to execute a method on the UI -import 'package:angular2/web_worker/worker.dart'; +import 'package:angular2/core.dart'; +import 'package:angular2/platform/worker_app.dart'; @Component(...) @View(...) diff --git a/modules/angular2/platform/worker_app.ts b/modules/angular2/platform/worker_app.ts new file mode 100644 index 0000000000..6868591554 --- /dev/null +++ b/modules/angular2/platform/worker_app.ts @@ -0,0 +1,18 @@ +export { + WORKER_APP_PLATFORM, + genericWorkerAppProviders +} from 'angular2/src/platform/worker_app_common'; +export * from 'angular2/src/platform/worker_app'; +export { + ClientMessageBroker, + ClientMessageBrokerFactory, + FnArg, + UiArguments +} from '../src/web_workers/shared/client_message_broker'; +export { + ReceivedMessage, + ServiceMessageBroker, + ServiceMessageBrokerFactory +} from '../src/web_workers/shared/service_message_broker'; +export {PRIMITIVE} from '../src/web_workers/shared/serializer'; +export * from '../src/web_workers/shared/message_bus'; diff --git a/modules/angular2/platform/worker_render.dart b/modules/angular2/platform/worker_render.dart new file mode 100644 index 0000000000..1b689cc244 --- /dev/null +++ b/modules/angular2/platform/worker_render.dart @@ -0,0 +1,20 @@ +library angular2.platform.worker_render; + +export 'package:angular2/src/platform/worker_render_common.dart' + show + WORKER_SCRIPT, + WORKER_RENDER_PLATFORM, + WORKER_RENDER_APP_COMMON, + initializeGenericWorkerRenderer; + +export 'package:angular2/src/platform/worker_render.dart' + show WORKER_RENDER_APP, initIsolate, WebWorkerInstance; + +export '../src/web_workers/shared/client_message_broker.dart' + show ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments; + +export '../src/web_workers/shared/service_message_broker.dart' + show ReceivedMessage, ServiceMessageBroker, ServiceMessageBrokerFactory; + +export '../src/web_workers/shared/serializer.dart' show PRIMITIVE; +export '../src/web_workers/shared/message_bus.dart'; diff --git a/modules/angular2/platform/worker_render.ts b/modules/angular2/platform/worker_render.ts new file mode 100644 index 0000000000..7a2e7ab579 --- /dev/null +++ b/modules/angular2/platform/worker_render.ts @@ -0,0 +1,20 @@ +export { + WORKER_SCRIPT, + WORKER_RENDER_PLATFORM, + initializeGenericWorkerRenderer, + WORKER_RENDER_APP_COMMON +} from 'angular2/src/platform/worker_render_common'; +export * from 'angular2/src/platform/worker_render'; +export { + ClientMessageBroker, + ClientMessageBrokerFactory, + FnArg, + UiArguments +} from '../src/web_workers/shared/client_message_broker'; +export { + ReceivedMessage, + ServiceMessageBroker, + ServiceMessageBrokerFactory +} from '../src/web_workers/shared/service_message_broker'; +export {PRIMITIVE} from '../src/web_workers/shared/serializer'; +export * from '../src/web_workers/shared/message_bus'; diff --git a/modules/angular2/src/core/application_ref.ts b/modules/angular2/src/core/application_ref.ts index 5d2d6c9ba4..2800dca73a 100644 --- a/modules/angular2/src/core/application_ref.ts +++ b/modules/angular2/src/core/application_ref.ts @@ -191,8 +191,8 @@ export abstract class PlatformRef { * new application. Once this promise resolves, the application will be * constructed in the same manner as a normal `application()`. */ - abstract asyncApplication(bindingFn: (zone: NgZone) => - Promise>): Promise; + abstract asyncApplication(bindingFn: (zone: NgZone) => Promise>, + providers?: Array): Promise; /** * Destroy the Angular platform and all Angular applications on the page. @@ -217,12 +217,15 @@ export class PlatformRef_ extends PlatformRef { return app; } - asyncApplication(bindingFn: (zone: NgZone) => Promise>): - Promise { + asyncApplication(bindingFn: (zone: NgZone) => Promise>, + additionalProviders?: Array): Promise { var zone = createNgZone(); var completer = PromiseWrapper.completer(); zone.run(() => { PromiseWrapper.then(bindingFn(zone), (providers: Array) => { + if (isPresent(additionalProviders)) { + providers = ListWrapper.concat(providers, additionalProviders); + } completer.resolve(this._initApp(zone, providers)); }); }); diff --git a/modules/angular2/src/platform/browser_common.ts b/modules/angular2/src/platform/browser_common.ts index 3e51dca1e5..81ba5ddee5 100644 --- a/modules/angular2/src/platform/browser_common.ts +++ b/modules/angular2/src/platform/browser_common.ts @@ -79,4 +79,4 @@ export function initDomAdapter() { BrowserDomAdapter.makeCurrent(); wtfInit(); BrowserGetTestability.init(); -} \ No newline at end of file +} diff --git a/modules/angular2/src/platform/worker_app.dart b/modules/angular2/src/platform/worker_app.dart new file mode 100644 index 0000000000..30bfa785c7 --- /dev/null +++ b/modules/angular2/src/platform/worker_app.dart @@ -0,0 +1,25 @@ +library angular2.src.platform.worker_app; + +import 'package:angular2/src/core/zone/ng_zone.dart'; +import 'package:angular2/src/platform/server/webworker_adapter.dart'; +import 'package:angular2/src/platform/worker_app_common.dart'; +import 'package:angular2/src/web_workers/shared/isolate_message_bus.dart'; +import 'dart:isolate'; + +setupIsolate(SendPort replyTo) { + return (NgZone zone) { + WebWorkerDomAdapter.makeCurrent(); + + ReceivePort rPort = new ReceivePort(); + var sink = new WebWorkerMessageBusSink(replyTo, rPort); + var source = new IsolateMessageBusSource(rPort); + IsolateMessageBus bus = new IsolateMessageBus(sink, source); + return genericWorkerAppProviders(bus, zone); + }; +} + +class WebWorkerMessageBusSink extends IsolateMessageBusSink { + WebWorkerMessageBusSink(SendPort sPort, ReceivePort rPort) : super(sPort) { + sPort.send(rPort.sendPort); + } +} diff --git a/modules/angular2/src/platform/worker_app.ts b/modules/angular2/src/platform/worker_app.ts new file mode 100644 index 0000000000..84cee71348 --- /dev/null +++ b/modules/angular2/src/platform/worker_app.ts @@ -0,0 +1,28 @@ +import {NgZone} from 'angular2/src/core/zone/ng_zone'; +import {Type, CONST_EXPR, isPresent} from 'angular2/src/facade/lang'; +import {Provider} from 'angular2/src/core/di'; +import {Parse5DomAdapter} from 'angular2/src/platform/server/parse5_adapter'; +import { + PostMessageBus, + PostMessageBusSink, + PostMessageBusSource +} from 'angular2/src/web_workers/shared/post_message_bus'; +import {genericWorkerAppProviders} from './worker_app_common'; + +// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492) +interface PostMessageInterface { + (message: any, transferrables?:[ArrayBuffer]): void; +} +var _postMessage: PostMessageInterface = postMessage; + +export function setupWebWorker(zone: NgZone): Promise> { + Parse5DomAdapter.makeCurrent(); + var sink = new PostMessageBusSink({ + postMessage: + (message: any, transferrables?:[ArrayBuffer]) => { _postMessage(message, transferrables); } + }); + var source = new PostMessageBusSource(); + var bus = new PostMessageBus(sink, source); + + return genericWorkerAppProviders(bus, zone); +} diff --git a/modules/angular2/src/platform/worker_app_common.ts b/modules/angular2/src/platform/worker_app_common.ts new file mode 100644 index 0000000000..af7eadc416 --- /dev/null +++ b/modules/angular2/src/platform/worker_app_common.ts @@ -0,0 +1,97 @@ +import {XHR} from 'angular2/src/compiler/xhr'; +import {WebWorkerXHRImpl} from 'angular2/src/web_workers/worker/xhr_impl'; +import {ListWrapper} from 'angular2/src/facade/collection'; +import {AppRootUrl} from 'angular2/src/compiler/app_root_url'; +import {WebWorkerRenderer} from 'angular2/src/web_workers/worker/renderer'; +import {print, Type, CONST_EXPR, isPresent} from 'angular2/src/facade/lang'; +import {MessageBus} from 'angular2/src/web_workers/shared/message_bus'; +import {Renderer} from 'angular2/src/core/render/api'; +import { + PLATFORM_DIRECTIVES, + PLATFORM_PIPES, + ExceptionHandler, + APPLICATION_COMMON_PROVIDERS, + PLATFORM_COMMON_PROVIDERS, +} from 'angular2/core'; +import {COMMON_DIRECTIVES, COMMON_PIPES, FORM_PROVIDERS} from "angular2/common"; +import { + ClientMessageBrokerFactory, + ClientMessageBrokerFactory_ +} from 'angular2/src/web_workers/shared/client_message_broker'; +import { + ServiceMessageBrokerFactory, + ServiceMessageBrokerFactory_ +} from 'angular2/src/web_workers/shared/service_message_broker'; +import {COMPILER_PROVIDERS} from 'angular2/src/compiler/compiler'; +import {Serializer} from "angular2/src/web_workers/shared/serializer"; +import {ON_WEB_WORKER} from "angular2/src/web_workers/shared/api"; +import {Provider} from 'angular2/src/core/di'; +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 {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher'; +import {NgZone} from 'angular2/src/core/zone/ng_zone'; +import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/facade/async'; +import {SETUP_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api'; +import {ObservableWrapper} from 'angular2/src/facade/async'; + +class PrintLogger { + log = print; + logError = print; + logGroup = print; + logGroupEnd() {} +} + +export const WORKER_APP_PLATFORM: Array = + CONST_EXPR([PLATFORM_COMMON_PROVIDERS]); + +export const WORKER_APP_COMMON_PROVIDERS: Array = CONST_EXPR([ + APPLICATION_COMMON_PROVIDERS, + COMPILER_PROVIDERS, + FORM_PROVIDERS, + Serializer, + new Provider(PLATFORM_PIPES, {useValue: COMMON_PIPES, multi: true}), + new Provider(PLATFORM_DIRECTIVES, {useValue: COMMON_DIRECTIVES, multi: true}), + new Provider(ClientMessageBrokerFactory, {useClass: ClientMessageBrokerFactory_}), + new Provider(ServiceMessageBrokerFactory, {useClass: ServiceMessageBrokerFactory_}), + WebWorkerRenderer, + new Provider(Renderer, {useExisting: WebWorkerRenderer}), + new Provider(ON_WEB_WORKER, {useValue: true}), + RenderViewWithFragmentsStore, + RenderProtoViewRefStore, + new Provider(ExceptionHandler, {useFactory: _exceptionHandler, deps: []}), + WebWorkerXHRImpl, + new Provider(XHR, {useExisting: WebWorkerXHRImpl}), + WebWorkerEventDispatcher +]); + +function _exceptionHandler(): ExceptionHandler { + return new ExceptionHandler(new PrintLogger()); +} + +/** + * Asynchronously returns a list of providers that can be used to initialize the + * Application injector. + * Also takes care of attaching the {@link MessageBus} to the given {@link NgZone}. + */ +export function genericWorkerAppProviders(bus: MessageBus, + zone: NgZone): Promise> { + var bootstrapProcess: PromiseCompleter = PromiseWrapper.completer(); + bus.attachToZone(zone); + bus.initChannel(SETUP_CHANNEL, false); + + var subscription: any; + var emitter = bus.from(SETUP_CHANNEL); + subscription = ObservableWrapper.subscribe(emitter, (initData: {[key: string]: any}) => { + var bindings = ListWrapper.concat(WORKER_APP_COMMON_PROVIDERS, [ + new Provider(MessageBus, {useValue: bus}), + new Provider(AppRootUrl, {useValue: new AppRootUrl(initData['rootUrl'])}), + ]); + bootstrapProcess.resolve(bindings); + ObservableWrapper.dispose(subscription); + }); + + ObservableWrapper.callNext(bus.to(SETUP_CHANNEL), "ready"); + return bootstrapProcess.promise; +} diff --git a/modules/angular2/src/platform/worker_render.dart b/modules/angular2/src/platform/worker_render.dart new file mode 100644 index 0000000000..387e704947 --- /dev/null +++ b/modules/angular2/src/platform/worker_render.dart @@ -0,0 +1,68 @@ +library angular2.src.platform.worker_render; + +import 'package:angular2/src/platform/worker_render_common.dart' + show + WORKER_RENDER_APP_COMMON, + WORKER_RENDER_MESSAGING_PROVIDERS, + WORKER_SCRIPT, + initializeGenericWorkerRenderer; +import 'package:angular2/src/web_workers/shared/isolate_message_bus.dart'; +import 'package:angular2/src/web_workers/shared/message_bus.dart'; +import 'package:angular2/core.dart'; +import 'package:angular2/src/core/di.dart'; +import 'package:angular2/src/core/zone/ng_zone.dart'; +import 'dart:isolate'; +import 'dart:async'; + +const WORKER_RENDER_APP = WORKER_RENDER_APP_COMMON; + +initIsolate(String scriptUri) { + return (NgZone zone) async { + var instance = await spawnIsolate(Uri.parse(scriptUri)); + + return [ + WORKER_RENDER_APP_COMMON, + new Provider(WebWorkerInstance, useValue: instance), + new Provider(APP_INITIALIZER, + useFactory: (injector) => () => initializeGenericWorkerRenderer(injector), + multi: true, + deps: [Injector]), + new Provider(MessageBus, useValue: instance.bus) + ]; + }; +} + +/** + * Spawns a new class and initializes the WebWorkerInstance + */ +Future spawnIsolate(Uri uri) async { + var receivePort = new ReceivePort(); + var isolateEndSendPort = receivePort.sendPort; + var isolate = await Isolate.spawnUri(uri, const [], isolateEndSendPort); + var source = new UIMessageBusSource(receivePort); + var sendPort = await source.sink; + var sink = new IsolateMessageBusSink(sendPort); + var bus = new IsolateMessageBus(sink, source); + + return new WebWorkerInstance(isolate, bus); +} + +class UIMessageBusSource extends IsolateMessageBusSource { + UIMessageBusSource(ReceivePort port) : super(port); + + Future get sink => stream.firstWhere((message) { + return message is SendPort; + }); +} + +/** + * Wrapper class that exposes the Isolate + * and underlying {@link MessageBus} for lower level message passing. + */ +@Injectable() +class WebWorkerInstance { + Isolate worker; + MessageBus bus; + + WebWorkerInstance(this.worker, this.bus); +} diff --git a/modules/angular2/src/platform/worker_render.ts b/modules/angular2/src/platform/worker_render.ts new file mode 100644 index 0000000000..c80bd35fb1 --- /dev/null +++ b/modules/angular2/src/platform/worker_render.ts @@ -0,0 +1,77 @@ +import { + PostMessageBus, + PostMessageBusSink, + PostMessageBusSource +} from 'angular2/src/web_workers/shared/post_message_bus'; +import {MessageBus} from 'angular2/src/web_workers/shared/message_bus'; +import {APP_INITIALIZER} from 'angular2/core'; +import {Injector, Injectable, Provider} from 'angular2/src/core/di'; +import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup'; +import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer'; +import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl'; +import { + WORKER_RENDER_APP_COMMON, + WORKER_RENDER_MESSAGING_PROVIDERS, + WORKER_SCRIPT, + initializeGenericWorkerRenderer +} from 'angular2/src/platform/worker_render_common'; +import {BaseException} from 'angular2/src/facade/exceptions'; +import {CONST_EXPR} from 'angular2/src/facade/lang'; + +/** + * Wrapper class that exposes the Worker + * and underlying {@link MessageBus} for lower level message passing. + */ +@Injectable() +export class WebWorkerInstance { + public worker: Worker; + public bus: MessageBus; + + /** @internal */ + public init(worker: Worker, bus: MessageBus) { + this.worker = worker; + this.bus = bus; + } +} + +/** + * An array of providers that should be passed into `application()` when initializing a new Worker. + */ +export const WORKER_RENDER_APP: Array = CONST_EXPR([ + WORKER_RENDER_APP_COMMON, + WebWorkerInstance, + new Provider(APP_INITIALIZER, + { + useFactory: (injector) => () => initWebWorkerApplication(injector), + multi: true, + deps: [Injector] + }), + new Provider(MessageBus, {useFactory: (instance) => instance.bus, deps: [WebWorkerInstance]}) +]); + +function initWebWorkerApplication(injector: Injector): void { + var scriptUri: string; + try { + scriptUri = injector.get(WORKER_SCRIPT); + } catch (e) { + throw new BaseException( + "You must provide your WebWorker's initialization script with the WORKER_SCRIPT token"); + } + + let instance = injector.get(WebWorkerInstance); + spawnWebWorker(scriptUri, instance); + + initializeGenericWorkerRenderer(injector); +} + +/** + * Spawns a new class and initializes the WebWorkerInstance + */ +function spawnWebWorker(uri: string, instance: WebWorkerInstance): void { + var webWorker: Worker = new Worker(uri); + var sink = new PostMessageBusSink(webWorker); + var source = new PostMessageBusSource(webWorker); + var bus = new PostMessageBus(sink, source); + + instance.init(webWorker, bus); +} diff --git a/modules/angular2/src/platform/worker_render_common.ts b/modules/angular2/src/platform/worker_render_common.ts new file mode 100644 index 0000000000..b51bdff8c8 --- /dev/null +++ b/modules/angular2/src/platform/worker_render_common.ts @@ -0,0 +1,120 @@ +import {CONST_EXPR} from 'angular2/src/facade/lang'; +import {MessageBus} from 'angular2/src/web_workers/shared/message_bus'; +import {NgZone} from 'angular2/src/core/zone/ng_zone'; +import {AnchorBasedAppRootUrl} from 'angular2/src/compiler/anchor_based_app_root_url'; +import {AppRootUrl} from 'angular2/src/compiler/app_root_url'; +import { + PLATFORM_DIRECTIVES, + PLATFORM_PIPES, + ComponentRef, + platform, + ExceptionHandler, + Reflector, + reflector, + APPLICATION_COMMON_PROVIDERS, + PLATFORM_COMMON_PROVIDERS, + Renderer, + PLATFORM_INITIALIZER, + APP_INITIALIZER +} from 'angular2/core'; +import {EVENT_MANAGER_PLUGINS, EventManager} from 'angular2/platform/common_dom'; +import {provide, Provider, Injector, OpaqueToken} from 'angular2/src/core/di'; +// TODO change these imports once dom_adapter is moved out of core +import {DOM} from 'angular2/src/platform/dom/dom_adapter'; +import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events'; +import {KeyEventsPlugin} from 'angular2/src/platform/dom/events/key_events'; +import {HammerGesturesPlugin} from 'angular2/src/platform/dom/events/hammer_gestures'; +import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens'; +import {DomRenderer, DomRenderer_} from 'angular2/src/platform/dom/dom_renderer'; +import {DomSharedStylesHost} from 'angular2/src/platform/dom/shared_styles_host'; +import {SharedStylesHost} from "angular2/src/platform/dom/shared_styles_host"; +import {BrowserDetails} from 'angular2/src/animate/browser_details'; +import {AnimationBuilder} from 'angular2/src/animate/animation_builder'; +import {XHR} from 'angular2/compiler'; +import {XHRImpl} from 'angular2/src/platform/browser/xhr_impl'; +import {Testability} from 'angular2/src/core/testability/testability'; +import {BrowserGetTestability} from 'angular2/src/platform/browser/testability'; +import {BrowserDomAdapter} from './browser/browser_adapter'; +import {wtfInit} from 'angular2/src/core/profile/wtf_init'; +import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup'; +import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer'; +import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl'; +import { + ServiceMessageBrokerFactory, + ServiceMessageBrokerFactory_ +} from 'angular2/src/web_workers/shared/service_message_broker'; +import { + ClientMessageBrokerFactory, + ClientMessageBrokerFactory_ +} from 'angular2/src/web_workers/shared/client_message_broker'; +import {Serializer} from 'angular2/src/web_workers/shared/serializer'; +import {ON_WEB_WORKER} 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'; + +export const WORKER_SCRIPT: OpaqueToken = CONST_EXPR(new OpaqueToken("WebWorkerScript")); + +// Message based Worker classes that listen on the MessageBus +export const WORKER_RENDER_MESSAGING_PROVIDERS: Array = + CONST_EXPR([MessageBasedRenderer, MessageBasedXHRImpl, WebWorkerSetup]); + +export const WORKER_RENDER_PLATFORM: Array = CONST_EXPR([ + PLATFORM_COMMON_PROVIDERS, + new Provider(PLATFORM_INITIALIZER, {useValue: initWebWorkerRenderPlatform, multi: true}) +]); + +export const WORKER_RENDER_APP_COMMON: Array = CONST_EXPR([ + APPLICATION_COMMON_PROVIDERS, + WORKER_RENDER_MESSAGING_PROVIDERS, + new Provider(ExceptionHandler, {useFactory: _exceptionHandler, deps: []}), + new Provider(DOCUMENT, {useFactory: _document, deps: []}), + // TODO(jteplitz602): Investigate if we definitely need EVENT_MANAGER on the render thread + // #5298 + new Provider(EVENT_MANAGER_PLUGINS, {useClass: DomEventsPlugin, multi: true}), + new Provider(EVENT_MANAGER_PLUGINS, {useClass: KeyEventsPlugin, multi: true}), + new Provider(EVENT_MANAGER_PLUGINS, {useClass: HammerGesturesPlugin, multi: true}), + new Provider(DomRenderer, {useClass: DomRenderer_}), + new Provider(Renderer, {useExisting: DomRenderer}), + new Provider(SharedStylesHost, {useExisting: DomSharedStylesHost}), + new Provider(XHR, {useClass: XHRImpl}), + MessageBasedXHRImpl, + new Provider(ServiceMessageBrokerFactory, {useClass: ServiceMessageBrokerFactory_}), + new Provider(ClientMessageBrokerFactory, {useClass: ClientMessageBrokerFactory_}), + AnchorBasedAppRootUrl, + new Provider(AppRootUrl, {useExisting: AnchorBasedAppRootUrl}), + Serializer, + new Provider(ON_WEB_WORKER, {useValue: false}), + RenderViewWithFragmentsStore, + RenderProtoViewRefStore, + DomSharedStylesHost, + Testability, + BrowserDetails, + AnimationBuilder, + EventManager +]); + +export function initializeGenericWorkerRenderer(injector: Injector) { + var bus = injector.get(MessageBus); + let zone = injector.get(NgZone); + bus.attachToZone(zone); + + zone.run(() => { + WORKER_RENDER_MESSAGING_PROVIDERS.forEach((token) => { injector.get(token).start(); }); + }); +} + +export function initWebWorkerRenderPlatform(): void { + BrowserDomAdapter.makeCurrent(); + wtfInit(); + BrowserGetTestability.init(); +} + +function _exceptionHandler(): ExceptionHandler { + return new ExceptionHandler(DOM, false); +} + +function _document(): any { + return DOM.defaultDoc(); +} diff --git a/modules/angular2/src/web_workers/debug_tools/multi_client_server_message_bus.dart b/modules/angular2/src/web_workers/debug_tools/multi_client_server_message_bus.dart index 3570723f69..218f7b09f8 100644 --- a/modules/angular2/src/web_workers/debug_tools/multi_client_server_message_bus.dart +++ b/modules/angular2/src/web_workers/debug_tools/multi_client_server_message_bus.dart @@ -57,16 +57,17 @@ class MultiClientServerMessageBus extends GenericMessageBus { } class WebSocketWrapper { - WebSocket socket; + WebSocket _socket; Stream stream; int _numResultsReceived = 0; bool _isPrimary = false; bool caughtUp = false; List _messageHistory; List _resultMarkers; + StreamController _sendStream; - WebSocketWrapper(this._messageHistory, this._resultMarkers, this.socket) { - stream = socket.asBroadcastStream(); + WebSocketWrapper(this._messageHistory, this._resultMarkers, this._socket) { + stream = _socket.asBroadcastStream(); stream.listen((encodedMessage) { var messages = JSON.decode(encodedMessage); messages.forEach((data) { @@ -78,6 +79,13 @@ class WebSocketWrapper { } }); }); + + _sendStream = new StreamController(); + _socket.addStream(_sendStream.stream); + } + + void send (String data) { + _sendStream.add(data); } bool get isPrimary => _isPrimary; @@ -113,7 +121,7 @@ class WebSocketWrapper { numMessages = end - curr; } while (numMessages > 0) { - socket.add(_messageHistory[curr]); + send(_messageHistory[curr]); curr++; numMessages--; } @@ -144,7 +152,7 @@ class MultiClientServerMessageBusSink extends GenericMessageBusSink { String encodedMessages = JSON.encode(messages); openConnections.forEach((WebSocketWrapper webSocket) { if (webSocket.caughtUp) { - webSocket.socket.add(encodedMessages); + webSocket.send(encodedMessages); } }); messageHistory.add(encodedMessages); diff --git a/modules/angular2/src/web_workers/ui/application.dart b/modules/angular2/src/web_workers/ui/application.dart deleted file mode 100644 index 7ffb407c02..0000000000 --- a/modules/angular2/src/web_workers/ui/application.dart +++ /dev/null @@ -1,56 +0,0 @@ -library angular2.src.web_workers.ui; - -import 'dart:isolate'; -import 'dart:async'; -import 'dart:core'; -import 'package:angular2/src/web_workers/shared/message_bus.dart' - show MessageBus; -import 'package:angular2/src/web_workers/ui/impl.dart' - show bootstrapUICommon, WebWorkerApplication; -import 'package:angular2/src/web_workers/shared/isolate_message_bus.dart'; - -/** - * Bootstrapping a WebWorker - * - * You instantiate a WebWorker application by calling bootstrap with the URI of your worker's index script - * Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the bootstrapping process - */ -Future bootstrap(String uri) async { - var instance = await spawnWebWorker(Uri.parse(uri)); - instance.app = bootstrapUICommon(instance.bus); - return instance; -} - -/** - * To be called from the main thread to spawn and communicate with the worker thread - */ -Future spawnWebWorker(Uri uri) async { - var receivePort = new ReceivePort(); - var isolateEndSendPort = receivePort.sendPort; - var isolate = await Isolate.spawnUri(uri, const [], isolateEndSendPort); - var source = new UIMessageBusSource(receivePort); - var sendPort = await source.sink; - var sink = new IsolateMessageBusSink(sendPort); - var bus = new IsolateMessageBus(sink, source); - return new IsolateInstance(null, isolate, bus); -} - -class UIMessageBusSource extends IsolateMessageBusSource { - UIMessageBusSource(ReceivePort port) : super(port); - - Future get sink => stream.firstWhere((message) { - return message is SendPort; - }); -} - -/** - * Wrapper class that exposes the {@link WebWorkerApplication} - * Isolate instance and underlying {@link MessageBus} for lower level message passing. - */ -class IsolateInstance { - WebWorkerApplication app; - final Isolate isolate; - final MessageBus bus; - - IsolateInstance(this.app, this.isolate, this.bus); -} diff --git a/modules/angular2/src/web_workers/ui/application.ts b/modules/angular2/src/web_workers/ui/application.ts deleted file mode 100644 index 0910057652..0000000000 --- a/modules/angular2/src/web_workers/ui/application.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - PostMessageBus, - PostMessageBusSink, - PostMessageBusSource -} from 'angular2/src/web_workers/shared/post_message_bus'; -import {MessageBus} from 'angular2/src/web_workers/shared/message_bus'; -import {BaseException, WrappedException} from 'angular2/src/facade/exceptions'; -import {bootstrapUICommon, WebWorkerApplication} from 'angular2/src/web_workers/ui/impl'; -export {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl'; -export * from 'angular2/src/web_workers/shared/message_bus'; - -/** - * Bootstrapping a WebWorker - * - * You instantiate a WebWorker application by calling bootstrap with the URI of your worker's index - * script - * Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the - * bootstrapping process - */ -export function bootstrap(uri: string): WebWorkerInstance { - var instance = spawnWebWorker(uri); - instance.app = bootstrapUICommon(instance.bus); - return instance; -} - -export function spawnWebWorker(uri: string): WebWorkerInstance { - var webWorker: Worker = new Worker(uri); - var sink = new PostMessageBusSink(webWorker); - var source = new PostMessageBusSource(webWorker); - var bus = new PostMessageBus(sink, source); - return new WebWorkerInstance(null, webWorker, bus); -} - -/** - * Wrapper class that exposes the {@link WebWorkerApplication} - * Isolate instance and underlying {@link MessageBus} for lower level message passing. - */ -export class WebWorkerInstance { - constructor(public app: WebWorkerApplication, public worker: Worker, public bus: MessageBus) {} -} diff --git a/modules/angular2/src/web_workers/ui/di_bindings.ts b/modules/angular2/src/web_workers/ui/di_bindings.ts deleted file mode 100644 index d0f0e4a553..0000000000 --- a/modules/angular2/src/web_workers/ui/di_bindings.ts +++ /dev/null @@ -1,122 +0,0 @@ -// TODO (jteplitz602): This whole file is nearly identical to core/application.ts. -// There should be a way to refactor application so that this file is unnecessary. See #3277 -import {Injector, provide, Provider} from "angular2/src/core/di"; -import {AnimationBuilder} from 'angular2/src/animate/animation_builder'; -import {BrowserDetails} from 'angular2/src/animate/browser_details'; -import {Reflector, reflector} from 'angular2/src/core/reflection/reflection'; -import {Parser, Lexer} from 'angular2/src/core/change_detection/change_detection'; -import {EventManager, EVENT_MANAGER_PLUGINS} from 'angular2/platform/common_dom'; -import {ProtoViewFactory} from 'angular2/src/core/linker/proto_view_factory'; -import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter'; -import {KeyEventsPlugin} from 'angular2/src/platform/dom/events/key_events'; -import {HammerGesturesPlugin} from 'angular2/src/platform/dom/events/hammer_gestures'; -import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/linker/view_pool'; -import {Renderer} from 'angular2/src/core/render/api'; -import {AppRootUrl} from 'angular2/src/compiler/app_root_url'; -import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens'; -import {DomRenderer, DomRenderer_} from 'angular2/src/platform/dom/dom_renderer'; -import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events'; -import {APP_ID_RANDOM_PROVIDER} from 'angular2/src/core/application_tokens'; -import {ElementSchemaRegistry} from 'angular2/src/compiler/schema/element_schema_registry'; -import {DomElementSchemaRegistry} from 'angular2/src/compiler/schema/dom_element_schema_registry'; -import {SharedStylesHost, DomSharedStylesHost} from 'angular2/src/platform/dom/shared_styles_host'; -import {DOM} from 'angular2/src/platform/dom/dom_adapter'; -import {NgZone} from 'angular2/src/core/zone/ng_zone'; -import {AppViewManager, AppViewManager_} from 'angular2/src/core/linker/view_manager'; -import {AppViewManagerUtils} from 'angular2/src/core/linker/view_manager_utils'; -import {AppViewListener} from 'angular2/src/core/linker/view_listener'; -import {ViewResolver} from 'angular2/src/core/linker/view_resolver'; -import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver'; -import {ExceptionHandler} from 'angular2/src/facade/exceptions'; -import { - DynamicComponentLoader, - DynamicComponentLoader_ -} from 'angular2/src/core/linker/dynamic_component_loader'; -import {UrlResolver} from 'angular2/src/compiler/url_resolver'; -import {Testability} from 'angular2/src/core/testability/testability'; -import {XHR} from 'angular2/src/compiler/xhr'; -import {XHRImpl} from 'angular2/src/platform/browser/xhr_impl'; -import {Serializer} from 'angular2/src/web_workers/shared/serializer'; -import {ON_WEB_WORKER} 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 {AnchorBasedAppRootUrl} from 'angular2/src/compiler/anchor_based_app_root_url'; -import {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl'; -import {MessageBus} from 'angular2/src/web_workers/shared/message_bus'; -import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer'; -import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl'; -import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup'; -import { - ServiceMessageBrokerFactory, - ServiceMessageBrokerFactory_ -} from 'angular2/src/web_workers/shared/service_message_broker'; -import { - ClientMessageBrokerFactory, - ClientMessageBrokerFactory_ -} from 'angular2/src/web_workers/shared/client_message_broker'; -import {PLATFORM_DIRECTIVES, PLATFORM_PIPES} from "angular2/src/core/platform_directives_and_pipes"; -import {COMMON_DIRECTIVES, COMMON_PIPES} from "angular2/common"; - -var _rootInjector: Injector; - -// Contains everything that is safe to share between applications. -var _rootProviders = [provide(Reflector, {useValue: reflector})]; - -// TODO: This code is nearly identical to core/application. There should be a way to only write it -// once -function _injectorProviders(): any[] { - return [ - provide(DOCUMENT, {useValue: DOM.defaultDoc()}), - EventManager, - new Provider(EVENT_MANAGER_PLUGINS, {useClass: DomEventsPlugin, multi: true}), - new Provider(EVENT_MANAGER_PLUGINS, {useClass: KeyEventsPlugin, multi: true}), - new Provider(EVENT_MANAGER_PLUGINS, {useClass: HammerGesturesPlugin, multi: true}), - provide(DomRenderer, {useClass: DomRenderer_}), - provide(Renderer, {useExisting: DomRenderer}), - APP_ID_RANDOM_PROVIDER, - DomSharedStylesHost, - provide(SharedStylesHost, {useExisting: DomSharedStylesHost}), - Serializer, - provide(ON_WEB_WORKER, {useValue: false}), - provide(ElementSchemaRegistry, {useValue: new DomElementSchemaRegistry()}), - RenderViewWithFragmentsStore, - RenderProtoViewRefStore, - AppViewPool, - provide(APP_VIEW_POOL_CAPACITY, {useValue: 10000}), - provide(AppViewManager, {useClass: AppViewManager_}), - AppViewManagerUtils, - AppViewListener, - ProtoViewFactory, - ViewResolver, - provide(PLATFORM_PIPES, {useValue: COMMON_PIPES, multi: true}), - provide(PLATFORM_DIRECTIVES, {useValue: COMMON_DIRECTIVES, multi: true}), - DirectiveResolver, - Parser, - Lexer, - provide(ExceptionHandler, {useFactory: () => new ExceptionHandler(DOM), deps: []}), - provide(XHR, {useValue: new XHRImpl()}), - UrlResolver, - provide(DynamicComponentLoader, {useClass: DynamicComponentLoader_}), - Testability, - AnchorBasedAppRootUrl, - provide(AppRootUrl, {useExisting: AnchorBasedAppRootUrl}), - WebWorkerApplication, - WebWorkerSetup, - MessageBasedXHRImpl, - MessageBasedRenderer, - provide(ServiceMessageBrokerFactory, {useClass: ServiceMessageBrokerFactory_}), - provide(ClientMessageBrokerFactory, {useClass: ClientMessageBrokerFactory_}), - BrowserDetails, - AnimationBuilder - ]; -} - -export function createInjector(zone: NgZone, bus: MessageBus): Injector { - BrowserDomAdapter.makeCurrent(); - _rootProviders.push(provide(NgZone, {useValue: zone})); - _rootProviders.push(provide(MessageBus, {useValue: bus})); - var injector: Injector = Injector.resolveAndCreate(_rootProviders); - return injector.resolveAndCreateChild(_injectorProviders()); -} diff --git a/modules/angular2/src/web_workers/ui/impl.ts b/modules/angular2/src/web_workers/ui/impl.ts deleted file mode 100644 index a237c13dec..0000000000 --- a/modules/angular2/src/web_workers/ui/impl.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is the entry point for the main thread - * It takes care of spawning the worker and sending it the initial init message - * It also acts and the messenger between the worker thread and the renderer running on the UI - * thread -*/ - -import {createInjector} from "./di_bindings"; -import {MessageBus, MessageBusSink} from "angular2/src/web_workers/shared/message_bus"; -import {createNgZone} from 'angular2/src/core/application_ref'; -import {Injectable} from 'angular2/src/core/di'; -import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter'; -import {wtfInit} from 'angular2/src/core/profile/wtf_init'; -import {WebWorkerSetup} from 'angular2/src/web_workers/ui/setup'; -import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer'; -import {MessageBasedXHRImpl} from 'angular2/src/web_workers/ui/xhr_impl'; -import { - ClientMessageBrokerFactory, - ClientMessageBroker, -} from 'angular2/src/web_workers/shared/client_message_broker'; -import { - ServiceMessageBrokerFactory, - ServiceMessageBroker -} from 'angular2/src/web_workers/shared/service_message_broker'; - -/** - * Creates a zone, sets up the DI providers - * And then creates a new WebWorkerMain object to handle messages from the worker - */ -export function bootstrapUICommon(bus: MessageBus): WebWorkerApplication { - BrowserDomAdapter.makeCurrent(); - var zone = createNgZone(); - wtfInit(); - bus.attachToZone(zone); - return zone.run(() => { - var injector = createInjector(zone, bus); - injector.get(MessageBasedRenderer).start(); - injector.get(MessageBasedXHRImpl).start(); - injector.get(WebWorkerSetup).start(); - return injector.get(WebWorkerApplication); - }); -} - -@Injectable() -export class WebWorkerApplication { - constructor(private _clientMessageBrokerFactory: ClientMessageBrokerFactory, - private _serviceMessageBrokerFactory: ServiceMessageBrokerFactory) {} - - createClientMessageBroker(channel: string, runInZone: boolean = true): ClientMessageBroker { - return this._clientMessageBrokerFactory.createMessageBroker(channel, runInZone); - } - - createServiceMessageBroker(channel: string, runInZone: boolean = true): ServiceMessageBroker { - return this._serviceMessageBrokerFactory.createMessageBroker(channel, runInZone); - } -} diff --git a/modules/angular2/src/web_workers/worker/application.dart b/modules/angular2/src/web_workers/worker/application.dart deleted file mode 100644 index 8703716330..0000000000 --- a/modules/angular2/src/web_workers/worker/application.dart +++ /dev/null @@ -1,41 +0,0 @@ -library angular2.src.web_workers.worker; - -import "package:angular2/src/web_workers/shared/isolate_message_bus.dart"; -import "package:angular2/src/web_workers/worker/application_common.dart" - show bootstrapWebWorkerCommon; -import "package:angular2/src/facade/async.dart" show Future; -import "package:angular2/src/facade/lang.dart" show Type, BaseException; -import "package:angular2/src/core/linker/dynamic_component_loader.dart" - show ComponentRef; -import "dart:isolate"; -import "dart:async"; -import 'dart:core'; -import 'package:angular2/src/platform/server/webworker_adapter.dart'; - -/** - * Bootstrapping a Webworker Application - * - * You instantiate the application side by calling bootstrapWebworker from your webworker index - * script. - * You must supply a SendPort for communicating with the UI side in order to instantiate - * the application. - * Other than the SendPort you can call bootstrapWebworker() exactly as you would call - * bootstrap() in a regular Angular application - * See the bootstrap() docs for more details. - */ -Future bootstrapWebWorker(SendPort replyTo, Type appComponentType, - [List componentInjectableBindings = null]) { - WebWorkerDomAdapter.makeCurrent(); - ReceivePort rPort = new ReceivePort(); - var sink = new WebWorkerMessageBusSink(replyTo, rPort); - var source = new IsolateMessageBusSource(rPort); - IsolateMessageBus bus = new IsolateMessageBus(sink, source); - return bootstrapWebWorkerCommon( - appComponentType, bus, componentInjectableBindings); -} - -class WebWorkerMessageBusSink extends IsolateMessageBusSink { - WebWorkerMessageBusSink(SendPort sPort, ReceivePort rPort) : super(sPort) { - sPort.send(rPort.sendPort); - } -} diff --git a/modules/angular2/src/web_workers/worker/application.ts b/modules/angular2/src/web_workers/worker/application.ts deleted file mode 100644 index 7eec9d15a6..0000000000 --- a/modules/angular2/src/web_workers/worker/application.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - PostMessageBus, - PostMessageBusSink, - PostMessageBusSource -} from 'angular2/src/web_workers/shared/post_message_bus'; -import {Type} from "angular2/src/facade/lang"; -import {Provider, Injectable} from "angular2/src/core/di"; -import {Map} from 'angular2/src/facade/collection'; -import {Promise} from 'angular2/src/facade/async'; -import {bootstrapWebWorkerCommon} from "angular2/src/web_workers/worker/application_common"; -import {ComponentRef} from "angular2/src/core/linker/dynamic_component_loader"; -export * from "angular2/src/web_workers/shared/message_bus"; -import {Parse5DomAdapter} from 'angular2/src/platform/server/parse5_adapter'; - -// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492) -interface PostMessageInterface { - (message: any, transferrables?:[ArrayBuffer]): void; -} -var _postMessage: PostMessageInterface = postMessage; - -/** - * Bootstrapping a Webworker Application - * - * You instantiate the application side by calling bootstrapWebworker from your webworker index - * script. - * You can call bootstrapWebworker() exactly as you would call bootstrap() in a regular Angular - * application - * See the bootstrap() docs for more details. - */ -export function bootstrapWebWorker( - appComponentType: Type, - componentInjectableProviders: Array = null): Promise { - Parse5DomAdapter.makeCurrent(); - var sink = new PostMessageBusSink({ - postMessage: - (message: any, transferrables?:[ArrayBuffer]) => { _postMessage(message, transferrables); } - }); - var source = new PostMessageBusSource(); - var bus = new PostMessageBus(sink, source); - - return bootstrapWebWorkerCommon(appComponentType, bus, componentInjectableProviders); -} diff --git a/modules/angular2/src/web_workers/worker/application_common.ts b/modules/angular2/src/web_workers/worker/application_common.ts deleted file mode 100644 index 1ea00687fe..0000000000 --- a/modules/angular2/src/web_workers/worker/application_common.ts +++ /dev/null @@ -1,147 +0,0 @@ -import {Injector, provide, OpaqueToken, Provider} from 'angular2/src/core/di'; -import {FORM_PROVIDERS} from 'angular2/src/common/forms'; -import { - NumberWrapper, - Type, - isBlank, - isPresent, - assertionsEnabled, - print, - stringify -} from 'angular2/src/facade/lang'; -import {ExceptionHandler} from 'angular2/src/facade/exceptions'; -import {Promise, PromiseWrapper, PromiseCompleter} from 'angular2/src/facade/async'; -import {XHR} from 'angular2/src/compiler/xhr'; -import {WebWorkerXHRImpl} from 'angular2/src/web_workers/worker/xhr_impl'; -import {AppRootUrl} from 'angular2/src/compiler/app_root_url'; -import {WebWorkerRenderer} from './renderer'; -import {Renderer} from 'angular2/src/core/render/api'; -import { - ClientMessageBrokerFactory, - ClientMessageBrokerFactory_ -} from 'angular2/src/web_workers/shared/client_message_broker'; -import { - ServiceMessageBrokerFactory, - ServiceMessageBrokerFactory_ -} from 'angular2/src/web_workers/shared/service_message_broker'; -import {MessageBus} from 'angular2/src/web_workers/shared/message_bus'; -import { - PlatformRef, - ApplicationRef, - APPLICATION_COMMON_PROVIDERS, - PLATFORM_COMMON_PROVIDERS -} from 'angular2/core'; -import * as core from 'angular2/core'; -import {Serializer} from "angular2/src/web_workers/shared/serializer"; -import {ON_WEB_WORKER} 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 {ObservableWrapper} from 'angular2/src/facade/async'; -import {SETUP_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api'; -import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher'; -import {ComponentRef} from 'angular2/src/core/linker/dynamic_component_loader'; -import {NgZone} from 'angular2/src/core/zone/ng_zone'; -import {COMPILER_PROVIDERS} from 'angular2/src/compiler/compiler'; - -/** - * Initialize the Angular 'platform' on the page in a manner suitable for applications - * running in a web worker. Applications running on a web worker do not have direct - * access to DOM APIs. - * - * See {@link PlatformRef} for details on the Angular platform. - * - * ### Without specified providers - * - * If no providers are specified, `platform`'s behavior depends on whether an existing - * platform exists: - * - * If no platform exists, a new one will be created with the default {@link platformProviders}. - * - * If a platform already exists, it will be returned (regardless of what providers it - * was created with). This is a convenience feature, allowing for multiple applications - * to be loaded into the same platform without awareness of each other. - * - * ### With specified providers - * - * It is also possible to specify providers to be made in the new platform. These providers - * will be shared between all applications on the page. For example, an abstraction for - * the browser cookie jar should be bound at the platform level, because there is only one - * cookie jar regardless of how many applications on the age will be accessing it. - * - * If providers are specified directly, `platform` will create the Angular platform with - * them if a platform did not exist already. If it did exist, however, an error will be - * thrown. - * - * ### For Web Worker Applications - * - * This version of `platform` initializes Angular for use with applications - * that do not directly touch the DOM, such as applications which run in a - * web worker context. Applications that need direct access to the DOM should - * use `platform` from `core/application_common` instead. - */ -export function platform(providers?: Array): PlatformRef { - let platformProviders = - isPresent(providers) ? [PLATFORM_COMMON_PROVIDERS, providers] : PLATFORM_COMMON_PROVIDERS; - return core.platform(platformProviders); -} - -class PrintLogger { - log = print; - logError = print; - logGroup = print; - logGroupEnd() {} -} - -function webWorkerProviders(appComponentType, bus: MessageBus, - initData: {[key: string]: any}): Array { - return [ - COMPILER_PROVIDERS, - Serializer, - provide(MessageBus, {useValue: bus}), - provide(ClientMessageBrokerFactory, {useClass: ClientMessageBrokerFactory_}), - provide(ServiceMessageBrokerFactory, {useClass: ServiceMessageBrokerFactory_}), - WebWorkerRenderer, - provide(Renderer, {useExisting: WebWorkerRenderer}), - provide(ON_WEB_WORKER, {useValue: true}), - RenderViewWithFragmentsStore, - RenderProtoViewRefStore, - provide(ExceptionHandler, - {useFactory: () => new ExceptionHandler(new PrintLogger()), deps: []}), - WebWorkerXHRImpl, - provide(XHR, {useExisting: WebWorkerXHRImpl}), - provide(AppRootUrl, {useValue: new AppRootUrl(initData['rootUrl'])}), - WebWorkerEventDispatcher, - FORM_PROVIDERS - ]; -} - -export function bootstrapWebWorkerCommon( - appComponentType: Type, bus: MessageBus, - appProviders: Array = null): Promise { - var bootstrapProcess: PromiseCompleter = PromiseWrapper.completer(); - var appPromise = platform().asyncApplication((zone: NgZone) => { - // TODO(rado): prepopulate template cache, so applications with only - // index.html and main.js are possible. - // - bus.attachToZone(zone); - bus.initChannel(SETUP_CHANNEL, false); - - var subscription: any; - var emitter = bus.from(SETUP_CHANNEL); - subscription = ObservableWrapper.subscribe(emitter, (message: {[key: string]: any}) => { - var bindings = - [APPLICATION_COMMON_PROVIDERS, webWorkerProviders(appComponentType, bus, message)]; - if (isPresent(appProviders)) { - bindings.push(appProviders); - } - bootstrapProcess.resolve(bindings); - ObservableWrapper.dispose(subscription); - }); - - ObservableWrapper.callEmit(bus.to(SETUP_CHANNEL), "ready"); - return bootstrapProcess.promise; - }); - return PromiseWrapper.then(appPromise, (app) => app.bootstrap(appComponentType)); -} diff --git a/modules/angular2/test/core/application_ref_spec.ts b/modules/angular2/test/core/application_ref_spec.ts index b69fd3605b..ae9a13a710 100644 --- a/modules/angular2/test/core/application_ref_spec.ts +++ b/modules/angular2/test/core/application_ref_spec.ts @@ -14,8 +14,11 @@ import { inject } from 'angular2/testing_internal'; import {SpyChangeDetector} from './spies'; -import {ApplicationRef_} from "angular2/src/core/application_ref"; +import {ApplicationRef_, PlatformRef_} from "angular2/src/core/application_ref"; +import {Injector, Provider} from "angular2/core"; import {ChangeDetectorRef_} from "angular2/src/core/change_detection/change_detector_ref"; +import {PromiseWrapper} from "angular2/src/facade/async"; +import {ListWrapper} from "angular2/src/facade/collection"; export function main() { describe("ApplicationRef", () => { @@ -27,4 +30,32 @@ export function main() { expect(() => ref.tick()).toThrowError("ApplicationRef.tick is called recursively"); }); }); + + describe("PlatformRef", () => { + describe("asyncApplication", () => { + it("should merge syncronous and asyncronous providers", + inject([AsyncTestCompleter, Injector], (async, injector) => { + let ref = new PlatformRef_(injector, null); + let ASYNC_PROVIDERS = [new Provider(Foo, {useValue: new Foo()})]; + let SYNC_PROVIDERS = [new Provider(Bar, {useValue: new Bar()})]; + ref.asyncApplication((zone) => PromiseWrapper.resolve(ASYNC_PROVIDERS), SYNC_PROVIDERS) + .then((appRef) => { + var providers = ListWrapper.concat(ASYNC_PROVIDERS, SYNC_PROVIDERS); + for (var i = 0; i < providers.length; i++) { + var provider = providers[i]; + expect(appRef.injector.get(provider.token)).toBe(provider.useValue); + } + async.done(); + }); + })); + }); + }); +} + +class Foo { + constructor() {} +} + +class Bar { + constructor() {} } diff --git a/modules/angular2/test/web_workers/debug_tools/bootstrap.server.spec.dart b/modules/angular2/test/web_workers/debug_tools/bootstrap.server.spec.dart index cc41581663..d5c6e877ee 100644 --- a/modules/angular2/test/web_workers/debug_tools/bootstrap.server.spec.dart +++ b/modules/angular2/test/web_workers/debug_tools/bootstrap.server.spec.dart @@ -4,8 +4,9 @@ import 'package:angular2/src/platform/server/html_adapter.dart'; import "package:angular2/testing_internal.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; -import "package:angular2/web_worker/worker.dart"; -import "package:angular2/src/web_workers/worker/application_common.dart"; +import "package:angular2/src/platform/worker_app_common.dart" show WORKER_APP_COMMON_PROVIDERS; +import "package:angular2/platform/worker_app.dart" show WORKER_APP_PLATFORM; +import "package:angular2/core.dart"; import "../shared/web_worker_test_util.dart"; import "dart:convert"; @@ -13,17 +14,12 @@ main() { Html5LibDomAdapter.makeCurrent(); testSetup(); - describe("bootstrapWebWorkerCommon", () { - it("should bootstrap on a Dart VM", () { + describe("WORKER_APP_COMMON_PROVIDERS", () { + it("should be able to load in a Dart VM", () { reflector.reflectionCapabilities = new ReflectionCapabilities(); var buses = createPairedMessageBuses(); - bootstrapWebWorkerCommon(App, buses.worker); + platform([WORKER_APP_PLATFORM]) + .application([WORKER_APP_COMMON_PROVIDERS]); }); }); } - -@Component(selector: "app") -@View(template: "

Hello {{name}}

") -class App { - String name = "Tester"; -} diff --git a/modules/angular2/test/web_workers/debug_tools/multi_client_server_message_bus.server.spec.dart b/modules/angular2/test/web_workers/debug_tools/multi_client_server_message_bus.server.spec.dart index c3aa704002..43494c9e6a 100644 --- a/modules/angular2/test/web_workers/debug_tools/multi_client_server_message_bus.server.spec.dart +++ b/modules/angular2/test/web_workers/debug_tools/multi_client_server_message_bus.server.spec.dart @@ -213,6 +213,7 @@ SpySocketWrapper createSocket({Function messageHandler}) { var socket = new SpyWebSocket(); if (messageHandler != null) { socket.spy("add").andCallFake(messageHandler); + socket.spy("addStream").andCallFake((Stream stream) => stream.listen(messageHandler)); } var controller = new StreamController.broadcast(); diff --git a/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts b/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts index a96b19828d..b48a12a745 100644 --- a/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts +++ b/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts @@ -49,7 +49,6 @@ import { RenderViewWithFragmentsStore, WebWorkerRenderViewRef } from 'angular2/src/web_workers/shared/render_view_with_fragments_store'; -import {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl'; import {MessageBasedRenderer} from 'angular2/src/web_workers/ui/renderer'; import {createPairedMessageBuses, PairedMessageBuses} from '../shared/web_worker_test_util'; import { @@ -76,7 +75,6 @@ export function main() { var renderer = new MessageBasedRenderer(uiMessageBrokerFactory, uiMessageBus, uiSerializer, uiRenderProtoViewStore, uiRenderViewStore, domRenderer); renderer.start(); - new WebWorkerApplication(null, null); return webWorkerBrokerFactory; } diff --git a/modules/angular2/web_worker/ui.ts b/modules/angular2/web_worker/ui.ts index 0d31f11206..3b28fff8b8 100644 --- a/modules/angular2/web_worker/ui.ts +++ b/modules/angular2/web_worker/ui.ts @@ -1,15 +1,11 @@ export * from 'angular2/src/facade/facade'; +export * from '../src/core/di'; +export {platform, PlatformRef, ApplicationRef} from '../src/core/application_ref'; +export { + APP_ID, + APP_COMPONENT, + APP_INITIALIZER, + PLATFORM_INITIALIZER +} from '../src/core/application_tokens'; export * from '../src/core/zone'; -export * from "../src/web_workers/ui/application"; -export { - ClientMessageBroker, - ClientMessageBrokerFactory, - FnArg, - UiArguments -} from "../src/web_workers/shared/client_message_broker"; -export { - ReceivedMessage, - ServiceMessageBroker, - ServiceMessageBrokerFactory -} from "../src/web_workers/shared/service_message_broker"; -export {PRIMITIVE} from '../src/web_workers/shared/serializer'; +export * from 'angular2/platform/worker_render'; diff --git a/modules/angular2/web_worker/worker.ts b/modules/angular2/web_worker/worker.ts index 744b7705b1..a540cff63f 100644 --- a/modules/angular2/web_worker/worker.ts +++ b/modules/angular2/web_worker/worker.ts @@ -1,55 +1,6 @@ -export * from '../src/core/linker/interfaces'; -export * from '../src/core/metadata'; -export * from '../src/core/util'; -export * from '../src/core/di'; -export * from '../src/common/pipes'; -export * from 'angular2/src/facade/facade'; -// Do not export application in web_worker, -// web_worker exports its own -// export * from '../src/core/application'; -export * from '../src/core/application_ref'; -export * from '../src/platform/browser/ruler'; -export * from '../src/platform/browser/title'; -export * from '../src/compiler/url_resolver'; -export * from '../src/core/linker'; -export * from '../src/core/zone'; -// Do not export render in web_worker -// export * from '../src/core/render'; -// Add special import for just render API -// TODO: Hard coded exports from render that need to be cleaned up -export { - RenderEventDispatcher, - Renderer, - RenderElementRef, - RenderViewRef, - RenderProtoViewRef, - RenderFragmentRef, - RenderViewWithFragments, - RenderTemplateCmd, - RenderCommandVisitor, - RenderTextCmd, - RenderNgContentCmd, - RenderBeginElementCmd, - RenderBeginComponentCmd, - RenderEmbeddedTemplateCmd, - RenderBeginCmd -} from '../src/core/render/api'; -export * from '../src/common/directives'; -export * from '../src/common/forms'; -export {DebugElement} from '../src/core/debug/debug_element'; -export * from '../src/core/change_detection'; - +export * from '../common'; +export * from '../core'; +export * from '../platform/worker_app'; +export {UrlResolver, AppRootUrl} from '../compiler'; export * from '../instrumentation'; -export * from '../src/web_workers/worker/application'; -export { - ClientMessageBroker, - ClientMessageBrokerFactory, - FnArg, - UiArguments -} from '../src/web_workers/shared/client_message_broker'; -export { - ReceivedMessage, - ServiceMessageBroker, - ServiceMessageBrokerFactory -} from '../src/web_workers/shared/service_message_broker'; -export {PRIMITIVE} from '../src/web_workers/shared/serializer'; +export * from 'angular2/src/platform/worker_app'; diff --git a/modules/playground/src/web_workers/images/background_index.dart b/modules/playground/src/web_workers/images/background_index.dart index bc4618061b..3998dff713 100644 --- a/modules/playground/src/web_workers/images/background_index.dart +++ b/modules/playground/src/web_workers/images/background_index.dart @@ -2,12 +2,14 @@ library playground.src.web_workers.images.background_index; import "index_common.dart" show ImageDemo; import "dart:isolate"; -import "package:angular2/src/web_workers/worker/application.dart" - show bootstrapWebWorker; +import "package:angular2/platform/worker_app.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; main(List args, SendPort replyTo) { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrapWebWorker(replyTo, ImageDemo).catchError((error) => throw error); -} + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupIsolate(replyTo)) + .then((ref) => ref.bootstrap(ImageDemo)); +} \ No newline at end of file diff --git a/modules/playground/src/web_workers/images/background_index.ts b/modules/playground/src/web_workers/images/background_index.ts index 3069f7c9db..acfd2f1a2d 100644 --- a/modules/playground/src/web_workers/images/background_index.ts +++ b/modules/playground/src/web_workers/images/background_index.ts @@ -1,6 +1,9 @@ -import {bootstrapWebWorker} from "angular2/src/web_workers/worker/application"; import {ImageDemo} from "./index_common"; +import {platform} from "angular2/core"; +import {WORKER_APP_PLATFORM, setupWebWorker} from "angular2/platform/worker_app"; export function main() { - bootstrapWebWorker(ImageDemo); -} + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupWebWorker) + .then((ref) => ref.bootstrap(ImageDemo)); +} \ No newline at end of file diff --git a/modules/playground/src/web_workers/images/index.dart b/modules/playground/src/web_workers/images/index.dart index 48c6470600..f9073cabb8 100644 --- a/modules/playground/src/web_workers/images/index.dart +++ b/modules/playground/src/web_workers/images/index.dart @@ -1,10 +1,12 @@ library angular2.examples.web_workers.images.index; -import "package:angular2/src/web_workers/ui/application.dart" show bootstrap; +import "package:angular2/platform/worker_render.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; main() { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrap("background_index.dart"); + platform([WORKER_RENDER_PLATFORM]) + .asyncApplication(initIsolate("background_index.dart")); } diff --git a/modules/playground/src/web_workers/images/index.ts b/modules/playground/src/web_workers/images/index.ts index d1726a1fed..caf9a38fa7 100644 --- a/modules/playground/src/web_workers/images/index.ts +++ b/modules/playground/src/web_workers/images/index.ts @@ -1,2 +1,9 @@ -import {bootstrap} from "angular2/src/web_workers/ui/application"; -bootstrap("loader.js"); +import {platform, Provider} from 'angular2/core'; +import { + WORKER_RENDER_APP, + WORKER_RENDER_PLATFORM, + WORKER_SCRIPT +} from 'angular2/platform/worker_render'; + +platform([WORKER_RENDER_PLATFORM]) + .application([WORKER_RENDER_APP, new Provider(WORKER_SCRIPT, {useValue: "loader.js"})]); diff --git a/modules/playground/src/web_workers/kitchen_sink/background_index.dart b/modules/playground/src/web_workers/kitchen_sink/background_index.dart index 7322f74e57..9974d6d5b4 100644 --- a/modules/playground/src/web_workers/kitchen_sink/background_index.dart +++ b/modules/playground/src/web_workers/kitchen_sink/background_index.dart @@ -2,12 +2,14 @@ library playground.src.web_workers.kitchen_sink.background_index; import "index_common.dart" show HelloCmp; import "dart:isolate"; -import "package:angular2/src/web_workers/worker/application.dart" - show bootstrapWebWorker; +import "package:angular2/platform/worker_app.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; main(List args, SendPort replyTo) { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrapWebWorker(replyTo, HelloCmp).catchError((error) => throw error); + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupIsolate(replyTo)) + .then((ref) => ref.bootstrap(HelloCmp)); } diff --git a/modules/playground/src/web_workers/kitchen_sink/background_index.ts b/modules/playground/src/web_workers/kitchen_sink/background_index.ts index ccc6352df4..7caed62823 100644 --- a/modules/playground/src/web_workers/kitchen_sink/background_index.ts +++ b/modules/playground/src/web_workers/kitchen_sink/background_index.ts @@ -1,6 +1,9 @@ import {HelloCmp} from "./index_common"; -import {bootstrapWebWorker} from "angular2/src/web_workers/worker/application"; +import {platform} from "angular2/core"; +import {WORKER_APP_PLATFORM, setupWebWorker} from "angular2/platform/worker_app"; export function main() { - bootstrapWebWorker(HelloCmp); -} + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupWebWorker) + .then((ref) => ref.bootstrap(HelloCmp)); +} \ No newline at end of file diff --git a/modules/playground/src/web_workers/kitchen_sink/index.dart b/modules/playground/src/web_workers/kitchen_sink/index.dart index 58cd33b420..6dbef2e011 100644 --- a/modules/playground/src/web_workers/kitchen_sink/index.dart +++ b/modules/playground/src/web_workers/kitchen_sink/index.dart @@ -1,10 +1,12 @@ library angular2.examples.web_workers.kitchen_sink.index; -import "package:angular2/src/web_workers/ui/application.dart" show bootstrap; +import "package:angular2/platform/worker_render.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; main() { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrap("background_index.dart"); + platform([WORKER_RENDER_PLATFORM]) + .asyncApplication(initIsolate("background_index.dart")); } diff --git a/modules/playground/src/web_workers/kitchen_sink/index.ts b/modules/playground/src/web_workers/kitchen_sink/index.ts index d1726a1fed..caf9a38fa7 100644 --- a/modules/playground/src/web_workers/kitchen_sink/index.ts +++ b/modules/playground/src/web_workers/kitchen_sink/index.ts @@ -1,2 +1,9 @@ -import {bootstrap} from "angular2/src/web_workers/ui/application"; -bootstrap("loader.js"); +import {platform, Provider} from 'angular2/core'; +import { + WORKER_RENDER_APP, + WORKER_RENDER_PLATFORM, + WORKER_SCRIPT +} from 'angular2/platform/worker_render'; + +platform([WORKER_RENDER_PLATFORM]) + .application([WORKER_RENDER_APP, new Provider(WORKER_SCRIPT, {useValue: "loader.js"})]); diff --git a/modules/playground/src/web_workers/message_broker/background_index.dart b/modules/playground/src/web_workers/message_broker/background_index.dart index 5611144797..51ea6e40c7 100644 --- a/modules/playground/src/web_workers/message_broker/background_index.dart +++ b/modules/playground/src/web_workers/message_broker/background_index.dart @@ -1,6 +1,7 @@ library angular2.examples.message_broker.background_index; -import "package:angular2/web_worker/worker.dart"; +import "package:angular2/platform/worker_app.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; import "index_common.dart" show App; @@ -8,5 +9,7 @@ import "dart:isolate"; main(List args, SendPort replyTo) { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrapWebWorker(replyTo, App).catchError((error) => throw error); + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupIsolate(replyTo)) + .then((ref) => ref.bootstrap(App)); } diff --git a/modules/playground/src/web_workers/message_broker/background_index.ts b/modules/playground/src/web_workers/message_broker/background_index.ts index 39f7b0935b..5eb6d43aa0 100644 --- a/modules/playground/src/web_workers/message_broker/background_index.ts +++ b/modules/playground/src/web_workers/message_broker/background_index.ts @@ -1,6 +1,9 @@ -import {bootstrapWebWorker} from "angular2/web_worker/worker"; +import {platform} from "angular2/core"; +import {WORKER_APP_PLATFORM, setupWebWorker} from "angular2/platform/worker_app"; import {App} from "./index_common"; export function main() { - bootstrapWebWorker(App); + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupWebWorker) + .then((ref) => ref.bootstrap(App)); } diff --git a/modules/playground/src/web_workers/message_broker/index.dart b/modules/playground/src/web_workers/message_broker/index.dart index f6f3cf6202..217598bb01 100644 --- a/modules/playground/src/web_workers/message_broker/index.dart +++ b/modules/playground/src/web_workers/message_broker/index.dart @@ -1,6 +1,7 @@ library angular2.examples.message_broker.index; -import "package:angular2/web_worker/ui.dart"; +import "package:angular2/platform/worker_render.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; import "dart:html"; @@ -8,8 +9,11 @@ import "dart:html"; main() { reflector.reflectionCapabilities = new ReflectionCapabilities(); const ECHO_CHANNEL = "ECHO"; - bootstrap("background_index.dart").then((instance) { - var broker = instance.app.createClientMessageBroker(ECHO_CHANNEL, false); + platform([WORKER_RENDER_PLATFORM]) + .asyncApplication(initIsolate("background_index.dart")) + .then((ref) { + var brokerFactory = ref.injector.get(ClientMessageBrokerFactory); + var broker = brokerFactory.createMessageBroker(ECHO_CHANNEL, false); querySelector("#send_echo").addEventListener("click", (e) { var val = (querySelector("#echo_input") as InputElement).value; var args = new UiArguments("echo", [new FnArg(val, PRIMITIVE)]); diff --git a/modules/playground/src/web_workers/message_broker/index.ts b/modules/playground/src/web_workers/message_broker/index.ts index ee0a74bb86..1317dfbad1 100644 --- a/modules/playground/src/web_workers/message_broker/index.ts +++ b/modules/playground/src/web_workers/message_broker/index.ts @@ -1,9 +1,21 @@ -import {bootstrap, UiArguments, FnArg, PRIMITIVE} from "angular2/web_worker/ui"; +import {platform, Provider} from 'angular2/core'; +import { + WORKER_RENDER_APP, + WORKER_RENDER_PLATFORM, + WORKER_SCRIPT, + UiArguments, + FnArg, + PRIMITIVE, + ClientMessageBrokerFactory +} from 'angular2/platform/worker_render'; const ECHO_CHANNEL = "ECHO"; -var instance = bootstrap("loader.js"); -var broker = instance.app.createClientMessageBroker(ECHO_CHANNEL, false); +let ref = + platform([WORKER_RENDER_PLATFORM]) + .application([WORKER_RENDER_APP, new Provider(WORKER_SCRIPT, {useValue: "loader.js"})]); +let brokerFactory: ClientMessageBrokerFactory = ref.injector.get(ClientMessageBrokerFactory); +var broker = brokerFactory.createMessageBroker(ECHO_CHANNEL, false); document.getElementById("send_echo") .addEventListener("click", (e) => { diff --git a/modules/playground/src/web_workers/message_broker/index_common.ts b/modules/playground/src/web_workers/message_broker/index_common.ts index 19ab7a3063..8b64abfb5c 100644 --- a/modules/playground/src/web_workers/message_broker/index_common.ts +++ b/modules/playground/src/web_workers/message_broker/index_common.ts @@ -1,5 +1,6 @@ import {PromiseWrapper} from "angular2/src/facade/async"; -import {Component, View, ServiceMessageBrokerFactory, PRIMITIVE} from "angular2/web_worker/worker"; +import {Component, View} from "angular2/core"; +import {ServiceMessageBrokerFactory, PRIMITIVE} from "angular2/platform/worker_app"; const ECHO_CHANNEL = "ECHO"; diff --git a/modules/playground/src/web_workers/message_broker/loader.js b/modules/playground/src/web_workers/message_broker/loader.js index 494006761a..a828da4812 100644 --- a/modules/playground/src/web_workers/message_broker/loader.js +++ b/modules/playground/src/web_workers/message_broker/loader.js @@ -8,7 +8,6 @@ System.config({ System.import("playground/src/web_workers/message_broker/background_index") .then( function(m) { - console.log("running main"); try { m.main(); } catch (e) { diff --git a/modules/playground/src/web_workers/todo/background_index.dart b/modules/playground/src/web_workers/todo/background_index.dart index c30e78538c..9bd7939b80 100644 --- a/modules/playground/src/web_workers/todo/background_index.dart +++ b/modules/playground/src/web_workers/todo/background_index.dart @@ -2,12 +2,14 @@ library playground.src.web_workers.todo.background_index; import "index_common.dart" show TodoApp; import "dart:isolate"; -import "package:angular2/src/web_workers/worker/application.dart" - show bootstrapWebWorker; +import "package:angular2/platform/worker_app.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; main(List args, SendPort replyTo) { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrapWebWorker(replyTo, TodoApp).catchError((error) => throw error); + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupIsolate(replyTo)) + .then((ref) => ref.bootstrap(TodoApp)); } diff --git a/modules/playground/src/web_workers/todo/background_index.ts b/modules/playground/src/web_workers/todo/background_index.ts index d6807bb930..bcf69706a5 100644 --- a/modules/playground/src/web_workers/todo/background_index.ts +++ b/modules/playground/src/web_workers/todo/background_index.ts @@ -1,6 +1,9 @@ -import {bootstrapWebWorker} from "angular2/src/web_workers/worker/application"; import {TodoApp} from "./index_common"; +import {platform} from "angular2/core"; +import {WORKER_APP_PLATFORM, setupWebWorker} from "angular2/platform/worker_app"; export function main() { - bootstrapWebWorker(TodoApp); + platform([WORKER_APP_PLATFORM]) + .asyncApplication(setupWebWorker) + .then((ref) => ref.bootstrap(TodoApp)); } diff --git a/modules/playground/src/web_workers/todo/index.dart b/modules/playground/src/web_workers/todo/index.dart index 52aa72e9f2..ef1010aade 100644 --- a/modules/playground/src/web_workers/todo/index.dart +++ b/modules/playground/src/web_workers/todo/index.dart @@ -1,10 +1,12 @@ library angular2.examples.web_workers.todo.index; -import "package:angular2/src/web_workers/ui/application.dart" show bootstrap; +import "package:angular2/platform/worker_render.dart"; +import "package:angular2/core.dart"; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; main() { reflector.reflectionCapabilities = new ReflectionCapabilities(); - bootstrap("background_index.dart"); + platform([WORKER_RENDER_PLATFORM]) + .asyncApplication(initIsolate("background_index.dart")); } diff --git a/modules/playground/src/web_workers/todo/index.ts b/modules/playground/src/web_workers/todo/index.ts index d1726a1fed..a138f5972e 100644 --- a/modules/playground/src/web_workers/todo/index.ts +++ b/modules/playground/src/web_workers/todo/index.ts @@ -1,2 +1,9 @@ -import {bootstrap} from "angular2/src/web_workers/ui/application"; -bootstrap("loader.js"); +import {platform, Provider} from 'angular2/core'; +import { + WORKER_RENDER_APP, + WORKER_RENDER_PLATFORM, + WORKER_SCRIPT +} from 'angular2/platform/worker_render'; + +platform([WORKER_RENDER_PLATFORM]) + .application([WORKER_RENDER_APP, new Provider(WORKER_SCRIPT, {useValue: "loader.js"})]); \ No newline at end of file diff --git a/modules/playground/src/web_workers/todo/index_common.ts b/modules/playground/src/web_workers/todo/index_common.ts index ae922ce50c..5f26ee6da2 100644 --- a/modules/playground/src/web_workers/todo/index_common.ts +++ b/modules/playground/src/web_workers/todo/index_common.ts @@ -1,4 +1,5 @@ -import {NgFor, View, Component, FORM_DIRECTIVES} from 'angular2/web_worker/worker'; +import {View, Component} from 'angular2/core'; +import {NgFor, FORM_DIRECTIVES} from 'angular2/common'; import {Store, Todo, TodoFactory} from './services/TodoStore'; @Component({selector: 'todo-app', viewProviders: [Store, TodoFactory]}) diff --git a/modules/playground/src/web_workers/todo/index_web_socket.dart b/modules/playground/src/web_workers/todo/index_web_socket.dart index a1faf9471e..2b091beab0 100644 --- a/modules/playground/src/web_workers/todo/index_web_socket.dart +++ b/modules/playground/src/web_workers/todo/index_web_socket.dart @@ -2,10 +2,10 @@ library angular2.examples.web_workers.todo.index_web_socket; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; -import "package:angular2/src/web_workers/ui/impl.dart" show bootstrapUICommon; +import "package:angular2/core.dart"; +import "package:angular2/platform/worker_render.dart"; import "package:angular2/src/web_workers/debug_tools/web_socket_message_bus.dart"; -import 'dart:html' - show WebSocket; +import 'dart:html' show WebSocket; main() { reflector.reflectionCapabilities = new ReflectionCapabilities(); @@ -13,6 +13,13 @@ main() { webSocket.onOpen.listen((e) { var bus = new WebSocketMessageBus.fromWebSocket(webSocket); - bootstrapUICommon(bus); + platform([WORKER_RENDER_PLATFORM]) + .application([WORKER_RENDER_APP_COMMON, new Provider(MessageBus, useValue: bus), + new Provider(APP_INITIALIZER, + useFactory: (injector) => () => initializeGenericWorkerRenderer(injector), + deps: [Injector], + multi: true + ) + ]); }); } diff --git a/modules/playground/src/web_workers/todo/server_index.dart b/modules/playground/src/web_workers/todo/server_index.dart index 295e034a49..62a52b61e4 100644 --- a/modules/playground/src/web_workers/todo/server_index.dart +++ b/modules/playground/src/web_workers/todo/server_index.dart @@ -1,19 +1,28 @@ library angular2.examples.web_workers.todo.server_index; + import "index_common.dart" show TodoApp; import "package:angular2/src/web_workers/debug_tools/multi_client_server_message_bus.dart"; -import "package:angular2/src/web_workers/worker/application_common.dart" - show bootstrapWebWorkerCommon; +import "package:angular2/platform/worker_app.dart"; +import "package:angular2/core.dart"; import 'dart:io'; +import 'dart:async'; import "package:angular2/src/core/reflection/reflection_capabilities.dart"; import "package:angular2/src/core/reflection/reflection.dart"; import "package:angular2/src/platform/server/html_adapter.dart"; void main() { + reflector.reflectionCapabilities = new ReflectionCapabilities(); + platform([WORKER_APP_PLATFORM]) + .asyncApplication(initAppThread) + .then((ref) => ref.bootstrap(TodoApp)); +} + +Future initAppThread(NgZone zone) { Html5LibDomAdapter.makeCurrent(); - reflector.reflectionCapabilities = new ReflectionCapabilities(); - HttpServer.bind('127.0.0.1', 1337).then((HttpServer server) { + return HttpServer.bind('127.0.0.1', 1337).then((HttpServer server) { + print("Server Listening for requests on 127.0.0.1:1337"); var bus = new MultiClientServerMessageBus.fromHttpServer(server); - bootstrapWebWorkerCommon(TodoApp, bus).catchError((error) => throw error); - print ("Server Listening for requests on 127.0.0.1:1337"); + return genericWorkerAppProviders(bus, zone); }); } + diff --git a/modules/playground/src/web_workers/todo/services/TodoStore.ts b/modules/playground/src/web_workers/todo/services/TodoStore.ts index 792a4b691c..658d8c8b83 100644 --- a/modules/playground/src/web_workers/todo/services/TodoStore.ts +++ b/modules/playground/src/web_workers/todo/services/TodoStore.ts @@ -1,4 +1,4 @@ -import {Injectable} from 'angular2/web_worker/worker'; +import {Injectable} from 'angular2/core'; import {ListWrapper, Predicate} from 'angular2/src/facade/collection'; // base model for RecordStore