Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

workerize-loader

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

workerize-loader - npm Package Compare versions

Comparing version 1.3.0 to 2.0.0

68

dist/index.js

@@ -43,13 +43,11 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var cb = this.async();
var filename = loaderUtils.interpolateName(this, (options.name || '[hash]') + ".worker.js", {
context: options.context || this.rootContext || this.options.context,
regExp: options.regExp
});
var compilerOptions = this._compiler.options || {};
var filename = (options.name || '[fullhash]') + '.worker.js';
var worker = {};
worker.options = {
filename: filename,
chunkFilename: "[id]." + filename,
namedChunkFilename: null
chunkFilename: filename,
publicPath: options.publicPath || compilerOptions.output.publicPath,
globalObject: 'self'
};
var compilerOptions = this._compiler.options || {};

@@ -60,3 +58,3 @@ if (compilerOptions.output && compilerOptions.output.globalObject === 'window') {

worker.compiler = this._compilation.createChildCompiler('worker', worker.options);
worker.compiler = this._compilation.createChildCompiler("worker " + request, worker.options);
new WebWorkerTemplatePlugin(worker.options).apply(worker.compiler);

@@ -85,19 +83,14 @@

new SingleEntryPlugin(this.context, "!!" + path.resolve(__dirname, 'rpc-worker-loader.js') + "!" + request, 'main').apply(worker.compiler);
var subCache = "subcache " + __dirname + " " + request;
var bundleName = path.parse(this.resourcePath).name;
new SingleEntryPlugin(this.context, "!!" + path.resolve(__dirname, 'rpc-worker-loader.js') + "!" + request, bundleName).apply(worker.compiler);
compilationHook(worker.compiler, function (compilation, data) {
if (compilation.cache) {
if (!compilation.cache[subCache]) compilation.cache[subCache] = {};
compilation.cache = compilation.cache[subCache];
}
parseHook(data, function (parser, options) {
exportDeclarationHook(parser, function (expr) {
var decl = expr.declaration || expr,
_parser$state = parser.state,
var decl = expr.declaration || expr;
var _parser$state = parser.state,
compilation = _parser$state.compilation,
current = _parser$state.current,
entry = compilation.entries[0].resource; // only process entry exports
current = _parser$state.current;
var entryModule = compilation.entries instanceof Map ? compilation.moduleGraph.getModule(compilation.entries.get(bundleName).dependencies[0]) : compilation.entries[0]; // only process entry exports
if (current.resource !== entry) return;
if (current.resource !== entryModule.resource) return;
var key = current.nameForCondition();

@@ -114,2 +107,23 @@ var exports = CACHE[key] || (CACHE[key] = {});

console.warn('[workerize] unknown export declaration: ', expr);
} // This is for Webpack 5: mark the exports as used so it does not get tree-shaken away on production build
if (compilation.moduleGraph) {
var _require = require('webpack/lib/util/runtime'),
getEntryRuntime = _require.getEntryRuntime;
var _require2 = require('webpack'),
UsageState = _require2.UsageState;
var runtime = getEntryRuntime(compilation, bundleName);
for (var _i = 0, _Object$keys = Object.keys(exports); _i < _Object$keys.length; _i++) {
var exportName = _Object$keys[_i];
var exportInfo = compilation.moduleGraph.getExportInfo(entryModule, exportName);
exportInfo.setUsed(UsageState.Used, runtime);
exportInfo.canMangleUse = false;
exportInfo.canMangleProvide = false;
}
compilation.moduleGraph.addExtraReason(entryModule, 'used by workerize-loader');
}

@@ -123,4 +137,6 @@ });

if (entries[0]) {
worker.file = entries[0].files[0];
var key = entries[0].entryModule.nameForCondition();
worker.file = Array.from(entries[0].files)[0];
var entryModules = compilation.chunkGraph && compilation.chunkGraph.getChunkEntryModulesIterable ? Array.from(compilation.chunkGraph.getChunkEntryModulesIterable(entries[0])) : null;
var entryModule = entryModules && entryModules.length > 0 ? entryModules[0] : entries[0].entryModule;
var key = entryModule.nameForCondition();
var contents = compilation.assets[worker.file].source();

@@ -144,6 +160,8 @@ var exports = Object.keys(CACHE[key] || {}); // console.log('Workerized exports: ', exports.join(', '));

if (options.import) {
workerUrl = "\"data:,importScripts('\"+location.origin+" + workerUrl + "+\"')\"";
}
workerUrl = "\"data:,importScripts('\"+new URL(" + workerUrl + ",location.origin)+\"')\"";
} // workerUrl will be URL.revokeObjectURL() to avoid memory leaks on browsers
// https://github.com/webpack-contrib/worker-loader/issues/208
return cb(null, "\n\t\t\t\tvar addMethods = require(" + loaderUtils.stringifyRequest(_this, path.resolve(__dirname, 'rpc-wrapper.js')) + ")\n\t\t\t\tvar methods = " + JSON.stringify(exports) + "\n\t\t\t\tmodule.exports = function() {\n\t\t\t\t\tvar w = new Worker(" + workerUrl + ", { name: " + JSON.stringify(filename) + " })\n\t\t\t\t\taddMethods(w, methods)\n\t\t\t\t\t" + (options.ready ? 'w.ready = new Promise(function(r) { w.addEventListener("ready", function(){ r(w) }) })' : '') + "\n\t\t\t\t\treturn w\n\t\t\t\t}\n\t\t\t");
return cb(null, "\n\t\t\t\tvar addMethods = require(" + loaderUtils.stringifyRequest(_this, path.resolve(__dirname, 'rpc-wrapper.js')) + ")\n\t\t\t\tvar methods = " + JSON.stringify(exports) + "\n\t\t\t\tmodule.exports = function() {\n\t\t\t\t\tvar w = new Worker(" + workerUrl + ", { name: " + JSON.stringify(filename) + " })\n\t\t\t\t\tURL.revokeObjectURL(" + workerUrl + ");\n\t\t\t\t\taddMethods(w, methods)\n\t\t\t\t\t" + (options.ready ? 'w.ready = new Promise(function(r) { w.addEventListener("ready", function(){ r(w) }) })' : '') + "\n\t\t\t\t\treturn w\n\t\t\t\t}\n\t\t\t");
}

@@ -150,0 +168,0 @@

{
"name": "workerize-loader",
"version": "1.3.0",
"version": "2.0.0",
"description": "Automatically move a module into a Web Worker (Webpack loader)",

@@ -8,2 +8,3 @@ "main": "dist/index.js",

"scripts": {
"postinstall": "patch-package",
"build": "microbundle --format cjs --no-compress --inline none src/*.js",

@@ -41,7 +42,10 @@ "prepublishOnly": "npm run build",

"devDependencies": {
"@types/jest": "^27.5.1",
"eslint": "^7.2.0",
"eslint-config-developit": "^1.2.0",
"karmatic": "^1.4.0",
"karmatic": "^3.0.0",
"microbundle": "^0.12.1",
"webpack": "^4.43.0"
"patch-package": "^6.4.7",
"puppeteer": "^14.1.1",
"webpack": "^5.30.0"
},

@@ -48,0 +52,0 @@ "dependencies": {

@@ -49,2 +49,4 @@ <img src="https://i.imgur.com/HZZG8wr.jpg" width="1358" alt="workerize-loader">

Workerize options can either be defined in your Webpack configuration, or using Webpack's [syntax for inline loader options](https://webpack.js.org/concepts/loaders/#inline).
#### `inline`

@@ -64,3 +66,5 @@

```
or
or
```js

@@ -70,2 +74,83 @@ import worker from 'workerize-loader?inline!./worker'

#### `name`
Type: `String`
Default: `[hash]`
Customize filename generation for worker bundles. Note that a `.worker` suffix will be injected automatically (`{name}.worker.js`).
```js
// webpack.config.js
{
loader: 'workerize-loader',
options: { name: '[name].[contenthash:8]' }
}
```
or
```js
import worker from 'workerize-loader?name=[name].[contenthash:8]!./worker'
```
#### `publicPath`
Type: `String`
Default: based on `output.publicPath`
Workerize uses the configured value of `output.publicPath` from Webpack unless specified here. The value of `publicPath` gets prepended to bundle filenames to get their full URL. It can be a path, or a full URL with host.
```js
// webpack.config.js
{
loader: 'workerize-loader',
options: { publicPath: '/static/' }
}
```
#### `ready`
Type: `Boolean`
Default: `false`
If `true`, the imported "workerized" module will include a `ready` property, which is a Promise that resolves once the Worker has been loaded. Note: this is unnecessary in most cases, since worker methods can be called prior to the worker being loaded.
```js
// webpack.config.js
{
loader: 'workerize-loader',
options: { ready: true }
}
```
or
```js
import worker from 'workerize-loader?ready!./worker'
let instance = worker() // `new` is optional
await instance.ready
```
#### `import`
Type: `Boolean`
Default: `false`
When enabled, generated output will create your Workers using a Data URL that loads your code via `importScripts` (eg: `new Worker('data:,importScripts("url")')`). This workaround enables cross-origin script preloading, but Workers are created on an "opaque origin" and cannot access resources on the origin of their host page without CORS enabled. Only enable it if you understand this and specifically need the workaround.
```js
// webpack.config.js
{
loader: 'workerize-loader',
options: { import: true }
}
```
or
```js
import worker from 'workerize-loader?import!./worker'
```
### About [Babel](https://babeljs.io/)

@@ -91,4 +176,23 @@

### Polyfill Required for IE11
Workerize-loader supports browsers that support Web Workers - that's IE10+.
However, these browsers require a polyfill in order to use Promises, which Workerize-loader relies on.
It is recommended that the polyfill be installed globally, since Webpack itself also needs Promises to load bundles.
The smallest implementation is the one we recommend installing:
`npm i promise-polyfill`
Then, in the module you are "workerizing", just add it as your first import:
```js
import 'promise-polyfill/src/polyfill';
```
All worker code can now use Promises.
### Testing
## Without Webpack
To test a module that is normally imported via `workerize-loader` when not using Webpack, import the module directly in your test:

@@ -103,9 +207,25 @@

To test modules that rely on workerized imports when not using Webpack, you'll need to dig into your test runner a bit. For Jest, it's possible to define a custom `transform` that emulates workerize-loader on the main thread:
## With Webpack and Jest
In Jest, it's possible to define a custom `transform` that emulates workerize-loader on the main thread.
First, install `babel-jest` and `identity-object-proxy`:
```sh
npm i -D babel-jest identity-object-proxy
```
Then, add these properties to the `"transform"` and `"moduleNameMapper"` sections of your Jest config (generally located in your `package.json`):
```js
// in your Jest configuration
{
"transform": {
"workerize-loader(\\?.*)?!(.*)": "<rootDir>/workerize-jest.js"
"jest": {
"moduleNameMapper": {
"workerize-loader(\\?.*)?!(.*)": "identity-obj-proxy"
},
"transform": {
"workerize-loader(\\?.*)?!(.*)": "<rootDir>/workerize-jest.js",
"^.+\\.[jt]sx?$": "babel-jest",
"^.+\\.[jt]s?$": "babel-jest"
}
}

@@ -115,13 +235,21 @@ }

... then add the `workerize-jest.js` shim to your project:
Finally, create the custom Jest transformer referenced above as a file `workerize-jest.js` in your project's root directory (where the package.json is):
```js
module.exports = {
process(src, filename, config, options) {
return 'module.exports = () => require(' + JSON.stringify(filename.replace(/.+!/,'')) + ')';
},
process(src, filename) {
return `
async function asyncify() { return this.apply(null, arguments); }
module.exports = function() {
const w = require(${JSON.stringify(filename.replace(/^.+!/, ''))});
const m = {};
for (let i in w) m[i] = asyncify.bind(w[i]);
return m;
};
`;
}
};
```
Now your tests and any modules they import can use `workerize-loader!` prefixes.
Now your tests and any modules they import can use `workerize-loader!` prefixes, and the imports will be turned into async functions just like they are in Workerize.

@@ -128,0 +256,0 @@ ### Credit

@@ -41,7 +41,6 @@ import path from 'path';

const filename = loaderUtils.interpolateName(this, `${options.name || '[hash]'}.worker.js`, {
context: options.context || this.rootContext || this.options.context,
regExp: options.regExp
});
const compilerOptions = this._compiler.options || {};
const filename = (options.name || '[fullhash]') + '.worker.js';
const worker = {};

@@ -51,7 +50,7 @@

filename,
chunkFilename: `[id].${filename}`,
namedChunkFilename: null
chunkFilename: filename,
publicPath: options.publicPath || compilerOptions.output.publicPath,
globalObject: 'self'
};
const compilerOptions = this._compiler.options || {};
if (compilerOptions.output && compilerOptions.output.globalObject==='window') {

@@ -61,3 +60,3 @@ console.warn('Warning (workerize-loader): output.globalObject is set to "window". It should be set to "self" or "this" to support HMR in Workers.');

worker.compiler = this._compilation.createChildCompiler('worker', worker.options);
worker.compiler = this._compilation.createChildCompiler(`worker ${request}`, worker.options);

@@ -89,24 +88,24 @@ (new WebWorkerTemplatePlugin(worker.options)).apply(worker.compiler);

(new SingleEntryPlugin(this.context, `!!${path.resolve(__dirname, 'rpc-worker-loader.js')}!${request}`, 'main')).apply(worker.compiler);
const bundleName = path.parse(this.resourcePath).name;
const subCache = `subcache ${__dirname} ${request}`;
(new SingleEntryPlugin(this.context, `!!${path.resolve(__dirname, 'rpc-worker-loader.js')}!${request}`, bundleName)).apply(worker.compiler);
compilationHook(worker.compiler, (compilation, data) => {
if (compilation.cache) {
if (!compilation.cache[subCache]) compilation.cache[subCache] = {};
compilation.cache = compilation.cache[subCache];
}
parseHook(data, (parser, options) => {
exportDeclarationHook(parser, expr => {
let decl = expr.declaration || expr,
{ compilation, current } = parser.state,
entry = compilation.entries[0].resource;
let decl = expr.declaration || expr;
let { compilation, current } = parser.state;
let entryModule =
compilation.entries instanceof Map
? compilation.moduleGraph.getModule(
compilation.entries.get(bundleName).dependencies[0]
)
: compilation.entries[0];
// only process entry exports
if (current.resource!==entry) return;
if (current.resource!==entryModule.resource) return;
let key = current.nameForCondition();
let exports = CACHE[key] || (CACHE[key] = {});
if (decl.id) {

@@ -123,2 +122,16 @@ exports[decl.id.name] = true;

}
// This is for Webpack 5: mark the exports as used so it does not get tree-shaken away on production build
if (compilation.moduleGraph) {
const { getEntryRuntime } = require('webpack/lib/util/runtime');
const { UsageState } = require('webpack');
const runtime = getEntryRuntime(compilation, bundleName);
for (const exportName of Object.keys(exports)) {
const exportInfo = compilation.moduleGraph.getExportInfo(entryModule, exportName);
exportInfo.setUsed(UsageState.Used, runtime);
exportInfo.canMangleUse = false;
exportInfo.canMangleProvide = false;
}
compilation.moduleGraph.addExtraReason(entryModule, 'used by workerize-loader');
}
});

@@ -132,5 +145,16 @@ });

if (entries[0]) {
worker.file = entries[0].files[0];
worker.file = Array.from(entries[0].files)[0];
const entryModules =
compilation.chunkGraph &&
compilation.chunkGraph.getChunkEntryModulesIterable
? Array.from(
compilation.chunkGraph.getChunkEntryModulesIterable(entries[0])
)
: null;
const entryModule =
entryModules && entryModules.length > 0
? entryModules[0]
: entries[0].entryModule;
let key = entries[0].entryModule.nameForCondition();
let key = entryModule.nameForCondition();
let contents = compilation.assets[worker.file].source();

@@ -157,5 +181,8 @@ let exports = Object.keys(CACHE[key] || {});

if (options.import) {
workerUrl = `"data:,importScripts('"+location.origin+${workerUrl}+"')"`;
workerUrl = `"data:,importScripts('"+new URL(${workerUrl},location.origin)+"')"`;
}
// workerUrl will be URL.revokeObjectURL() to avoid memory leaks on browsers
// https://github.com/webpack-contrib/worker-loader/issues/208
return cb(null, `

@@ -166,2 +193,3 @@ var addMethods = require(${loaderUtils.stringifyRequest(this, path.resolve(__dirname, 'rpc-wrapper.js'))})

var w = new Worker(${workerUrl}, { name: ${JSON.stringify(filename)} })
URL.revokeObjectURL(${workerUrl});
addMethods(w, methods)

@@ -168,0 +196,0 @@ ${ options.ready ? 'w.ready = new Promise(function(r) { w.addEventListener("ready", function(){ r(w) }) })' : '' }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc