Giter Club home page Giter Club logo

worker-loader's Introduction

npm node deps tests coverage chat size

worker-loader

DEPRECATED for v5: https://webpack.js.org/guides/web-workers/

Web Worker loader for webpack 4.

Note that this is specific to webpack 4. To use Web Workers in webpack 5, see https://webpack.js.org/guides/web-workers/.

Getting Started

To begin, you'll need to install worker-loader:

$ npm install worker-loader --save-dev

Inlined

App.js

import Worker from "worker-loader!./Worker.js";

Config

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.js$/,
        use: { loader: "worker-loader" },
      },
    ],
  },
};

App.js

import Worker from "./file.worker.js";

const worker = new Worker();

worker.postMessage({ a: 1 });
worker.onmessage = function (event) {};

worker.addEventListener("message", function (event) {});

And run webpack via your preferred method.

Options

Name Type Default Description
worker {String|Object} Worker Allows to set web worker constructor name and options
publicPath {String|Function} based on output.publicPath specifies the public URL address of the output files when referenced in a browser
filename {String|Function} based on output.filename The filename of entry chunks for web workers
chunkFilename {String} based on output.chunkFilename The filename of non-entry chunks for web workers
inline 'no-fallback'|'fallback' undefined Allow to inline the worker as a BLOB
esModule {Boolean} true Use ES modules syntax

worker

Type: String|Object Default: Worker

Set the worker type.

String

Allows to set web worker constructor name.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          worker: "SharedWorker",
        },
      },
    ],
  },
};

Object

Allow to set web worker constructor name and options.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          worker: {
            type: "SharedWorker",
            options: {
              type: "classic",
              credentials: "omit",
              name: "my-custom-worker-name",
            },
          },
        },
      },
    ],
  },
};

publicPath

Type: String|Function Default: based on output.publicPath

The publicPath specifies the public URL address of the output files when referenced in a browser. If not specified, the same public path used for other webpack assets is used.

String

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          publicPath: "/scripts/workers/",
        },
      },
    ],
  },
};

Function

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          publicPath: (pathData, assetInfo) => {
            return `/scripts/${pathData.hash}/workers/`;
          },
        },
      },
    ],
  },
};

filename

Type: String|Function Default: based on output.filename, adding worker suffix, for example - output.filename: '[name].js' value of this option will be [name].worker.js

The filename of entry chunks for web workers.

String

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          filename: "[name].[contenthash].worker.js",
        },
      },
    ],
  },
};

Function

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          filename: (pathData) => {
            if (
              /\.worker\.(c|m)?js$/i.test(pathData.chunk.entryModule.resource)
            ) {
              return "[name].custom.worker.js";
            }

            return "[name].js";
          },
        },
      },
    ],
  },
};

chunkFilename

Type: String Default: based on output.chunkFilename, adding worker suffix, for example - output.chunkFilename: '[id].js' value of this option will be [id].worker.js

The filename of non-entry chunks for web workers.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          chunkFilename: "[id].[contenthash].worker.js",
        },
      },
    ],
  },
};

inline

Type: 'fallback' | 'no-fallback' Default: undefined

Allow to inline the worker as a BLOB.

Inline mode with the fallback value will create file for browsers without support web workers, to disable this behavior just use no-fallback value.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          inline: "fallback",
        },
      },
    ],
  },
};

esModule

Type: Boolean Default: true

By default, worker-loader generates JS modules that use the ES modules syntax.

You can enable a CommonJS modules syntax using:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          esModule: false,
        },
      },
    ],
  },
};

Examples

Basic

The worker file can import dependencies just like any other file:

index.js

import Worker from "./my.worker.js";

var worker = new Worker();

var result;

worker.onmessage = function (event) {
  if (!result) {
    result = document.createElement("div");
    result.setAttribute("id", "result");

    document.body.append(result);
  }

  result.innerText = JSON.stringify(event.data);
};

const button = document.getElementById("button");

button.addEventListener("click", function () {
  worker.postMessage({ postMessage: true });
});

my.worker.js

onmessage = function (event) {
  var workerResult = event.data;

  workerResult.onmessage = true;

  postMessage(workerResult);
};

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        loader: "worker-loader",
        options: {
          esModule: false,
        },
      },
    ],
  },
};

Integrating with ES6+ features

You can even use ES6+ features if you have the babel-loader configured.

index.js

import Worker from "./my.worker.js";

const worker = new Worker();

let result;

