Work with web-workers using comlink on a webpack5 project with typescript

Viewed 972

I have a project written on Typescript and bundeled using webpack5. I try to use web-workers to off-load some of the code from the min thread.

main.worker.ts:

import { expose } from 'comlink';
import  {TimeConsumingFunction} from "./TimeConsumingFunction"

const exports = {
    TimeConsumingFunction
};

export type WorkerInterfaceTimeConsumingFunction = typeof exports;
export default null as any;
expose(exports);

main.ts:

import { wrap } from 'comlink';
import {WorkerInterfaceTimeConsumingFunction, default as DataPixelsWorker} from './main.worker';


const worker = new Worker(new URL("./main.worker", import.meta.url));
const workerApi = wrap(worker);

let result = await workerApi.TimeConsumingFunction();

tsconfig:

{
  "compilerOptions": {
    "target": "es3",
    "module": "esnext",
    "lib": ["webworker", "es2018", "dom"],
    "allowJs": true,
    "checkJs": false,
    "sourceMap": true,
    "removeComments": false,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "esModuleInterop": true
},
  "include": [
      "./**/*"
  ],
  "exclude": [
      "./plugins/**/*",
      "./typings/**/*",
      "./dev/**/*",
      "./dist/**/*"
  ]
}

webpack.js:

const path = require('path');

module.exports = [
    {
        entry: './main.ts',
        mode: 'production',
        target: ['web', 'es5'],
        module: 
        {
            rules: 
            [
                {
                    test: /\.worker\.(js|ts)$/,
                    use: { loader: 'worker-loader' }
                },
                {
                    test: /\.tsx?$/,
                    use: 'ts-loader',
                    exclude: /node_modules/
                }
            ]
        },
        resolve: 
        {
            extensions: [ '.tsx', '.ts', '.js' ]
        },
        output: 
        {
            path: path.resolve(__dirname, 'dist'),
            filename: 'main.js'
        },
        optimization: 
        {
            minimize: true,
        },
        stats: 
        {
            colors: true
        }
    }
];

Package.json:

{
  "name": "Project",
  "sideEffects": false,
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --progress --config=./webpack.js --mode production --output-path ./dist/."
  },
  "devDependencies": {
    "@babel/core": "^7.14.6",
    "@babel/plugin-proposal-class-properties": "^7.14.5",
    "@babel/plugin-proposal-decorators": "^7.14.5",
    "@babel/plugin-transform-runtime": "^7.14.5",
    "@babel/preset-env": "^7.14.5",
    "@babel/preset-typescript": "^7.14.5",
    "babel-loader": "^8.2.2",
    "ts-loader": "^4.5.0",
    "typescript": "^4.2.4",
    "webpack": "^5.36.0",
    "webpack-cli": "^4.6.0",
    "webpack-version-file-plugin": "^0.4.0",
    "worker-loader": "^3.0.8"
  },
  "dependencies": {
    "@babel/runtime": "^7.14.6",
    "comlink": "^4.3.1",
    "core-js": "^3.11.2"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

When the project is transpiled using the command npm run build the output contains 2 files:

  1. main.js
  2. main.worker.js

The output files are uploaded to a CDN. The files will be loaded from the URL https://www.example.com/main.js.

The content is loaded from the URL https://www.example-content.com The content contains the following script tag <script src='https://www.example.com/main.js'></script>

When the content is loaded, the following error appears on the browser's console:

main.js?x=1111:1 Uncaught (in promise) DOMException: Failed to construct 'Worker': Script at 'https://www.example.com/main.worker.js' 
cannot be accessed from origin 'https://www.example-content.com'.

    at e.<anonymous> (https://www.example.com/main.js?x=1111:1:313839)

Because the script is loaded from a CDN that is accessible through a different domain than the content that loads the script I think the best way is to bundle the files main.worker.js into main.js. Is there a way doing that with webpack 5? Is there another way to overcome this problem?

0 Answers
Related