Effective utilization of web workers with Aurelia and TypeScript

Unfortunately, my search for a solution to this issue across the internet has been fruitless.

I am currently working on an Aurelia application that is built using TypeScript, Aurelia CLI, and RequireJS. The project structure looks like this:

|data
   |-MyService.ts
|workers
   |-SomeWorker.ts/js

There is a package called aurelia-pal-worker, however it lacks comprehensive documentation and detailed examples.


Methods I've experimented with so far

  • Typed-Web-Workers, which proved to be restrictive
  • Created a SomeWorker.js file and integrated Browserify as an additional build step in the aurelia_project.

The Browserify approach functions well when external libraries like RxJs are required. However, it fails when attempting to require("../data/MyService.ts"). To make this work, I would need to replace the entire build process with one that runs the whole Aurelia project through Browserify with the tsify plugin.

It appears that I have three potential solutions:

  • Find a successful example of compiling a TypeScript file into a web worker and utilizing aurelia-pal-worker for importing dependencies.
  • Utilize TypedWorker and place resource-intensive functions into a thread like:
    new TypedWoker(expensiveFuncFromService, handleOutput)
  • Compile MyService.ts into separate JS files (rather than bundling them) and require them in this manner:
    require("/scripts/MyService.js")

The latter two options do not seem particularly appealing to me, but they should be relatively simple to execute. Any guidance or examples would be greatly appreciated!

PS: For those unfamiliar with Aurelia: It utilizes a gulp pipeline behind the scenes.

Answer №1

After experimenting with different solutions, I decided to migrate to a webpack-based approach, allowing me to leverage the powerful features of webpack-worker-loader.

This choice struck the perfect balance between adapting my existing project and getting it back up and running swiftly.

Here is the final implementation:

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));

Once 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);

The following console output will be generated:

1: "[SomeService] Stuff was done"
2: "[Worker] Did stuff"
3: "[MyClass] got msg from worker", 1
4: "[MyClass] got msg from worker", 2
...

Need full dependency injection in a worker?

No worries, thanks to this insightful answer, I discovered how to adapt this using our webpack-powered 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 credit for this loader-chain goes to @jeremy-danyow.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

An obstacle encountered while using the Laravel 5.2 framework in conjunction with AngularJS 2.0 beta

I recently set up a brand new Laravel 5.2.* project and attempted to integrate AngularJS 2.0 beta using the quick start guide. Unfortunately, I encountered some issues during the configuration process. The problem I am facing is shown in the screenshot be ...

Guide to incorporating ThreeJS Collada loader with TypeScript / Angular CLI

I currently have three plugins installed: node_modules/three My Collada loader was also successfully installed in: node_modules/three-collada-loader It seems that the typings already include definitions for the Collada loader as well: node_modules/@ty ...

Modifying the state of one React component using another

Attempting to modify the state of one component using another component in ReactJs, however, being new to React. The parent component contains a state called: _SPCommandBarDisabled this.state = { _SPCommandBarDisabled: true } In a child component ...

Share edited collection with Observer

The challenge Imagine creating an Angular service that needs to expose an Observable<number[]> to consumers: numbers: Observable<number[]>; Our requirements are: Receive the latest value upon subscription Receive the entire array every tim ...

Angular II slash avoiding Pipe

I am working on developing a customized pipe in Angular 2 that will handle the replacement of the backslash ('\') character in a given string. This backslash is commonly used to escape special characters. What I have accomplished so far: T ...

Detecting and clearing custom visual filters in Power BI

Currently, I am developing a unique visual on Microsoft Power BI using d3.js. This customized visual includes a filter effect where selecting filters changes the style properties and adds new items. However, one issue in Power BI is the inability to dete ...

TypeScript is throwing an error because it is unable to recognize the identifiers such as WeakMap

Currently, I am in the process of learning Angular and have set up my TypeScript and Webpack configurations as follows: Here is my tsconfig file: { "compilerOptions": { "target": "es5", "module": "es2015", "moduleResolution": "node", "sourceMap": ...

What causes React component state initialization to return a `never` type when set to null?

Initializing a component's state to null outside of the constructor results in the state having the type never in the render function. However, when the state is initialized within the constructor, the correct type is maintained. Despite many StackO ...

Enhance the appearance of a custom checkbox component in Angular

I developed a customized toggle switch for my application and integrated it into various sections. Recently, I decided to rework it as a component. However, I am encountering an issue where the toggle switch button does not update in the view (it remains t ...

What is the method for transmitting a concealed attribute "dragable" to my component?

Currently, I have successfully integrated a here map into my project, but I am now tackling the challenge of adding draggable markers to this map. To achieve this, I am utilizing a custom package/module developed by my company. This package is designed to ...

Is it possible to execute TypeScript class methods in asynchronous mode without causing the main thread to be blocked?

Creating an app that retrieves attachments from specific messages in my Outlook mail and stores the data in MongoDB. The challenge lies in the time-consuming process of receiving these attachments. To address this, I aim to execute the task in a separate t ...

Guide on removing a key from an object in TypeScript

My variable myMap: { [key: string]: string[] } = {} contains data that I need to modify. Specifically, I am trying to remove a specific value associated with a certain key from the myMap. In this case, my goal is to delete value1 from myMap[Key1]. Despit ...

Change the German number format from (0,01) to the English number format (0.01) using Angular 8

My application supports multiple languages. A user has selected German as their preferred language and I have registered it using registerLocale. I am able to convert decimal values from 0.001 (in English format) to 0,001 (in German format). However, when ...

Retrieving Data in Typescript Async Function: Ensuring Data is Returned Once All Code is Executed

I need help with waiting for data to be retrieved before returning it. The code below fetches data from indexedDB and sends it back to a component. I understand that observables or promises can accomplish this, but I am struggling with how to implement t ...

NestJS's "Exclude" decorator in class-transformer does not exclude the property as expected

I attempted to exclude a specific property within an entity in NestJS, but it appears that the exclusion is not working as expected. When I make a request, the property is still being included. Code: // src/tasks/task.entity.ts import { Exclude } from &ap ...

Struggling to access properties of a javascript object while trying to slice it within table pagination

As I work on this program, my goal is to apply a function to an Array of objects to display rows with information from this group of users. However, TypeScript is throwing various errors when I try to access this information. I'm unsure of what I&apos ...

Pairing objects by utilizing a Universal Mapper

Classes Defined: abstract class ModelBase { id: string; } class Person extends ModelBase { favoriteDog: Dog | undefined; favoriteDogId: string | undefined; dogs: Dog[] } class Dog extends ModelBase { id: string; ownerId: string; name: strin ...

Consolidate all RxJS operators into a single class property for re-exporting

Check out this code snippet from the open-source project Thingsboard. import { forkJoin, of } from 'rxjs'; ... import { catchError, map, mergeMap, switchMap } from 'rxjs/operators'; ... export class WidgetContext { ... rxjs = { ...

Adjusting the value of a mat-option depending on a condition in *ngIf

When working with my mat-option, I have two different sets of values to choose from: tempTime: TempOptions[] = [ { value: 100, viewValue: '100 points' }, { value: 200, viewValue: '200 points' } ]; tempTimesHighNumber: TempOpt ...

Error with React Query Mutation and TypeScript: The argument '{ surgeryID: any; stageTitle: any; }' cannot be assigned to a parameter of type 'void'

Utilizing react-query for fetching and posting data to my database on supabase has been really helpful. I took the initiative to create a custom hook specifically for adding records using react-query: export function useAddSurgeryStage() { const { mutate ...