worker.onmessage = (event) => {
  if (!result) {
    result = document.createElement("div");
    result.setAttribute("id", "result");

    document.body.append(result);
  }

  result.innerText = JSON.stringify(event.data);
};

const button = document.getElementById("button");

button.addEventListener("click", () => {
  worker.postMessage({ postMessage: true });
});

my.worker.js

onmessage = function (event) {
  const workerResult = event.data;

  workerResult.onmessage = true;

  postMessage(workerResult);
};

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.worker\.(c|m)?js$/i,
        use: [
          {
            loader: "worker-loader",
          },
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env"],
            },
          },
        ],
      },
    ],
  },
};

Integrating with TypeScript

To integrate with TypeScript, you will need to define a custom module for the exports of your worker.

Loading with worker-loader!

typings/worker-loader.d.ts

declare module "worker-loader!*" {
  // You need to change `Worker`, if you specified a different value for the `workerType` option
  class WebpackWorker extends Worker {
    constructor();
  }

  // Uncomment this if you set the `esModule` option to `false`
  // export = WebpackWorker;
  export default WebpackWorker;
}

my.worker.ts

const ctx: Worker = self as any;

// Post data to parent thread
ctx.postMessage({ foo: "foo" });

// Respond to message from parent thread
ctx.addEventListener("message", (event) => console.log(event));

index.ts

import Worker from "worker-loader!./Worker";

const worker = new Worker();

worker.postMessage({ a: 1 });
worker.onmessage = (event) => {};

worker.addEventListener("message", (event) => {});

Loading without worker-loader!

Alternatively, you can omit the worker-loader! prefix passed to import statement by using the following notation. This is useful for executing the code using a non-WebPack runtime environment (such as Jest with workerloader-jest-transformer).

typings/worker-loader.d.ts

declare module "*.worker.ts" {
  // You need to change `Worker`, if you specified a different value for the `workerType` option
  class WebpackWorker extends Worker {
    constructor();
  }

  // Uncomment this if you set the `esModule` option to `false`
  // export = WebpackWorker;
  export default WebpackWorker;
}

my.worker.ts

const ctx: Worker = self as any;

// Post data to parent thread
ctx.postMessage({ foo: "foo" });

// Respond to message from parent thread
ctx.addEventListener("message", (event) => console.log(event));

index.ts

import MyWorker from "./my.worker.ts";

const worker = new MyWorker();

worker.postMessage({ a: 1 });
worker.onmessage = (event) => {};

worker.addEventListener("message", (event) => {});

webpack.config.js

module.exports = {
  module: {
    rules: [
      // Place this *before* the `ts-loader`.
      {
        test: /\.worker\.ts$/,
        loader: "worker-loader",
      },
      {
        test: /\.ts$/,
        loader: "ts-loader",
      },
    ],
  },
  resolve: {
    extensions: [".ts", ".js"],
  },
};

Cross-Origin Policy

WebWorkers are restricted by a same-origin policy, so if your webpack assets are not being served from the same origin as your application, their download may be blocked by your browser. This scenario can commonly occur if you are hosting your assets under a CDN domain. Even downloads from the webpack-dev-server could be blocked.

There are two workarounds:

Firstly, you can inline the worker as a blob instead of downloading it as an external script via the inline parameter

App.js

import Worker from "./file.worker.js";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        loader: "worker-loader",
        options: { inline: "fallback" },
      },
    ],
  },
};

Secondly, you may override the base download URL for your worker script via the publicPath option

App.js

// This will cause the worker to be downloaded from `/workers/file.worker.js`
import Worker from "./file.worker.js";

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        loader: "worker-loader",
        options: { publicPath: "/workers/" },
      },
    ],
  },
};

Contributing

Please take a moment to read our contributing guidelines if you haven't yet done so.

CONTRIBUTING

License

MIT

worker-loader's People

Contributors

alexander-akait avatar cap-bernardito avatar csharpermantle avatar dtinth avatar evilebottnawi avatar frogthefrog avatar grind086 avatar joshwiens avatar kevinzwhuang avatar kevzettler avatar knagis avatar matthewsteel avatar michael-ciniawsky avatar rafi993 avatar ramasilveyra avatar renchap avatar schl3ck avatar shellscape avatar simon04 avatar smelukov avatar snitin315 avatar sokra avatar spacek33z avatar thallada avatar tobek avatar tomlagier avatar trusktr avatar trysound avatar visvirial avatar zeripath avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

