Sadly, I couldn't find a single answer to this on the whole web.
I have an Aurelia app based on TypeScript
/ Aurelia CLI
/ RequireJS
.
With a structure like this:
|data
|-MyService.ts
|workers
|-SomeWorker.ts/js
There exists a package called aurelia-pal-worker
, but without documentation or complex examples.
What I've tried so far
Typed-Web-Workers
which is nice but too limitingSomeWorker
.js and used Browserify as an additional buildstep in aurelia_project.The Browserify approach works, as long as I require external libs like RxJs
.
Of course this breaks when I try to require("../data/MyService.ts")
. For this to work, I would need to replace the whole build pipeline with another, that runs the entire aurelia project through Browserify with the tsify plugin.
It seems to my I've got 3 choices:
aurelia-pal-worker
to import dependencies.TypedWorker
and just throw expensive functions into a thread like:new TypedWoker(expensiveFuncFromService, handleOutput)
MyService.ts
to separate JS-Files (instead of bundling it) and require it like this:require("/scripts/MyService.js")
The last two don't seem very appealing to me, but should be straightforward to do. Any hints or examples are highly appreciated!
PS: For anyone not familiar with Aurelia: It uses a gulp pipeline under the hood.
So after some fiddling around I switched to a webpack based solution, which allows me to use the amazing webpack-worker-loader.
This was the best tradeoff between modifying my existing project and having it up and running again quickly.
This is how it looks like in the end:
custom_typings/worker-loader.d.ts
declare module "worker-loader!*" {
const content: new () => any;
export = content;
}
worker/some-service.ts
export class SomeService {
public doStuff() {
console.log("[SomeService] Stuff was done");
}
}
worker/my-worker.ts
import "rxjs/add/observable/interval";
import { Observable } from "rxjs/Observable";
import { SomeService } from "./some-service";
const svc = new SomeService();
svc.doStuff();
console.log("[Worker] Did stuff");
onmessage = event => {
console.log(event);
};
Observable.interval(1000).subscribe(x => postMessage(x));
After the worker is loaded like this:
import * as MyWorker from "worker-loader!./worker/my-worker";
const worker = new MyWorker();
worker.onmessage = msg => console.log("[MyClass] got msg from worker", msg);
It will generate the following console output:
1: "[SomeService] Stuff was done"
2: "[Worker] Did stuff"
3: "[MyClass] got msg from worker", 1
4: "[MyClass] got msg from worker", 2
...
You need full blown DI in a worker?
Fear not, with a little help of this answer I figured out how rewrite this with our webpack based solution:
let container: Container = null;
let myService: SuperComplexService = null;
// Import the loader abstraction, so the DI container knows how to resolve our modules.
import("aurelia-pal-worker")
.then(pal => pal.initialize())
// We need some polyfills (like "Reflect.defineMetadata")
.then(() => import("aurelia-polyfills"))
// Then we get the DI service and create a container
.then(() => import("aurelia-dependency-injection"))
.then(({ Container }) => (container = new Container()))
.then(() => import("../services/my-super-complex-service")) // Here we go!
.then(({ SuperComplexService }) => (myService = container.get(SuperComplexService) as SuperComplexService))
.then(() => startWorker());
const startWorker = async() => {
// Let's get going!
}
All credits for this loader-chain go to @jeremy-danyow.