workerize-loader
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -10,4 +10,4 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } | ||
function loader() {} | ||
var CACHE = {}; | ||
var tapName = 'workerize-loader'; | ||
const CACHE = {}; | ||
const tapName = 'workerize-loader'; | ||
@@ -39,18 +39,16 @@ function compilationHook(compiler, handler) { | ||
loader.pitch = function (request) { | ||
var this$1 = this; | ||
this.cacheable(false); | ||
var options = loaderUtils.getOptions(this) || {}; | ||
var cb = this.async(); | ||
var filename = loaderUtils.interpolateName(this, ((options.name || '[hash]') + ".worker.js"), { | ||
const options = loaderUtils.getOptions(this) || {}; | ||
const cb = this.async(); | ||
const filename = loaderUtils.interpolateName(this, `${options.name || '[hash]'}.worker.js`, { | ||
context: options.context || this.rootContext || this.options.context, | ||
regExp: options.regExp | ||
}); | ||
var worker = {}; | ||
const worker = {}; | ||
worker.options = { | ||
filename: filename, | ||
chunkFilename: ("[id]." + filename), | ||
filename, | ||
chunkFilename: `[id].${filename}`, | ||
namedChunkFilename: null | ||
}; | ||
var compilerOptions = this._compiler.options || {}; | ||
const compilerOptions = this._compiler.options || {}; | ||
@@ -68,25 +66,39 @@ if (compilerOptions.output && compilerOptions.output.globalObject === 'window') { | ||
new SingleEntryPlugin(this.context, ("!!" + (path.resolve(__dirname, 'rpc-worker-loader.js')) + "!" + request), 'main').apply(worker.compiler); | ||
var subCache = "subcache " + __dirname + " " + request; | ||
compilationHook(worker.compiler, function (compilation, data) { | ||
let wasmPluginPath = null; | ||
try { | ||
wasmPluginPath = require.resolve('webpack/lib/web/FetchCompileWasmTemplatePlugin'); | ||
} catch (_err) {} | ||
if (wasmPluginPath) { | ||
const FetchCompileWasmTemplatePlugin = require(wasmPluginPath); | ||
new FetchCompileWasmTemplatePlugin({ | ||
mangleImports: this._compiler.options.optimization.mangleWasmImports | ||
}).apply(worker.compiler); | ||
} | ||
new SingleEntryPlugin(this.context, `!!${path.resolve(__dirname, 'rpc-worker-loader.js')}!${request}`, 'main').apply(worker.compiler); | ||
const subCache = `subcache ${__dirname} ${request}`; | ||
compilationHook(worker.compiler, (compilation, data) => { | ||
if (compilation.cache) { | ||
if (!compilation.cache[subCache]) { compilation.cache[subCache] = {}; } | ||
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; | ||
var ref = parser.state; | ||
var compilation = ref.compilation; | ||
var current = ref.current; | ||
var entry = compilation.entries[0].resource; // only process entry exports | ||
parseHook(data, (parser, options) => { | ||
exportDeclarationHook(parser, expr => { | ||
let decl = expr.declaration || expr, | ||
{ | ||
compilation, | ||
current | ||
} = parser.state, | ||
entry = compilation.entries[0].resource; | ||
if (current.resource !== entry) return; | ||
let exports = CACHE[entry] || (CACHE[entry] = {}); | ||
if (current.resource !== entry) { return; } | ||
var exports = compilation.__workerizeExports || (compilation.__workerizeExports = {}); | ||
if (decl.id) { | ||
exports[decl.id.name] = true; | ||
} else if (decl.declarations) { | ||
for (var i = 0; i < decl.declarations.length; i++) { | ||
for (let i = 0; i < decl.declarations.length; i++) { | ||
exports[decl.declarations[i].id.name] = true; | ||
@@ -100,27 +112,37 @@ } | ||
}); | ||
worker.compiler.runAsChild(function (err, entries, compilation) { | ||
if (err) { return cb(err); } | ||
worker.compiler.runAsChild((err, entries, compilation) => { | ||
if (err) return cb(err); | ||
if (entries[0]) { | ||
worker.file = entries[0].files[0]; | ||
var contents = compilation.assets[worker.file].source(); | ||
var exports = Object.keys(CACHE[worker.file] = compilation.__workerizeExports || CACHE[worker.file] || {}); // console.log('Workerized exports: ', exports.join(', ')); | ||
let entry = entries[0].entryModule.resource; | ||
let contents = compilation.assets[worker.file].source(); | ||
let exports = Object.keys(CACHE[entry] || {}); | ||
if (options.inline) { | ||
worker.url = "URL.createObjectURL(new Blob([" + (JSON.stringify(contents)) + "]))"; | ||
worker.url = `URL.createObjectURL(new Blob([${JSON.stringify(contents)}]))`; | ||
} else { | ||
worker.url = "__webpack_public_path__ + " + (JSON.stringify(worker.file)); | ||
worker.url = `__webpack_public_path__ + ${JSON.stringify(worker.file)}`; | ||
} | ||
if (options.fallback === false) { | ||
delete this$1._compilation.assets[worker.file]; | ||
delete this._compilation.assets[worker.file]; | ||
} | ||
var workerUrl = worker.url; | ||
let workerUrl = worker.url; | ||
if (options.import) { | ||
workerUrl = "\"data:,importScripts('\"+location.origin+" + workerUrl + "+\"')\""; | ||
workerUrl = `"data:,importScripts('"+location.origin+${workerUrl}+"')"`; | ||
} | ||
return cb(null, ("\n\t\t\t\tvar addMethods = require(" + (loaderUtils.stringifyRequest(this$1, 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, ` | ||
var addMethods = require(${loaderUtils.stringifyRequest(this, path.resolve(__dirname, 'rpc-wrapper.js'))}) | ||
var methods = ${JSON.stringify(exports)} | ||
module.exports = function() { | ||
var w = new Worker(${workerUrl}, { name: ${JSON.stringify(filename)} }) | ||
addMethods(w, methods) | ||
${options.ready ? 'w.ready = new Promise(function(r) { w.addEventListener("ready", function(){ r(w) }) })' : ''} | ||
return w | ||
} | ||
`); | ||
} | ||
@@ -127,0 +149,0 @@ |
@@ -1,10 +0,10 @@ | ||
/* global __webpack_exports__ */ | ||
function workerSetup() { | ||
addEventListener('message', function (e) { | ||
var ref = e.data; | ||
var type = ref.type; | ||
var method = ref.method; | ||
var id = ref.id; | ||
var params = ref.params; | ||
var f, | ||
addEventListener('message', e => { | ||
let { | ||
type, | ||
method, | ||
id, | ||
params | ||
} = e.data, | ||
f, | ||
p; | ||
@@ -14,3 +14,3 @@ | ||
if (f = __webpack_exports__[method]) { | ||
p = Promise.resolve().then(function () { return f.apply(__webpack_exports__, params); }); | ||
p = Promise.resolve().then(() => f.apply(__webpack_exports__, params)); | ||
} else { | ||
@@ -20,10 +20,10 @@ p = Promise.reject('No such method'); | ||
p.then(function (result) { | ||
p.then(result => { | ||
postMessage({ | ||
type: 'RPC', | ||
id: id, | ||
result: result | ||
id, | ||
result | ||
}); | ||
}).catch(function (e) { | ||
var error = { | ||
}).catch(e => { | ||
let error = { | ||
message: e | ||
@@ -40,4 +40,4 @@ }; | ||
type: 'RPC', | ||
id: id, | ||
error: error | ||
id, | ||
error | ||
}); | ||
@@ -53,3 +53,3 @@ }); | ||
var workerScript = '\n' + Function.prototype.toString.call(workerSetup).replace(/(^.*\{|\}.*$|\n\s*)/g, ''); | ||
const workerScript = '\n' + Function.prototype.toString.call(workerSetup).replace(/(^.*\{|\}.*$|\n\s*)/g, ''); | ||
function rpcWorkerLoader(content) { | ||
@@ -56,0 +56,0 @@ return content + workerScript; |
function addMethods(worker, methods) { | ||
var c = 0; | ||
var callbacks = {}; | ||
worker.addEventListener('message', function (e) { | ||
var d = e.data; | ||
if (d.type !== 'RPC') { return; } | ||
let c = 0; | ||
let callbacks = {}; | ||
worker.addEventListener('message', e => { | ||
let d = e.data; | ||
if (d.type !== 'RPC') return; | ||
if (d.id) { | ||
var f = callbacks[d.id]; | ||
let f = callbacks[d.id]; | ||
@@ -21,3 +21,3 @@ if (f) { | ||
} else { | ||
var evt = document.createEvent('Event'); | ||
let evt = document.createEvent('Event'); | ||
evt.initEvent(d.method, false, false); | ||
@@ -28,18 +28,13 @@ evt.data = d.params; | ||
}); | ||
methods.forEach(function (method) { | ||
worker[method] = function () { | ||
var params = [], len = arguments.length; | ||
while ( len-- ) params[ len ] = arguments[ len ]; | ||
return new Promise(function (a, b) { | ||
var id = ++c; | ||
methods.forEach(method => { | ||
worker[method] = (...params) => new Promise((a, b) => { | ||
let id = ++c; | ||
callbacks[id] = [a, b]; | ||
worker.postMessage({ | ||
type: 'RPC', | ||
id: id, | ||
method: method, | ||
params: params | ||
id, | ||
method, | ||
params | ||
}); | ||
}); | ||
}; | ||
}); | ||
@@ -46,0 +41,0 @@ } |
{ | ||
"name": "workerize-loader", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Automatically move a module into a Web Worker (Webpack loader)", | ||
@@ -36,6 +36,6 @@ "main": "dist/index.js", | ||
"devDependencies": { | ||
"eslint": "^5.16.0", | ||
"eslint": "^6.8.0", | ||
"eslint-config-developit": "^1.1.1", | ||
"karmatic": "^1.3.1", | ||
"microbundle": "^0.11.0", | ||
"karmatic": "^1.4.0", | ||
"microbundle": "0.12.0-next.8", | ||
"webpack": "^4.39.2" | ||
@@ -42,0 +42,0 @@ }, |
@@ -88,2 +88,36 @@ <img src="https://i.imgur.com/HZZG8wr.jpg" width="1358" alt="workerize-loader"> | ||
### Testing | ||
To test a module that is normally imported via `workerize-loader` when not using Webpack, import the module directly in your test: | ||
```diff | ||
-const worker = require('workerize-loader!./worker.js'); | ||
+const worker = () => require('./worker.js'); | ||
const instance = worker(); | ||
``` | ||
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: | ||
```js | ||
// in your Jest configuration | ||
{ | ||
"transform": { | ||
"workerize-loader(\\?.*)?!(.*)": "<rootDir>/workerize-jest.js" | ||
} | ||
} | ||
``` | ||
... then add the `workerize-jest.js` shim to your project: | ||
```js | ||
module.exports = { | ||
process(src, filename, config, options) { | ||
return 'module.exports = () => require(' + JSON.stringify(filename.replace(/.+!/,'')) + ')'; | ||
}, | ||
}; | ||
``` | ||
Now your tests and any modules they import can use `workerize-loader!` prefixes. | ||
### Credit | ||
@@ -90,0 +124,0 @@ |
@@ -67,2 +67,21 @@ import path from 'path'; | ||
// webpack >= v4 supports webassembly | ||
let wasmPluginPath = null; | ||
try { | ||
wasmPluginPath = require.resolve( | ||
'webpack/lib/web/FetchCompileWasmTemplatePlugin' | ||
); | ||
} | ||
catch (_err) { | ||
// webpack <= v3, skipping | ||
} | ||
if (wasmPluginPath) { | ||
// eslint-disable-next-line global-require | ||
const FetchCompileWasmTemplatePlugin = require(wasmPluginPath); | ||
new FetchCompileWasmTemplatePlugin({ | ||
mangleImports: this._compiler.options.optimization.mangleWasmImports | ||
}).apply(worker.compiler); | ||
} | ||
(new SingleEntryPlugin(this.context, `!!${path.resolve(__dirname, 'rpc-worker-loader.js')}!${request}`, 'main')).apply(worker.compiler); | ||
@@ -87,3 +106,3 @@ | ||
let exports = compilation.__workerizeExports || (compilation.__workerizeExports = {}); | ||
let exports = CACHE[entry] || (CACHE[entry] = {}); | ||
@@ -111,4 +130,5 @@ if (decl.id) { | ||
let entry = entries[0].entryModule.resource; | ||
let contents = compilation.assets[worker.file].source(); | ||
let exports = Object.keys(CACHE[worker.file] = compilation.__workerizeExports || CACHE[worker.file] || {}); | ||
let exports = Object.keys(CACHE[entry] || {}); | ||
@@ -115,0 +135,0 @@ // console.log('Workerized exports: ', exports.join(', ')); |
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
35334
406
130
2