worker-loader's Issues

webpack-defaults upgrade

Addition of webpack-defaults & associated refactoring as a part of the next Major release

Issue exists for status tracking across the organization.

Please do not close

Worker bundle contains first level deep dependencies

When the worker code imports modules (first level) which import other modules (second level), then modules from second level are not included in the output worker bundle file.

Here's an illustration:
Worker.js -> import moduleA -> import moduleB

The moduleA will be included in the worker.bundle.js, while moduleB will not be included.

Is this the expected behaviour or an I doing something wrong?

[Docs] Typescript Usage

The documentation for worker-loader here

https://webpack.js.org/loaders/worker-loader/

Has a section at the end titled 'Integrating with Typescript'. That has sections showing how to create a typings/custom.d.ts file, and how to import into App.ts.

However it does not show how the web worker should be defined in Typescript.

Also the code in the other examples won't work in a Typescript file as self.postMessage({ result: 'Fred'}) won't transpile in Typescript.

It seems the function signature for postMessage in Typescript is different from what works in Javascript.

Can someone complete the documentation with a functioning Typescript example please.

[Question] Get blob URL instead of worker instance

I want to use this loader in Angular project to bootstrap application via @angular/webworker-platform.

And that API requires to pass a URL string and then angular itself will bootstrap and instantiate the worker.

So my question is can I somehow get just a blob URL of the worker script and not an object to call new on it?

Thanks

Doesn't seem to honor externals configuration

I have a project which uses this loader and emits two bundles, a main script and a worker script that should run in a web worker. Both of these scripts include a 3rd party library that deals with doing some crypto operations. These libraries have conditionals in them that deal with the Node crypto library and optionally attempt to run require('crypto'). I don't need the crypto-browserify plugin included in my builds so I've told webpack to ignore these includes by setting my externals in my config like so:

externals: {
   crypto: "crypto",
},

This works great for the main script and it only includes the files I expect. However, when the worker.js script gets output, it includes all of the crypto-browserify library, which ends up being a few hundred K of code. I don't quite understand why the externals config would work for the main script but not for the web worker script, but I haven't been able to figure out a way for webpack to ignore the require("crypto") line that ends up in my web worker.

imports and stuff?

Doesn't seem like this lets us import anything inside the worker. For example, in the worker, I'd like to do

import TWEEN from 'tween.js'

// ...

Or did I miss how it works?

importScripts() only works when imported script is in root

My angular2 app uses web workers and uses webpack for bundling.

My worker and its supporting scripts are in one directory (upload/). The script that does the require('worker!...') is one directory up from (upload/). In my worker script, I have an importScripts('encoder.js'), which I believe is the correct path since the worker and encoder.js are both in the same (upload/) directory.

My app keeps looking for encoder.js in the root directory and not in the upload/ directory. How do I make it so that webpack informs importScripts() of where encoder.js is?

How do I minify the worker chunk?

