Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular: Using TypeScript for Service Worker (ServiceWorkerModule)

Is it possible to register a ServiceWorker written in TypeScript with @angular/service-worker?

currently registering a service worker looks like this in app.module.ts:

ServiceWorkerModule.register('ngsw-worker.js', {
  enabled: environment.production
})

Is it somehow possible to register a ngsw-worker.ts?

At least this is possible with web workers in Angular:

const worker = new Worker('../my-worker.worker', {
      type: 'module'
    });

my-worker.worker.ts

/// <reference lib="webworker" />

import {someMethod} from './some-method';

addEventListener('message', ({ data }) => {
  const response = `worker response to ${data}`;
  postMessage(response);
  someMethod();
});

Any help is appreciated - thanks

like image 849
kerosene Avatar asked Sep 08 '26 00:09

kerosene


1 Answers

As a beginner with Angular/TypeScript/Javascript I've tried the same for a few days. My intents were to use TypeScript as my main language to use it as an es5 transpiler, so I don't have to worry about:

  • language versioning (es5, es2015, ...)
  • bundling
  • linting
  • etc

And I think I've got a nice, yet weird solution with uses the worker-plugin, available starting with Angular8. Adjusted for Angular16.

First of all: you need to enable webworkers in angular and serviceworker. The angular.json then contains

"build": {
 "options": {
    "webWorkerTsConfig": "tsconfig.workers.json",
    ...
  }
  "configurations": {
    "production": {
      "serviceWorker": true,
      "ngswConfigPath": "src/ngsw-config.json"
      ...
    }
  }
}

Note: This is only in production mode. Probably to keep browser/cache/install sideeffects away from ng serve. Somehow I've also lost this configuration during an ng update.

Example:

tsconfig.workers.json

Allowing all kinds of web-workers

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/workers",
    "lib": [
      "es2018",
      "webworker"
    ],
    "types": []
  },
  "include": [
    "src/**/*.worker.ts"
  ]
}

workers/service-worker.worker.ts

This is the example target code.

// Import angular serviceworker
importScripts("ngsw-worker.js");

// custom code
addEventListener("message", (data) => {
    console.log(data);
});

workers/service-worker-config.ts

Angular generates hashed names for its *.js output. We need to grab this name.

import { environment } from "../../environments/environment";

export let generatedServiceWorkerUrl: string = null;
(function generateUrl(): void {
    // Override the real Worker with a stub
    // to return the filename, which will be generated/replaced by the worker-plugin.
    // @ts-ignore
    Worker = class WorkerStub {
        constructor(public stringUrl: string, public options?: WorkerOptions) {}
    };

    const worker = new Worker(new URL("./service-worker.worker", import.meta.url), { type: "module" }) as any;
    generatedServiceWorkerUrl = worker.stringUrl;
})();

export const serviceWorkerConfig = {
    enabled: environment.production,
    serviceWorkerUrl: generatedServiceWorkerUrl
};

app.module.ts

import { serviceWorkerConfig  } from "./workers/service-worker-config";

@NgModule({
    declarations: [AppComponent],
    entryComponents: [],
    imports: [
        [...],
        ServiceWorkerModule.register(serviceWorkerConfig.serviceWorkerUrl, { enabled: serviceWorkerConfig.enabled })
    ],
    providers: [...],
    bootstrap: [AppComponent]
})
export class AppModule {}
like image 99
Kelon Avatar answered Sep 10 '26 16:09

Kelon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!