For Angular 7, see answer below.
I spent a lot of time to figure out how to do it, so I hope this can help someone.
Preconditions
I’m assuming that you have an Angular project (version 2 or 4) generated with Angular CLI 1.0 or higher.
It is not mandatory to generate the project with CLI to follow this steps, but the instructions I’ll give related with the webpack file, are be based on the CLI webpack config.
Steps
1. Extract webpack file
Since Angular CLI v1.0, there’s the “eject” feature, that allows you to extract the webpack config file and manipulate it as you wish.
-
Run
ng eject
so Angular CLI generates the webpack.config.js file. -
Run
npm install
so the new dependencies generated by CLI are satisfied
2. Install webworker bootstrap dependencies
Run npm install --save @angular/platform-webworker @angular/platform-webworker-dynamic
3. Changes in UI thread bootstrap
3.1 Changes in app.module.ts
Replace BrowserModule
by WorkerAppModule
in the app.module.ts file. You’ll also need to update the import statement in order to use @angular/platform-webworker
library.
//src/app/app.module.ts
import { WorkerAppModule } from '@angular/platform-webworker';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
//...other imports...
@NgModule({
declarations: [
AppComponent
],
imports: [
WorkerAppModule,
//...other modules...
],
providers: [/*...providers...*/],
bootstrap: [AppComponent]
})
export class AppModule { }
3.2 Changes in src/main.ts
Replace bootstrap process with: bootstrapWorkerUI
(update also the import).
You’ll need to pass a URL with the file where the web worker is defined. Use a file called webworker.bundle.js
, don’t worry, we will create this file soon.
//main.ts
import { enableProdMode } from '@angular/core';
import { bootstrapWorkerUi } from '@angular/platform-webworker';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
bootstrapWorkerUi('webworker.bundle.js');
3.3 Create workerLoader.ts file
- Create a new file src/workerLoader.ts.
- As your Web Worker will be a single file containing all the required stuff, you need to include
polyfills.ts
,@angular/core
, and@angular/common
packages. On next steps, you will update Webpack in order to transpile and build a bundle with the result. - Import
platformWorkerAppDynamic
- Import the
AppModule
(remove the import from main.ts) and bootstrap it using thisplatformWorkerAppDynamic
platform.
// workerLoader.ts
import 'polyfills.ts';
import '@angular/core';
import '@angular/common';
import { platformWorkerAppDynamic } from '@angular/platform-webworker-dynamic';
import { AppModule } from './app/app.module';
platformWorkerAppDynamic().bootstrapModule(AppModule);
4. Update webpack to build your webworker
The webpack auto generated config file is quite long, but you’ll just need to center your attention in the following things:
-
Add a
webworker
entry point for ourworkerLoader.ts
file. If you look at the output, you’ll see that it attaches a bundle.js prefix to all chunks. That’s why during bootstrap step we have usedwebworker.bundle.js
-
Go to HtmlWebpackPlugin and exclude the
webworker
entry point, so the generated Web Worker file is not included in the index.html file. -
Go to CommonChunksPlugin, and for the
inline
common chunk, set the entry chunks explicitely to preventwebworker
to be included. -
Go to AotPlugin and set explicitely the
entryModule
// webpack.config.js
//...some stuff...
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CommonsChunkPlugin } = require('webpack').optimize;
const { AotPlugin } = require('@ngtools/webpack');
//...some stuff...
module.exports = {
//...some stuff...
"entry": {
"main": [
"./src/main.ts"
],
"polyfills": [
"./src/polyfills.ts"
],
"styles": [
"./src/styles.css"
],
"webworker": [
"./src/workerLoader.ts"
]
},
"output": {
"path": path.join(process.cwd(), "dist"),
"filename": "[name].bundle.js",
"chunkFilename": "[id].chunk.js"
},
"module": { /*...a lot of stuff...*/ },
"plugins": [
//...some stuff...
new HtmlWebpackPlugin({
//...some stuff...
"excludeChunks": [
"webworker"
],
//...some more stuff...
}),
new BaseHrefWebpackPlugin({}),
new CommonsChunkPlugin({
"name": "inline",
"minChunks": null,
"chunks": [
"main",
"polyfills",
"styles"
]
}),
//...some stuff...
new AotPlugin({
"mainPath": "main.ts",
"entryModule": "app/app.module#AppModule",
//...some stuff...
})
],
//...some more stuff...
};
You’re ready
If you have followed correctly the previous steps, now you only need to compile the code and try the results.
Run npm start
All the logic of your Angular app should be running inside a WebWorker, causing the UI to be more fluent.
Furter notes
npm start
runs the webpack-dev server, and it has some kind of problem with webworkers throwing an error message on console log. Anyway, the webworker seems to run fine.
If you compile the app using webpack
command and serve it from any http server like simplehttpserver, the error goes away 😉
Sample code and demo
You can get the whole code (webpack config, app.module.ts, …) from this repo.
You can also watch here a live demo, to check out differences between using Web Workers or not