diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..d579f75
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+ - "8"
+ - "10"
+git:
+ depth: 5
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
deleted file mode 100644
index 44f15d9..0000000
--- a/LICENSE.md
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018 Jason Miller
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
index b61a097..a1a1cae 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
- If exported module methods are already async, signature is unchanged
- Supports synchronous and asynchronous worker functions
- Works beautifully with async/await
-- Just **900 bytes** of gzipped ES3
+- Just **800 bytes** of gzipped ES3
## Install
@@ -33,7 +33,7 @@ let worker = workerize(`
export function add(a, b) {
// block for half a second to demonstrate asynchronicity
let start = Date.now();
- while (Date.now()-start < 250);
+ while (Date.now()-start < 500);
return a + b;
}
`);
@@ -46,4 +46,4 @@ let worker = workerize(`
### License
-[MIT License](LICENSE.md) © [Jason Miller](https://jasonformat.com)
+[MIT License](https://oss.ninja/mit/developit/) © [Jason Miller](https://jasonformat.com)
diff --git a/demo.html b/demo.html
new file mode 100644
index 0000000..7ded2d0
--- /dev/null
+++ b/demo.html
@@ -0,0 +1,24 @@
+
+
+
+ Workerize Demo
+
+
+
+
+
diff --git a/loader.js b/loader.js
new file mode 100644
index 0000000..cf3256a
--- /dev/null
+++ b/loader.js
@@ -0,0 +1,9 @@
+try {
+ module.exports = require('workerize-loader');
+}
+catch (e) {
+ console.warn("Warning: workerize-loader is not installed.");
+ module.exports = function() {
+ throw "To use workerize as a loader, you must install workerize-loader.";
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 3c7e226..d5e8577 100644
--- a/package.json
+++ b/package.json
@@ -1,25 +1,40 @@
{
"name": "workerize",
- "version": "0.1.2",
+ "version": "0.1.8",
"description": "Run a module in a Web Worker.",
"main": "dist/workerize.js",
- "module": "src/index.js",
+ "module": "dist/workerize.m.js",
+ "source": "src/index.js",
"repository": "developit/workerize",
+ "loader": "./loader.js",
"scripts": {
"build": "microbundle",
"prepublishOnly": "npm run build",
"release": "npm t && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish",
"test": "echo \"Error: no test specified\" && exit 0"
},
+ "eslintConfig": {
+ "extends": "eslint-config-developit",
+ "rules": {
+ "prefer-spread": 0,
+ "prefer-rest-params": 0
+ }
+ },
+ "files": [
+ "src",
+ "dist",
+ "loader.js"
+ ],
"keywords": [
"worker",
"web workers",
"threads"
],
"author": "Jason Miller (http://jasonformat.com)",
- "license": "ISC",
+ "license": "MIT",
"devDependencies": {
- "eslint": "^4.15.0",
- "microbundle": "^0.2.4"
+ "eslint": "^4.16.0",
+ "eslint-config-developit": "^1.1.1",
+ "microbundle": "^0.4.3"
}
}
diff --git a/src/index.js b/src/index.js
index 386495e..75a5b44 100644
--- a/src/index.js
+++ b/src/index.js
@@ -17,98 +17,75 @@
* console.log('1 + 2 = ', await worker.add(1, 2));
* })();
*/
-
-
-export default function workerize(code) {
+export default function workerize(code, options) {
let exports = {};
- let exportsObjName = `__EXPORTS_${Math.random().toString().substring(2)}__`;
- if (typeof code==='function') code = `(${toCode(code)})(${exportsObjName})`;
- code = toCjs(code, exportsObjName, exports);
- code += `\n(${toCode(setup)})(self, ${exportsObjName}, {})`;
- let blob = new Blob([code], {
- type: 'application/javascript'
- }),
- url = URL.createObjectURL(blob),
- worker = new Worker(url),
+ let exportsObjName = `__xpo${Math.random().toString().substring(2)}__`;
+ if (typeof code==='function') code = `(${Function.prototype.toString.call(code)})(${exportsObjName})`;
+ code = toCjs(code, exportsObjName, exports) + `\n(${Function.prototype.toString.call(setup)})(self,${exportsObjName},{})`;
+ let url = URL.createObjectURL(new Blob([code],{ type: 'text/javascript' })),
+ worker = new Worker(url, options),
+ term = worker.terminate,
+ callbacks = {},
counter = 0,
- callbacks = {};
+ i;
worker.kill = signal => {
worker.postMessage({ type: 'KILL', signal });
setTimeout(worker.terminate);
};
- let term = worker.terminate;
worker.terminate = () => {
URL.revokeObjectURL(url);
- term();
+ term.call(worker);
};
- worker.rpcMethods = {};
- function setup(ctx, rpcMethods, callbacks) {
- /*
- ctx.expose = (methods, replace) => {
- if (typeof methods==='string') {
- rpcMethods[methods] = replace;
- }
- else {
- if (replace===true) rpcMethods = {};
- Object.assign(rpcMethods, methods);
- }
- };
- */
- ctx.addEventListener('message', ({ data }) => {
- if (data.type==='RPC') {
- let id = data.id;
- if (id!=null) {
- if (data.method) {
- let method = rpcMethods[data.method];
- if (method==null) {
- ctx.postMessage({ type: 'RPC', id, error: 'NO_SUCH_METHOD' });
- }
- else {
- Promise.resolve()
- .then( () => method.apply(null, data.params) )
- .then( result => { ctx.postMessage({ type: 'RPC', id, result }); })
- .catch( error => { ctx.postMessage({ type: 'RPC', id, error }); });
- }
- }
- else {
- let callback = callbacks[id];
- if (callback==null) throw Error(`Unknown callback ${id}`);
- delete callbacks[id];
- if (data.error) callback.reject(Error(data.error));
- else callback.resolve(data.result);
- }
- }
- }
- });
- }
- setup(worker, worker.rpcMethods, callbacks);
worker.call = (method, params) => new Promise( (resolve, reject) => {
let id = `rpc${++counter}`;
- callbacks[id] = { method, resolve, reject };
+ callbacks[id] = [resolve, reject];
worker.postMessage({ type: 'RPC', id, method, params });
});
- for (let i in exports) {
- if (exports.hasOwnProperty(i) && !(i in worker)) {
- worker[i] = (...args) => worker.call(i, args);
- }
- }
+ worker.rpcMethods = {};
+ setup(worker, worker.rpcMethods, callbacks);
+ worker.expose = methodName => {
+ worker[methodName] = function() {
+ return worker.call(methodName, [].slice.call(arguments));
+ };
+ };
+ for (i in exports) if (!(i in worker)) worker.expose(i);
return worker;
}
-function toCode(func) {
- return Function.prototype.toString.call(func);
+function setup(ctx, rpcMethods, callbacks) {
+ ctx.addEventListener('message', ({ data }) => {
+ let id = data.id;
+ if (data.type!=='RPC' || id==null) return;
+ if (data.method) {
+ let method = rpcMethods[data.method];
+ if (method==null) {
+ ctx.postMessage({ type: 'RPC', id, error: 'NO_SUCH_METHOD' });
+ }
+ else {
+ Promise.resolve()
+ .then( () => method.apply(null, data.params) )
+ .then( result => { ctx.postMessage({ type: 'RPC', id, result }); })
+ .catch( err => { ctx.postMessage({ type: 'RPC', id, error: ''+err }); });
+ }
+ }
+ else {
+ let callback = callbacks[id];
+ if (callback==null) throw Error(`Unknown callback ${id}`);
+ delete callbacks[id];
+ if (data.error) callback[1](Error(data.error));
+ else callback[0](data.result);
+ }
+ });
}
function toCjs(code, exportsObjName, exports) {
- exportsObjName = exportsObjName || 'exports';
- exports = exports || {};
code = code.replace(/^(\s*)export\s+default\s+/m, (s, before) => {
exports.default = true;
- return `${before}${exportsObjName}.default = `;
+ return `${before}${exportsObjName}.default=`;
});
- code = code.replace(/^(\s*)export\s+(function|const|let|var)(\s+)([a-zA-Z$_][a-zA-Z0-9$_]*)/m, (s, before, type, ws, name) => {
+ code = code.replace(/^(\s*)export\s+((?:async\s*)?function(?:\s*\*)?|const|let|var)(\s+)([a-zA-Z$_][a-zA-Z0-9$_]*)/mg, (s, before, type, ws, name) => {
exports[name] = true;
- return `${before}${exportsObjName}.${name} = ${type}${ws}${name}`;
+ return `${before}${exportsObjName}.${name}=${type}${ws}${name}`;
});
- return `var ${exportsObjName} = {};\n${code}\n${exportsObjName};`;
+ return `var ${exportsObjName}={};\n${code}\n${exportsObjName};`;
}