[SOLVED] web worker not loading properly when using typescript on nextjs

Issue

I’m using next js for my project and it uses Webpack 5 for bundling.
according to this webworkers I can use the following syntax to load my web workers:

new Worker(new URL('./worker.js', import.meta.url));

but when I use the following:

new Worker(new URL('./worker.ts', import.meta.url));

it is loading as a media type file on the browser and not resolving imports and exports for typescript. any suggestions as to how I can resolve this issue on next js?

my tsconfig:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    }
  },
  "exclude": ["node_modules", ".next", "out"],
  "include": [
    "next-env.d.ts",
    "global.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "**/*.mdx",
    "**/*.js",
    "workers/**/*.ts"
  ]
}

Solution

Not sure if this exactly answers your question, but here is an option I’ve used for a Typescript only web worker experience. I think it is pretty neat and enables a nice object based coding model, so perhaps it meets your requirements?

DEPENDENCIES

Run these commands:

npm install comlink --save
npm install worker-loader --save-dev

DEFINE THE WEB WORKER

Add this to a typings.d.ts file:

declare module 'worker-loader!*' {

    class WebpackWorker extends Worker {
        constructor();
    }

    export default WebpackWorker;
}

CREATE THE WEB WORKER

import {expose} from 'comlink';

export class MyWebWorker {

  private readonly name: string;

  public constructor(name: string) {
    this.name = name;
  }  

  public async getData(input: string) : Promise<any> {
    return {
      message: `Hello from web worker, ${name}, ${input}`;
    };
 }
}

expose(MyWebWorker);

USE THE WEB WORKER

import {wrap, Remote} from 'comlink';
import Worker from 'worker-loader!./mywebworker';
import {MyWebWorker} from './mywebworker';

export class MyConsumingClass {

  public async callWebWorker(): Promise<void> {
  {
    const RemoteChannel = wrap<typeof MyWebWorker>(new Worker());
    const webWorker: Remote<MyWebWorker> = await new RemoteChannel("some name");
    const data = await webWorker.getData("some input");
    console.log(data.message);
  }
}

WEBPACK BEHAVIOUR

The above typings.d.ts file and worker-loader plugin means webpack 5 will output a file called mywebworker.bundle.worker.js, and note that this is lower cased. No reference to worker-loader is needed in the actual webpack file, though in my setup I used this output format, which may influence the name of the web worker bundle:

output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].bundle.js'
}

Answered By – Gary Archer

Answer Checked By – Dawn Plyler (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *