0

Currently I have a package (lets call it package A) that uses Webpack 5. Package A uses a worker. I am using the new Webpack 5 built in worker loader. I can clearly see that the file is being generated and is placed in Package A build directory.

However when I include package A as a dependency of package B the Javascript file that is used by the worker is not imported in to the build directory of the project B.

How do I solve this? Is there something in the package.json file that identifies asset files that must also be included? Is there a way to inline worker.js files so I dont have import it separately?

Any help on this is much appreciated

ZNackasha
  • 755
  • 2
  • 9
  • 29

2 Answers2

0

There is not a clean way to do this with standalone worker scripts AFAIK. You would have to instruct users to copy the worker file out of the distribution folder into their own build. Or alternatively, host the file as a separate package on a CDN which your original package or its users can request it from. There are quite a few caveats to this and either way it means making some assumptions about the environment your package is going to get used in.

However, it is relatively painless to bundle a package with inline workers. Currently, Webpack works on the assumption that you are bundling a complete project for production and not a module, and as a result inlining workers is not available in the core package. You can add this functionality by installing the actual worker-loader and passing these settings in your config:

module: {
  rules: [
    {
      test: /\.worker\.js$/,
      loader: "worker-loader",
      options: {
        inline: "no-fallback",
      },
    },
  ],
}

You may have to change your naming convention for worker files to get them to compile correctly - more info is available at the docs. The no-fallback option is specified here for inline since we don't want to create an extra file for the worker which will be unusable when someone installs our package.

lawrence-witt
  • 8,094
  • 3
  • 13
  • 32
  • thanks for the help but i could not get your example to work =( however i did find a solution that worked for me =) – ZNackasha Apr 08 '21 at 02:48
  • I recently created a [simple package](https://github.com/lawrence-witt/set-worker-timer) using Webpack 5 and `worker-loader` - it took me a while to get the config right but it was worth learning in the end. Asset loading the script is fine until it has to import other modules, either from your project or an external source. At that point you will need the bundler to treat the worker as essentially a new entry point into your project, which `worker-loader` does. There's really no need to provide your own wheel here, this has been solved for Webpack. – lawrence-witt Apr 08 '21 at 09:08
0

so the way i solved this was to do it manually. I dont think there is a loader for webpack 5 to do this but it should be easy to add an inline-worker-loader.

I created a file i called workify.ts

// URL.createObjectURL
window.URL = window.URL || window.webkitURL;

export default (code: string): Worker => {
  let blob;
  try {
    blob = new Blob([code], { type: 'application/javascript' });
  } catch (e) {
    // Backwards-compatibility
    window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
    blob = new BlobBuilder();
    blob.append(code);
    blob = blob.getBlob();
  }
  return new Worker(URL.createObjectURL(blob));
};

this file simply allows you to take a code as string and make it worker.

i then simply placed the code i wanted to run in a worker in a file ending with .worker.js

I then added the following loader to the webpack.config.js file

      {
        test: /\.worker\.js$/,
        type: 'asset/source',
      },

the asset/source type simply will load the file as string.

i can then simply

import workerify from './workerify';
import DetectWakeup from './DetectWakeup.worker.js';

const myWorker = workerify(DetectWakeup);

as you can see this can easily be turned into a loader to

ZNackasha
  • 755
  • 2
  • 9
  • 29