I'm trying to move the whole execution of an Angular 2 app to a web worker, but I've find out that all examples available right now are using System.js, and I'm trying to do so with a WebPack based project (built with angular-cli).
Has anyone done this or have an idea on how to do this with WebPack?
Below is my main.ts bootstrap file:
import './polyfills.ts';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
import {bootstrapWorkerUi} from '@angular/platform-webworker';
bootstrapWorkerUi('/app/loader.js');
My loader.js
looks like this:
import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic';
import { AppModule } from './app/';
platformWorkerAppDynamic().bootstrapModule(AppModule);
And my app.module.ts
is declaring @NgModule
this way:
import { NgModule } from '@angular/core';
import {WorkerAppModule} from '@angular/platform-webworker';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
WorkerAppModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
However, when I run it, I get the error Uncaught SyntaxError: Unexpected token import in loader.js:1.
The issue seems related with webpack and some lack of imports of @angular libs in the webworker side, as suggested by Tamas Gegedus and MathMate, so the next step is to modify the webpack config file in order to provide all the required libs to the webworker. I'll work on that.
----------- UPDATE -----------
Since angular-cli do not provide access to webpack.config.js file, I've included mine, making little changes in code so it can work. I created the second entry point at webpack config file and I'm getting the error VM33:106 Uncaught ReferenceError: window is not defined.
Webpack config file looks like this:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var helpers = require('./config/helpers');
module.exports = {
entry: {
'app': ['./src/polyfills.ts', './src/vendor.ts', './src/main.ts'],
'webworker': ['./src/workerLoader.ts']
},
resolve: {
extensions: ['', '.ts', '.js']
},
output: {
path: helpers.root('dist'),
publicPath: 'http://localhost:8080/',
filename: '[name].js'
},
devtool: 'cheap-module-eval-source-map',
module: {
loaders: [
{
test: /\.ts$/,
loaders: ['awesome-typescript-loader?tsconfig=./src/tsconfig.json', 'angular2-template-loader']
},
{
test: /\.html$/,
loader: 'html'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file?name=assets/[name].[hash].[ext]'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
excludeChunks: ['webworker']
}),
new ExtractTextPlugin('[name].css')
]
};
where polyfills.ts and vendor.ts include polyfills and angular libs respectively.
I've created 2 entry points, that generate 2 outputs (app.js and webworker.js).
With the HtmlWebpackPlugin, the first one is included in the index.html file, but not the second one.
When index.html is included, main.ts (contained in app.js) is called and tries to bootstrap the webworker using the second output of webpack (webworker.js):
import {bootstrapWorkerUi} from '@angular/platform-webworker';
bootstrapWorkerUi('../webworker.js');
webworker.js has been generated by webpack using workerLoader.ts entry, that is like previous loader.js, but including some imports.
WorkerLoader.ts file looks like this:
import './polyfills.ts';
import '@angular/core';
import '@angular/common';
import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic';
import { AppModule } from './app/';
platformWorkerAppDynamic().bootstrapModule(AppModule);
I know that the web worker is been generated, as shown in the following image, but as shown in the image, I get the error VM33:106 Uncaught ReferenceError: window is not defined, and nothing is displayed except the Loading message from index.html.
On the other side, I think that the webpack config is OK because if running the app with webpack in NO webworker mode, it works fine.
Right now I think that this issue is related with webworker bootstrap, but I'm quite stucked here.
Any help would be appreciated ;)
I finally solved the issue :)
After running the code with my custom webpack config, I realized that the error VM33:106 Uncaught ReferenceError: window is not defined was caused by webpack-dev-server.
I solved it by:
1 - doing a standalone webpack build
and
2 - running with another devserver tool like simplehttpserver
And voilà, the error is gone and it simply works!
Changes applied to angular-cli project: Webpack config
Let me summarize the webpack changes regarding the original Angular-CLI project.
As
angular-cli
do not provide access towebpack.config.js
file and customizing webpack is key to use webworkers, I've included mine, making little changes in code.Webpack config file looks like this:
where polyfills.ts and vendor.ts include polyfills and angular libs respectively.
I've created 2 entry points, that generate 2 outputs (app.js and webworker.js).
With the HtmlWebpackPlugin, the first one is included in the index.html file, but not the second one.
When index.html is included, main.ts (contained in app.js) is called and bootstraps the webworker like this:
webworker.js is the code webpack generated using workerLoader.ts entry.
WorkerLoader.ts file looks like this:
And AppModule looks like this:
Code example
To make easier to understand the differences, I've created a project showing how to convert a regular angular 2 project in a web workers based one. Check this repo: https://github.com/kaikcreator/webWorkerFactorialExample
You'll see in master branch the "single thread" code, and in webWorkers branch, the changes to run code using web workers.
As Tamas Hegedus has already mentioned in comment, most likely your webpack bundle is still referring es6 file for loader.js.
You need to create separate bundle with entry point for loader script.
If you share your webpack config then it would be easier to tell where the things might be going wrong.
Also your loader script needs to have required polyfills. You can add
import 'core-js/es7/reflect'; import 'zone.js/dist/zone';