It seems I have to use LoaderOptionsPlugin to set options.worker.plugins (https://github.com/webpack-contrib/worker-loader/blob/v0.8.0/index.js#L42), but when I use that to add new webpack.optimize.UglifyJsPlugin({}) to options.worker.plugins, I get this error:

Module build failed: TypeError: Cannot read property 'replace' of undefined
    at new RequestShortener (node_modules/webpack/lib/RequestShortener.js:11:24)
    at UglifyJsPlugin.apply (node_modules/uglifyjs-webpack-plugin/dist/index.js:40:27)
    at Compiler.apply (node_modules/tapable/lib/Tapable.js:306:16)
    at options.plugins.forEach.plugin (node_modules/worker-loader/index.js:52:54)
    at Array.forEach (native)
    at Object.pitch (node_modules/worker-loader/index.js:52:21)

I'm using webpack 3.5.6

LoaderOptionsPlugin config:

new webpack.LoaderOptionsPlugin({
	options: {
		// context: path.resolve(__dirname, ".."),
		worker:  {
			plugins: [
				new webpack.optimize.UglifyJsPlugin({
					compress: {
						warnings: false,
					},
					sourceMap: false,
				}),
			],
		},
	},
}),

I tried with and without context in LoaderOptionsPlugin, it fails with the same error either way.

duplicate chunks

I use PDF.js library that use a web worker for pdf rendering (pdf.worker.js).
PDF.js also has a fallback mode for browsers that does not support web workers (it just use pdf.worker.js without a web worker).

var pdfjs = require('./build/pdf.js');
var PdfjsWorker = require('worker-loader!./build/pdf.worker.js');
...
pdfjs.PDFJS.workerPort = new PdfjsWorker();

source

build/pdf.js also requires the pdf.worker.js as fallback

      worker = require('./pdf.worker.js');

source

All of this lead to a duplicate of pdf.worker.js (> 600KB).

Is it possible to ask worker-loader to keep pdf.worker.js common ?

(maybe related to issue #70)

[Bug] incorrect worker file paths

I have an app at domain.com/subfolder/
I'm doing an inline import of a worker script in one of the files.
import * as MyWorker from "worker-loader!./myWorker";

The resulting file name what the browser is trying to load is:
http://domain.com/subfolder793f4dbaa1493689665f.worker.js

That is missing a trailing slash between the folder and the file name, so the file is not found. I tried figuring out a configuration, which could let me set webpack public path for worker-loader specifically, but couldn't find it yet.

Could you push me into the right direction with this?

[Feature] support code splitting?

Before I used webpack I was able to share some common libs with main code and the worker through a separate file that was loaded on both sides.

I see that CommonsChunkPlugin separate libs from app code. When I use it I see that my main javascript file gets smaller but my worker file stays the same even though they both use common libs.

Is there any way I can get it to optimize the worker size also (so that it uses the common script file)?

[Feature] support for ignoring modules

We are using the following function in order to keep certain modules (generally platform specific dependancies like sqlite3) from being bundled into our webpack bundle which will cause any module in the array to be manually required instead:

  externals: [
    (function () {
      var IGNORES = [
        'buffer',
        'fs',
        'electron',
        'sqlite3',
        'JSONStream',
        'request',
        'zlib',
        'bindings',
        'leveldown',
        'pouchdb',
        'canvas'
      ];
      return function (context, request, callback) {
        if (IGNORES.indexOf(request) >= 0) {
          return callback(null, "require('" + request + "')");
        }
        return callback();
      };
    })()
  ]

When loading a worker that uses any of those modules directly or uses a module that uses them, webpack attempts to trace back these require statements instead of ignoring them as the above config dictates leading to build errors like:

    ERROR in ./~/sqlite3/~/node-pre-gyp/lib/info.js
    Module not found: Error: Can't resolve 'aws-sdk' in '/Users/symbyte/projects/my-project/node_modules/sqlite3/node_modules/node-pre-gyp/lib'
     @ ./~/sqlite3/~/node-pre-gyp/lib/info.js 14:14-32
     @ ./~/sqlite3/~/node-pre-gyp/lib ^\.\/.*$
     @ ./~/sqlite3/~/node-pre-gyp/lib/node-pre-gyp.js
     @ ./~/sqlite3/lib/sqlite3.js
     @ ./~/ts-loader?{"useTranspileModule":true}!./~/tslint-loader?{"configFile":"/Users/symbyte/projects/my-project/tslint.json"}!./~/tslint-loader!./src/app/data/workers/geojson-io.worker.ts

Is there some way to get worker-loader to acknowledge this part of my webpack config, have I done something incorrectly, or is this a bug?

Uncaught SecurityError: Failed to construct 'Worker': Script

Apologies if I'm misunderstanding something obvious, but I'm unable to load a worker script with this loader. The error I'm getting is...

Uncaught SecurityError: Failed to construct 'Worker': Script at 'http://localhost:9010/console-assets/6edae5507e4e62f5e077.worker.js' cannot be accessed from origin 'http://localhost:3000'.
  module.exports @SearchIndex.js:2
  Search @Search.js:32
  ...

My code is basically the same as what's in the README:

import Worker from 'worker!./SearchIndex'

const worker = new Worker()

My local application is running on port 3000 via webpack-dev-server. Any advice?

Webpack 3.0 support

The peerDependancies needs to be updated to allow Webpack 3.0.

After a yarn upgrade webpack && yarn upgrade, tests are not passing (same error for all):

     TypeError: Cannot read property 'map' of undefined
      at makeBundle.then (test/index.js:39:9)
      at <anonymous>

I am not familiar enough with Webpack's internals to provide a fix.

Need to load modules from other chunks

Do you want to request a feature or report a bug?
Request a feature

What is the current behavior?
When importing modules in a worker, all module code is included, whether or not other chunks define the module elsewhere, and whether or not CommonsChunkPlugin is used.

If the current behavior is a bug, please provide the steps to reproduce.
There is an example of the current behavior at this repo.

What is the expected behavior?
It should be possible to import chunks/modules via importScripts when possible.

If this is a feature request, what is motivation or use case for changing the behavior?
Importing other chunks via importScripts from workers in order to access modules will drastically decrease worker size and load time.

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

This issue is for Webpack 2.x.x with worker-loader 0.8.1

Related: #70 #86

Make worker cacheable

Can the worker be made cacheable? I'm happy to create a pull request if it's possible.

[Feature] support `DedupePlugin`

When using webpack.DedupePlugin, it is dropping lines like import 'babel-polyfill' if they are defined both in worker and in global scope.

Loader crashes if there is a syntax error

I am not sure if it is a bug or a feature.

But basically, if make a JS syntax error in file loaded via the worker-loader you will see some not-so-helpfull error.

a

Other loaders point out a syntax error.

window is undefined when creating worker-in-worker

I created pull #12 to fix the issue I'm seeing. Not sure if you want to pull it in or what. All I did was wrap:

(function (w) {
// a copy of the existing code with "window" being replaced by "w"
}(this));

The issue popped up when I started creating inline workers inside of inline workers...

"Script file not found" When Using worker-loader With Webpack Dev Server

The worker loader works fine for me when I use webpack to create my distribution files.

When I use webpack dev server in hot reload mode, however, I get this error message on the browser console: Script file not found: js/3a7e2f55336ef9a3d972.worker.js

It seems that the script tries to load the worker bundle not from the dev server running on localhost:8080 (like the main bundle), but from the local file system.

I tried using the worker loader both through my webapp config (as post loader) and through worker! in my require statement, with the same result, it works with webpack, but not with webpack dev server.

link to my project

Error: Cannot find module 'worker!./[workername]'

So I'm having some issues that are difficult to debug. I'm creating an npm module library to be used in a separate project that includes that module. So I've been building the module - it creates a bundle.js and a separate worker file with it in the build directory - then I run the project, and I don't get any errors, but it doesn't seem like the Worker is actually doing anything/receiving my messages. Maybe it's not actually finding the file because it's in a separate module/not linked correctly?

So I tried to test this in the project itself by putting the Worker source file in the same directory as my index.js, building, and running. But when I run it, I get this error:

Error: Cannot find module 'worker!./[workername]'

For reference, This is excerpted from my code (I'm using React):

var [workername] = require('worker!./[workername]');

...

class ComponentName extends React.Component {
  ...
  componentDidMount () {
    var worker = new [workername]();
    function logMessage (e) {
      console.log(e.data);
    }
    worker.onmessage = logMessage;
    console.log('worker made',worker);
    setInterval(function () {
      worker.postMessage('start');
    }, 1000);
  }
}

and this is my worker (but not sure if that matters since it doesn't even recognize the module!):

self.onmessage = function (e) {
    postMessage('message received!');
};

Help?

[Bug] `importScripts` inside web worker loses context

I'm facing a bug here.
I'm using worker-loader to load webworkers in my project. My web worker script uses importScripts to download other scripts and execute them. According to

The browser loads each listed script and executes it. Any global objects from each script may then be used by the worker.

However, this is not what happens when I use worker-loader.

This is what happens.

var Worker = require("worker-loader!./myWorker.js");
var worker = new Worker;

// myWorker.js
var x = x || {};
importScripts("a.js");
x.name // "undefined"


//a.js
var x = x || {};
x.name = "hello";

This is what happens (expected) when I don't use a worker-loader

var worker = window.Worker("myWorker.js");

// myWorker.js
var x = x || {};
importScripts("a.js");
x.name // "hello"


//a.js
var x = x || {};
x.name = "hello";

I've created a test repo in case you want to reproduce it.
worker-loader

webpack version: 2.2.1
worker-loader version 0.7.1
node version 6.9.5

worker-loader makes it very hard to distribute code

Our main gripe is that it still insists spitting out a separate file, even if the inline option is set to true. This forces everyone using the component to change their webpack configs:

plugins: [
    new webpack.LoaderOptionsPlugin({ 
        options: { 
            worker: { 
                output: { filename: 'build/worker.js' } 
            } 
        } 
    }),

๐Ÿ˜จ

... or else worker-loader will stack randomly hash-named files into the projects root dir, which is very impractical. All our customers have complained about this and we just don't know what to do. We could bundle all code and create a Blob by hand, but that would mix gulp stuff into webpack again.

I suggest that

  1. inline finally respects the true setting without fallbacks

  2. it fetches the chunkFilename to determine where to store the file and under which name

Best solution would be if a loader existed that could cook a readymade, require-resolved bundle so that we can use it together with raw-loader in order to create our own blobs.

Name worker chunk files

I have two different workers. The only way to distinguish the output files is to include [hash] which means my output directory gets flooded with old versions of my worker files. It would be nice to be able to specify the name, or automatically pull it from the entry filename.

I wrote a quick workaround in index.js:

// ...
var workerCompiler = this._compilation.createChildCompiler("worker", outputOptions);
workerCompiler.apply(new WebWorkerTemplatePlugin(outputOptions));

// get the specified name from the query, or fall back to the filename without its extension
var requestName = query.name || request.replace(/^.*[\\\/](.*)(\.[^\.]*)$/, '$1');
workerCompiler.apply(new SingleEntryPlugin(this.context, "!!" + request, requestName));
if(this.options && this.options.worker && this.options.worker.plugins) {
// ...

[Feature] support `ServiceWorker`

Yes, I know, they are different things. But...

  • ... serviceworker-loader, is dead
  • ... and it is basically a copy of an old version of this, with minor adjustments
  • ... because most of the webpack code is the same for a service worker (emit a new file, allow instanciation), only the instanciation helper is different
  • ... and they don't share the "worker" part of their name for no reason :)

Basic description of worker-loader's purpose

I created an issue here webpack/webpack.js.org#1161, but was asked to add to individual projects

I really love the documentation improvements that came with the new webpack 2 website. However, I find it frustrating that some of the promoted plugins/loaders on the webpack website do not have simple descriptions of their purpose.

For example, https://github.com/webpack-contrib/worker-loader states

Worker loader for Webpack.

What is a Worker Loader? Why might I want it?

There is a lot of implicit knowledge that we're expecting developers to have. This makes it hard and intimidating for new users to start using the platform. My suggestion is to make sure that, at a minimum, worker-loader add an easily understandable description of its purpose, such that a layman could make sense of their intended use.

Prevent file fallback for inline workers

Can there be an option that prevents worker-loader from splitting extra files for inline workers? We build a single-output library that works with newer browsers which support webGL, so IE9 is out of the question anyway. We need this to be a single bundle and push it straight to bower from the /dist folder.

I explicitely request a blob by doing:

import WebWorker from 'worker?inline=true!./worker';

Worker-loader seems to acknowledge and adds a blob to the bundle but dumps out files into /dist anyway. I know this was done to make it work for very old browsers, but if these were important to us we wouldn't use inline in the first place.

Something like ?inline=true&fallback=false would work for us.

Loading workers doesn't work at all without inline mode

I've only been able to get the Worker Loader to work in inline mode. Compiling worker files separately results in the worker immediately triggering its onerror event โ€” except event.message is undefined. No code inside the worker's .js file appears to be executed. I've even tried commenting out the entirety of a worker file save for a single console.log statement, and this doesn't execute either.

My Webpack config includes:

postLoaders: [{
    test: /\.worker\.js$/,
    loader: "worker-loader?inline=true"
}],

when it works. Changing loader to "worker-loader" causes the failure.

I'm using these helper functions to interact with workers:

//callWorker.js

// Returns a promise that resolves after a web worker sends its next message
export function nextWorkerMessage(worker, terminate = false) {
    return new Promise((resolve, reject) => {
        worker.onmessage = ({data}) => {
            worker.onmessage = null;
            worker.onerror = null;
            if (terminate) worker.terminate();
            resolve(data);
        };
        worker.onerror = ({message}) => {
            worker.onmessage = null;
            worker.onerror = null;
            worker.terminate();
            reject(message);
        };
    });
}

// Create a new web worker from a constructor, then pass the args in a
// postMessage. Returns a promise that resolves after its next message, and
// then terminates the worker.
export default function callWorker(workerConstructor, ...args) {
    let worker = new workerConstructor();
    const promise = nextWorkerMessage(worker, true);
    const message = [...args];
    // If there are multiple args, pass them as an array. If there's
    // only one, pass it by itself
    if (message.length > 1) {
        worker.postMessage([...args]);
    } else {
        worker.postMessage(args[0]);
    }
    return promise;
}

And then in my app, something like this:

import callWorker from "callWorker";
import MyWorker from "myWorker.worker.js"; // Webpack is configured to load this with worker-loader

async function mainFn() {
    const result = await callWorker(MyWorker, "Send this message");
}

All of this works fine in inline mode, but disabling inline mode causes it to fail. I've even tried directly importing MyWorker in the same file where callWorker is defined to see if that cleared things up, but it didn't.

I'm not really sure how to go about debugging this further.

"extract-text-webpack-plugin" loader is used without the corresponding plugin

ModuleBuildError: Module build failed: ModuleBuildError: Module build failed: Error: "extract-text-webpack-plugin" loader is used without the corresponding plugin, refer to https://github.com/webpack/extract-text-webpack-plugin for the usage example at Object.module.exports.pitch

I get this error whenever I try to use this. Can anyone help me out.

This is how i am trying to import my worker
var MyWorker = require("worker?inline!./../../../workers/TaskExportWorker.js");

Unable to require native modules when targeting node-webkit

As the title says, it is not possible to import native node modules when setting target to node-webkit.

Steps to reproduce

test.worker.js

var stream = require('stream') // native node module

index.js

require('./test.worker')

webpack.config.js

var config = {
  entry: './index.js',
  target: 'node-webkit',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'dist/'
  },
  module: {
    loaders: [{
      test: /\.worker.js$/,
      loader: 'worker-loader',
    }],

  }
};

module.exports = config;

Actual result

 ERROR in ./test.worker.js
 Module not found: Error: Can't resolve 'stream' in '/Users/samvv/Projects/orion/isolate'
 @ ./test.worker.js 2:13-30

Expected behaviour

No errors. Require to native module is preserved.

Cannot resolve node.js core modules in Webpack 2

After I migrated from webpack 1 it started to throw following errors:

Module not found: Error: Can't resolve 'path' in /absolute-file-path

Modules, which cause errors are: path, fs, vm, crypto and constants

I've figured out that webpack can't resolve it only when it required from file, which was processed by worker-loader.

Tried to load it via require(worker-loader!file-name.js) syntax and via webpack.config.js settings

Here is my webpack.config.js:

const config = {
  target: 'electron-renderer',
  context: __dirname,
  entry: { app: './app.js', vendor: [/*vendors*/]},
  cache: true,
  devtool: 'source-map',
  watch: false

  resolve: {
    extensions: ['.js', '.json', '.jsx'],
    modules: ["node_modules"]
  },

  module: {

    rules: [
      {test: /\.html/, loader: 'html-loader'},
      {test: /worker\.js/, loader: 'worker-loader'},
      {
        test: /\.less$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: ["css-loader?sourceMap", "less-loader?sourceMap"]
        })
      },
      {
        test: /\.css/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader?sourceMap"
        })
      },
      {test: /\.(jpg|png|gif|jpeg|svg|otf|ttf|eot|woff)$/, loader: 'url-loader?limit=10000'}
    ]
  },

  plugins: [

    new ExtractTextPlugin('styles.[contenthash].css'),

    new webpack.optimize.CommonsChunkPlugin({
      names: ['commons', 'vendor', 'manifest'],
      minChuncks: Infinity
    }),

    new HtmlWebpackPlugin({
      template: './index.html',
      filename: 'index.html',
      hash: false,
      inject: 'head',
      cashe: true,
      showErrors: true
    })

  ],

  output: {
    publicPath: './',
    path: path.join(__dirname, 'dist'),
    filename: '[name].[chunkhash].js',
    chunkFilename: '[name].[chunkhash].js'
  }
};

module.exports = config;

Document Interop with Typescript

I'm not sure the best place for this, if it's a candidate for addition to the README. Currently it's buried in the awesome-typescript-loader issues, and I'd love to get some more visibility as I spent a chunk of time trying to get it functional. This is how you can make the worker-loader function with Typescript 2+

App.ts

import * as MyWorker from "worker-loader!../../worker";
const worker: Worker = new MyWorker();

typings/custom.d.ts

declare module "worker-loader!*" {
  const content: any;
  export = content;
}

Use in Cordova

Hi,

Has anyone got web workers to work in a cordova context? When I take a look at the js resources loaded into IOS app, I don't see a file for the web worker.

Multiple entries / output

Hi,

Looking at the code, it looks like the loader does not manage the "entry:" directive inside the "worker:" directive of webpack.config.js, and that it takes by default entries[0] in runAsChild()

Is there a way for the loader to manage several worker files?

Thank you for any help!

How to use with babel-loader ?

I'm trying to use worker-loader with babel for es6 import support in web worker code. The readme says this is possible but I guess I need a better example.

I have the following setup in my webpack.config.js

   {
     test: /\.worker\.js$/,
     loader: "worker!babel",
     presets: ['es2015']
   }

This correctly produces a sepearte bundle file for the worker with a hash name like d46f60b8e184bf8b1cb8.worker.js

However this file is not run through the Babel transforms and converted to es5. So it contains raw es6 import statmenets and syntax that is failing in a browser. Looks like:

/* 0 */
/***/ function(module, exports) {

    import _ from 'lodash';

    var o = {foo: 'foo'};

    _.has(o, 'foo'); // true

    setInterval(() => {
       postMessage({tick: Date.now()});
    }, 1000);


/***/ }
/******/ ]);

I have tried switching the order of the loaders like:

   {
     test: /\.worker\.js$/,
     loader: "babel!worker",
     presets: ['es2015']
   }

and also tried moving it to preLoaders and postLoaders with no success.

Upgrade to webpack >= v2.0.0 causes output script to be larger

We recently upgraded to webpack2.5.1 which increased the bundle of worker.js script

                                     Asset     Size  Chunks                    Chunk Names
            9ecf2d4a6705b3ec6e59.worker.js   4.6 MB          [emitted]  [big]

Before,

                                 Asset     Size  Chunks             Chunk Names
            0a49cd42e52df7a50b2f.worker.js  3.29 MB          [emitted]

We require like below,

var RenderWorker = require('worker-loader?proxy=%2Fworkers%2F!../workers/website-renderer');

Also upgraded to latest [email protected]

Thoughts and pointers would be much appreciated.

Error in Safari Mac OS

Hello,

I got an error on the worker chunk file:

        // Convenience aliases.
        var objectProto = Object.prototype
dc85ec888f7b03108b40.worker.js:12880TypeError: undefined is not an object (evaluating 'Object.prototype')

It works fine on Chrome and Firefox. These are the versions I use:
Node 5.6.0
Npm 3.8.8
Babel 6

"webpack": "^1.12.9"
"worker-loader": "^0.7.0"

In my code:

import WebWorker from 'worker!client/workers/webWorker'
const webWorker = new WebWorker()

Thank you for your help

Require is not defined: external "os"

Hello,
In my worker, when trying to use the "os" module I get the following error:

Require is not defined: external "os"

Even though the os module is installed and present in my node_modules folder.
Is there any way around this?

The thing is, my most expensive tasks rely on modules that in turn seem to rely on either "os" or "fs", so I'm pretty much stuck for now.
Thank you

change worker file path inline

Hey guys,

Is there anyways to override the path inline? Or how I can fix it in the webpack config. Tried all the examples i the documentation with no luck.

I am using this angular 2 seed here. https://github.com/UIUXEngineering/web-worker-in-ng

We have to transpile the worker before angular so we use a separate webpack config https://github.com/UIUXEngineering/web-worker-in-ng/blob/master/webpack.worker.config.js

This is how we load the workers
`
import { Injectable } from '@angular/core';
import * as DemoOneWorker from 'worker-loader!../../web-workers/worker-demo1/demo1.worker.bundle.js';
import * as DemoTwoWorker from 'worker-loader!../../web-workers/worker-demo2/demo2.worker.bundle.js';

@Injectable()
export class WebWorkerService {

demoOneWorker: Worker = new DemoOneWorker();
demoTwoWorker: Worker = new DemoTwoWorker();

constructor() {
}

initialize() {

// Demo 1 worker
this.demoOneWorker.onmessage = function ( event ) {
  const data = event.data; // "This text was generated by template B"
  console.log('Web Worker ONE Response: ', data);
};

const that = this;

setTimeout(function () {
  console.log('\n\nPosting message to web worker ONE');
  that.demoOneWorker.postMessage('Worker ONE Data');
}, 1000);

// Demo 2 worker
this.demoTwoWorker.onmessage = function ( event ) {
  const data = event.data; // "This text was generated by template B"
  console.log('Web Worker TWO Response: ', data);
};

setTimeout(function () {
  console.log('\n\nPosting message to web worker TWO');
  that.demoTwoWorker.postMessage('Worker TWO Data');
}, 2000);

}

}`
Not sure how to go about fixing this.

ignore

Glitch in the Matrix, please ignore

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.