From 79f0e7b212df0560aef3749216ecc35895455317 Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Thu, 21 May 2020 05:45:31 +0200 Subject: [PATCH 1/5] Implement BlobWorker --- src/master/implementation.browser.ts | 27 ++++++++-- src/master/implementation.node.ts | 79 ++++++++++++++++++++++------ src/master/index.ts | 8 ++- src/types/master.ts | 12 +++++ 4 files changed, 103 insertions(+), 23 deletions(-) diff --git a/src/master/implementation.browser.ts b/src/master/implementation.browser.ts index e1763eea..b2d898ee 100644 --- a/src/master/implementation.browser.ts +++ b/src/master/implementation.browser.ts @@ -1,6 +1,6 @@ // tslint:disable max-classes-per-file -import { ThreadsWorkerOptions, WorkerImplementation } from "../types/master" +import { ImplementationExport, ThreadsWorkerOptions } from "../types/master" import { getBundleURL } from "./get-bundle-url.browser" export const defaultPoolSize = typeof navigator !== "undefined" && navigator.hardwareConcurrency @@ -17,7 +17,7 @@ function createSourceBlobURL(code: string): string { return URL.createObjectURL(blob) } -function selectWorkerImplementation(): typeof WorkerImplementation { +function selectWorkerImplementation(): ImplementationExport { if (typeof Worker === "undefined") { // Might happen on Safari, for instance // The idea is to only fail if the constructor is actually used @@ -28,7 +28,7 @@ function selectWorkerImplementation(): typeof WorkerImplementation { } as any } - return class WebWorker extends Worker { + class WebWorker extends Worker { constructor(url: string | URL, options?: ThreadsWorkerOptions) { if (typeof url === "string" && options && options._baseURL) { url = new URL(url, options._baseURL) @@ -44,11 +44,28 @@ function selectWorkerImplementation(): typeof WorkerImplementation { super(url, options) } } + + class BlobWorker extends WebWorker { + constructor(blob: Blob, options?: ThreadsWorkerOptions) { + const url = window.URL.createObjectURL(blob) + super(url, options) + } + + public static fromText(source: string, options?: ThreadsWorkerOptions): WebWorker { + const blob = new window.Blob([source], { type: "text/javascript" }) + return new BlobWorker(blob, options) + } + } + + return { + blob: BlobWorker, + default: WebWorker + } } -let implementation: typeof WorkerImplementation +let implementation: ImplementationExport -export function getWorkerImplementation(): typeof WorkerImplementation { +export function getWorkerImplementation(): ImplementationExport { if (!implementation) { implementation = selectWorkerImplementation() } diff --git a/src/master/implementation.node.ts b/src/master/implementation.node.ts index 40965682..a8f5f517 100644 --- a/src/master/implementation.node.ts +++ b/src/master/implementation.node.ts @@ -5,7 +5,11 @@ import getCallsites, { CallSite } from "callsites" import EventEmitter from "events" import { cpus } from 'os' import * as path from "path" -import { ThreadsWorkerOptions, WorkerImplementation } from "../types/master" +import { + ImplementationExport, + ThreadsWorkerOptions, + WorkerImplementation +} from "../types/master" interface WorkerGlobalScope { addEventListener(eventName: string, listener: (event: Event) => void): void @@ -84,7 +88,7 @@ function resolveScriptPath(scriptPath: string, baseURL?: string | undefined) { return workerFilePath } -function initWorkerThreadsWorker(): typeof WorkerImplementation { +function initWorkerThreadsWorker(): ImplementationExport { // Webpack hack const NativeWorker = typeof __non_webpack_require__ === "function" ? __non_webpack_require__("worker_threads").Worker @@ -95,10 +99,16 @@ function initWorkerThreadsWorker(): typeof WorkerImplementation { class Worker extends NativeWorker { private mappedEventListeners: WeakMap - constructor(scriptPath: string, options?: ThreadsWorkerOptions) { - const resolvedScriptPath = resolveScriptPath(scriptPath, (options || {})._baseURL) + constructor(scriptPath: string, options?: ThreadsWorkerOptions & { fromSource: boolean }) { + const resolvedScriptPath = options && options.fromSource + ? null + : resolveScriptPath(scriptPath, (options || {})._baseURL) - if (resolvedScriptPath.match(/\.tsx?$/i) && detectTsNode()) { + if (!resolvedScriptPath) { + // `options.fromSource` is true + const sourceCode = scriptPath + super(sourceCode, { ...options, eval: true }) + } else if (resolvedScriptPath.match(/\.tsx?$/i) && detectTsNode()) { super(createTsNodeModule(resolvedScriptPath), { ...options, eval: true }) } else if (resolvedScriptPath.match(/\.asar[\/\\]/)) { // See @@ -138,10 +148,23 @@ function initWorkerThreadsWorker(): typeof WorkerImplementation { process.on("SIGINT", () => terminateWorkersAndMaster()) process.on("SIGTERM", () => terminateWorkersAndMaster()) - return Worker as any + class BlobWorker extends Worker { + constructor(blob: Uint8Array, options?: ThreadsWorkerOptions) { + super(Buffer.from(blob).toString("utf-8"), { ...options, fromSource: true }) + } + + public static fromText(source: string, options?: ThreadsWorkerOptions): WorkerImplementation { + return new Worker(source, { ...options, fromSource: true }) as any + } + } + + return { + blob: BlobWorker as any, + default: Worker as any + } } -function initTinyWorker(): typeof WorkerImplementation { +function initTinyWorker(): ImplementationExport { const TinyWorker = require("tiny-worker") let allWorkers: Array = [] @@ -149,14 +172,20 @@ function initTinyWorker(): typeof WorkerImplementation { class Worker extends TinyWorker { private emitter: EventEmitter - constructor(scriptPath: string) { + constructor(scriptPath: string, options?: ThreadsWorkerOptions & { fromSource?: boolean }) { // Need to apply a work-around for Windows or it will choke upon the absolute path // (`Error [ERR_INVALID_PROTOCOL]: Protocol 'c:' not supported`) - const resolvedScriptPath = process.platform === "win32" - ? `file:///${resolveScriptPath(scriptPath).replace(/\\/g, "/")}` - : resolveScriptPath(scriptPath) - - if (resolvedScriptPath.match(/\.tsx?$/i) && detectTsNode()) { + const resolvedScriptPath = options && options.fromSource + ? null + : process.platform === "win32" + ? `file:///${resolveScriptPath(scriptPath).replace(/\\/g, "/")}` + : resolveScriptPath(scriptPath) + + if (!resolvedScriptPath) { + // `options.fromSource` is true + const sourceCode = scriptPath + super(new Function(sourceCode), [], { esm: true }) + } else if (resolvedScriptPath.match(/\.tsx?$/i) && detectTsNode()) { super(new Function(createTsNodeModule(resolveScriptPath(scriptPath))), [], { esm: true }) } else if (resolvedScriptPath.match(/\.asar[\/\\]/)) { // See @@ -171,12 +200,15 @@ function initTinyWorker(): typeof WorkerImplementation { this.onerror = (error: Error) => this.emitter.emit("error", error) this.onmessage = (message: MessageEvent) => this.emitter.emit("message", message) } + public addEventListener(eventName: WorkerEventName, listener: EventListener) { this.emitter.addListener(eventName, listener) } + public removeEventListener(eventName: WorkerEventName, listener: EventListener) { this.emitter.removeListener(eventName, listener) } + public terminate() { allWorkers = allWorkers.filter(worker => worker !== this) return super.terminate() @@ -197,13 +229,26 @@ function initTinyWorker(): typeof WorkerImplementation { process.on("SIGINT", () => terminateWorkersAndMaster()) process.on("SIGTERM", () => terminateWorkersAndMaster()) - return Worker as any + class BlobWorker extends Worker { + constructor(blob: Uint8Array, options?: ThreadsWorkerOptions) { + super(Buffer.from(blob).toString("utf-8"), { ...options, fromSource: true }) + } + + public static fromText(source: string, options?: ThreadsWorkerOptions): WorkerImplementation { + return new Worker(source, { ...options, fromSource: true }) as any + } + } + + return { + blob: BlobWorker as any, + default: Worker as any + } } -let implementation: typeof WorkerImplementation +let implementation: ImplementationExport let isTinyWorker: boolean -function selectWorkerImplementation(): typeof WorkerImplementation { +function selectWorkerImplementation(): ImplementationExport { try { isTinyWorker = false return initWorkerThreadsWorker() @@ -215,7 +260,7 @@ function selectWorkerImplementation(): typeof WorkerImplementation { } } -export function getWorkerImplementation(): typeof WorkerImplementation { +export function getWorkerImplementation(): ImplementationExport { if (!implementation) { implementation = selectWorkerImplementation() } diff --git a/src/master/index.ts b/src/master/index.ts index 68dffcfa..ed1b2da1 100644 --- a/src/master/index.ts +++ b/src/master/index.ts @@ -1,3 +1,5 @@ +// tslint:disable no-duplicate-imports +import type { BlobWorker as BlobWorkerClass } from "../types/master" import { Worker as WorkerType } from "../types/master" import { getWorkerImplementation, isWorkerRuntime } from "./implementation" @@ -7,7 +9,11 @@ export { spawn } from "./spawn" export { Thread } from "./thread" export { isWorkerRuntime } +export type BlobWorker = typeof BlobWorkerClass export type Worker = WorkerType +/** Separate class to spawn workers from source code blobs or strings. */ +export const BlobWorker = getWorkerImplementation().blob + /** Worker implementation. Either web worker or a node.js Worker class. */ -export const Worker = getWorkerImplementation() +export const Worker = getWorkerImplementation().default diff --git a/src/types/master.ts b/src/types/master.ts index 3747459a..d7b6a8d3 100644 --- a/src/types/master.ts +++ b/src/types/master.ts @@ -1,4 +1,5 @@ /// +// tslint:disable max-classes-per-file // Cannot use `compilerOptions.esModuleInterop` and default import syntax // See @@ -89,6 +90,17 @@ export declare class WorkerImplementation extends EventTarget implements Worker public terminate(): void } +/** Class to spawn workers from a blob or source string. */ +export declare class BlobWorker extends WorkerImplementation { + constructor(blob: Blob, options?: ThreadsWorkerOptions) + public static fromText(source: string, options?: ThreadsWorkerOptions): WorkerImplementation +} + +export interface ImplementationExport { + blob: typeof BlobWorker + default: typeof WorkerImplementation +} + /** Event as emitted by worker thread. Subscribe to using `Thread.events(thread)`. */ export enum WorkerEventType { internalError = "internalError", From df872d6ca7839f18b5a6e49f61716c10b23c358a Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Thu, 21 May 2020 05:46:16 +0200 Subject: [PATCH 2/5] Test BlobWorker in browser --- .gitignore | 1 + package-lock.json | 12 ++++++------ package.json | 6 ++++-- rollup.config.js | 14 ++++++++++++++ src/worker/bundle-entry.ts | 9 +++++++++ test/spawn.chromium.mocha.ts | 27 +++++++++++++++++++++++++-- test/transferables.test.ts | 4 ++-- 7 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 rollup.config.js create mode 100644 src/worker/bundle-entry.ts diff --git a/.gitignore b/.gitignore index e4f4f004..32a128a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .cache/ .vscode/ +bundle/ docs/_site docs/vendor dist/* diff --git a/package-lock.json b/package-lock.json index ddcd6871..6fd1209a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -859,9 +859,9 @@ } }, "@babel/parser": { - "version": "7.7.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.7.tgz", - "integrity": "sha512-WtTZMZAZLbeymhkd/sEaPD8IQyGAhmuTuvTzLiCFM7iXiVdY0gc0IaI+cW0fh1BnSMbJSzXX6/fHllgHKwHhXw==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", + "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", "dev": true }, "@babel/plugin-proposal-async-generator-functions": { @@ -11052,9 +11052,9 @@ } }, "typescript": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz", - "integrity": "sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==", + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", + "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", "dev": true }, "uid2": { diff --git a/package.json b/package.json index eee09967..f7837770 100644 --- a/package.json +++ b/package.json @@ -15,9 +15,11 @@ "build": "run-p build:cjs build:es", "build:cjs": "tsc -p tsconfig.json", "build:es": "tsc -p tsconfig-esm.json", + "postbuild": "run-s bundle", + "bundle": "rollup -c -f umd --file=bundle/worker.js --name=threads --silent -- dist-esm/worker/bundle-entry.js", "test": "run-s test:ava test:puppeteer:basic test:puppeteer:webpack", "test:ava": "cross-env TS_NODE_FILES=true ava", - "test:puppeteer:basic": "puppet-run --plugin=mocha --bundle=./test/workers/:/workers/ ./test/*.chromium*.ts", + "test:puppeteer:basic": "puppet-run --plugin=mocha --bundle=./test/workers/:/workers/ --serve=./bundle/worker.js:/worker.js ./test/*.chromium*.ts", "test:puppeteer:webpack": "puppet-run --serve ./test/webpack/dist.web/0.worker.js --serve ./test/webpack/dist.web/1.worker.js --plugin=mocha ./test/webpack/webpack.chromium.mocha.ts", "posttest": "tslint --project .", "prepare": "run-s build" @@ -79,7 +81,7 @@ "ts-node": "^8.1.0", "tslint": "^5.16.0", "tslint-config-prettier": "^1.18.0", - "typescript": "^3.4.5", + "typescript": "^3.9.3", "wavy": "^1.0.4", "webpack": "^4.32.2", "worker-plugin": "^3.1.0" diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..8954fbcb --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,14 @@ +const commonjs = require("rollup-plugin-commonjs") +const nodeResolve = require("rollup-plugin-node-resolve") + +module.exports = { + plugins: [ + nodeResolve({ + browser: true, + mainFields: ["module", "main"], + preferBuiltins: true + }), + + commonjs() + ] +}; diff --git a/src/worker/bundle-entry.ts b/src/worker/bundle-entry.ts new file mode 100644 index 00000000..1cbb6ed6 --- /dev/null +++ b/src/worker/bundle-entry.ts @@ -0,0 +1,9 @@ +import { expose } from "./index" +export * from "./index" + +if (typeof global !== "undefined") { + (global as any).expose = expose +} +if (typeof self !== "undefined") { + (self as any).expose = expose +} diff --git a/test/spawn.chromium.mocha.ts b/test/spawn.chromium.mocha.ts index f5f588e4..6a5cb350 100644 --- a/test/spawn.chromium.mocha.ts +++ b/test/spawn.chromium.mocha.ts @@ -1,8 +1,13 @@ +/* + * This code here will be run in a headless Chromium browser using `puppet-run`. + * Check the package.json scripts `test:puppeteer:*`. + */ + import { expect } from "chai" -import { spawn, Thread } from "../" +import { spawn, BlobWorker, Thread } from "../" // We need this as a work-around to make our threads Worker global, since -// the Parcel bundler would otherwise not recognize `new Worker()` as a web worker +// the bundler would otherwise not recognize `new Worker()` as a web worker import "../src/master/register" describe("threads in browser", function() { @@ -20,4 +25,22 @@ describe("threads in browser", function() { await Thread.terminate(increment) }) + it("can spawn and use a blob worker", async function() { + const baseUrl = new URL(window.location.href).origin + const workerSource = ` + // Makes expose() available on global scope + importScripts(${JSON.stringify(baseUrl + "/worker.js")}) + + let counter = 0 + + expose(function() { + return ++counter + }) + ` + const increment = await spawn<() => number>(BlobWorker.fromText(workerSource)) + expect(await increment()).to.equal(1) + expect(await increment()).to.equal(2) + expect(await increment()).to.equal(3) + await Thread.terminate(increment) + }) }) diff --git a/test/transferables.test.ts b/test/transferables.test.ts index 0db063db..cee0cd7f 100644 --- a/test/transferables.test.ts +++ b/test/transferables.test.ts @@ -21,10 +21,10 @@ function replaceArrayBufferWithPlaceholder(obj: In, arrayBuffer: } else if (Array.isArray(obj)) { return (obj as any[]).map(element => replaceArrayBufferWithPlaceholder(element, arrayBuffer)) as any } else if (obj && typeof obj === "object") { - const result: typeof obj = Object.create(Object.getPrototypeOf(obj)) + const result: In = Object.create(Object.getPrototypeOf(obj)) for (const key of Object.getOwnPropertyNames(obj)) { - result[key] = replaceArrayBufferWithPlaceholder(obj[key], arrayBuffer) + (result as any)[key] = replaceArrayBufferWithPlaceholder((obj as any)[key], arrayBuffer) } return result as any } else { From b1178fcfb0818eb044aed0a2ba537aa51e699922 Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Thu, 21 May 2020 06:09:35 +0200 Subject: [PATCH 3/5] Update puppet-run --- package-lock.json | 343 ++++++++++++++++++++++++++++++---------------- package.json | 2 +- 2 files changed, 224 insertions(+), 121 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6fd1209a..1f2178b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -291,12 +291,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -382,12 +376,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -483,12 +471,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -746,12 +728,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -1389,12 +1365,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -1557,12 +1527,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -1739,12 +1703,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -1883,12 +1841,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -2015,12 +1967,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -2133,12 +2079,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/template": { "version": "7.8.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", @@ -2926,12 +2866,6 @@ "js-tokens": "^4.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", @@ -4818,9 +4752,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001048", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001048.tgz", - "integrity": "sha512-g1iSHKVxornw0K8LG9LLdf+Fxnv7T1Z+mMsf0/YYLclQX4Cd522Ap0Lrw6NFqHgezit78dtyWxzlV2Xfc7vgRg==", + "version": "1.0.30001062", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001062.tgz", + "integrity": "sha512-ei9ZqeOnN7edDrb24QfJ0OZicpEbsWxv7WusOiQGz/f2SfvBgHHbOEwBJ8HKGVSyx8Z6ndPjxzR6m0NQq+0bfw==", "dev": true }, "chai": { @@ -5724,9 +5658,9 @@ } }, "electron-to-chromium": { - "version": "1.3.424", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.424.tgz", - "integrity": "sha512-h8apsMr1RK3OusH8iwxlJ7TZkpgWfg2HvTXZ3o1w9R/SeRKX0hEGMQmRyTWijZAloHfmfwTLaPurVqKWdFC5dw==", + "version": "1.3.447", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.447.tgz", + "integrity": "sha512-aXQTgDBUfSejZkwrFIQZ/jJOOevQE9ROsvIs4aSib+l4FknL4qUxGWjCySu4msJFHwVKo9fkX+8bIGSHQp/vTg==", "dev": true }, "elliptic": { @@ -6240,21 +6174,6 @@ "ms": "2.0.0" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -7063,6 +6982,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, "get-assigned-identifiers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", @@ -8315,9 +8240,9 @@ } }, "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", + "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==", "dev": true }, "mime-db": { @@ -8433,9 +8358,9 @@ } }, "mkdirp-classic": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz", - "integrity": "sha512-ejdnDQcR75gwknmMw/tx02AuRs8jCtqFoFqDZMjiNxsu85sRIJVXDKHuLYvUUPRBUtV2FpSZa9bL1BUa3BdR2g==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, "mocha": { @@ -8694,9 +8619,9 @@ } }, "node-releases": { - "version": "1.1.53", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz", - "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==", + "version": "1.1.56", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.56.tgz", + "integrity": "sha512-EVo605FhWLygH8a64TjgpjyHYOihkxECwX1bHHr8tETJKWEiWS2YJjPbvsX2jFjnjTNEgBCmk9mLjKG1Mf11cw==", "dev": true }, "normalize-package-data": { @@ -9407,38 +9332,216 @@ "dev": true }, "puppet-run": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/puppet-run/-/puppet-run-0.11.0.tgz", - "integrity": "sha512-Bf+OnNEDxwPlDOq6Twd2gmV0eXR60a15orUBz0Lns/kA14EW9WklZwLWwHfINRjxMb4ew1S5bPLJ2+NKlXFkmw==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/puppet-run/-/puppet-run-0.11.1.tgz", + "integrity": "sha512-ha4qBwL0PUbzeu1Dfo5ApE9S17I/aSoRgVpQSTksopv1BHS0sAljRbvTlyc7Rbc/A842XBlhiTsE6tU4Ca2Z4A==", "dev": true, "requires": { - "@babel/core": "^7.4.4", - "@babel/preset-env": "^7.4.4", - "@babel/preset-react": "^7.0.0", - "@babel/preset-typescript": "^7.3.3", + "@babel/core": "^7.9.6", + "@babel/preset-env": "^7.9.6", + "@babel/preset-react": "^7.9.4", + "@babel/preset-typescript": "^7.9.0", "babelify": "^10.0.0", - "browserify": "^16.2.3", + "browserify": "^16.5.1", "chai": "^4.2.0", "chalk": "^2.4.2", "dedent": "^0.7.0", "envify": "^4.1.0", - "get-port": "^4.0.0", + "get-port": "^4.2.0", "meow": "^5.0.0", "minimist": "^1.2.5", "mkdirp": "^0.5.1", - "nanoid": "^2.0.3", - "ora": "^3.0.0", + "nanoid": "^2.1.11", + "ora": "^3.4.0", "puppeteer-core": "^1.20.0", - "rimraf": "^2.6.2", - "serve-handler": "^6.0.0", - "sourcemapped-stacktrace": "^1.1.9", + "rimraf": "^2.7.1", + "serve-handler": "^6.1.2", + "sourcemapped-stacktrace": "^1.1.11", "which": "^1.3.1" }, "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/core": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.6.tgz", + "integrity": "sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.6", + "@babel/helper-module-transforms": "^7.9.0", + "@babel/helpers": "^7.9.6", + "@babel/parser": "^7.9.6", + "@babel/template": "^7.8.6", + "@babel/traverse": "^7.9.6", + "@babel/types": "^7.9.6", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz", + "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==", + "dev": true, + "requires": { + "@babel/types": "^7.9.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.9.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", + "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.9.5" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-imports": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-module-transforms": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", + "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-simple-access": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/template": "^7.8.6", + "@babel/types": "^7.9.0", + "lodash": "^4.17.13" + } + }, + "@babel/helper-simple-access": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helpers": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.6.tgz", + "integrity": "sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw==", + "dev": true, + "requires": { + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.9.6", + "@babel/types": "^7.9.6" + } + }, + "@babel/highlight": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", + "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.0", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/template": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/traverse": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.6.tgz", + "integrity": "sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.9.6", + "@babel/helper-function-name": "^7.9.5", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz", + "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.9.5", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } } @@ -10448,15 +10551,15 @@ } }, "stream-http": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.0.tgz", - "integrity": "sha512-cuB6RgO7BqC4FBYzmnvhob5Do3wIdIsXAgGycHJnW+981gHqoYcYz9lqjJrk8WXRddbwPuqPYRl+bag6mYv4lw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz", + "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==", "dev": true, "requires": { "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^3.0.6", - "xtend": "^4.0.0" + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" }, "dependencies": { "readable-stream": { diff --git a/package.json b/package.json index f7837770..97623bc1 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "execa": "^3.4.0", "mocha": "^5.2.0", "npm-run-all": "^4.1.5", - "puppet-run": "^0.11.0", + "puppet-run": "^0.11.1", "puppet-run-plugin-mocha": "^0.10.0-alpha", "rimraf": "^2.6.3", "rollup": "^1.16.2", From a8e71ebf5ad790571578264e98e879047e427993 Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Fri, 12 Jun 2020 10:07:20 +0200 Subject: [PATCH 4/5] Add BlobWorker tests --- .gitignore | 2 +- package-lock.json | 117 ++++++++++++++++++++---- package.json | 7 +- test/webpack/app-with-inlined-worker.ts | 24 +++++ test/webpack/raw-loader.d.ts | 4 + test/webpack/webpack.chromium.mocha.ts | 13 ++- test/webpack/webpack.node.config.js | 2 +- test/webpack/webpack.test.ts | 55 ++++++++++- test/webpack/webpack.web.config.js | 2 +- 9 files changed, 200 insertions(+), 26 deletions(-) create mode 100644 test/webpack/app-with-inlined-worker.ts create mode 100644 test/webpack/raw-loader.d.ts diff --git a/.gitignore b/.gitignore index 32a128a0..a341f355 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ dist/* dist-*/* node_modules/ test/rollup/dist/ -test/webpack/dist* +test/webpack/dist/ test/workers/*.js .DS_Store Thumbs.db diff --git a/package-lock.json b/package-lock.json index 1f2178b5..7c6fd1cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3255,6 +3255,12 @@ "@types/node": "*" } }, + "@types/json-schema": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", + "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -3668,9 +3674,9 @@ "dev": true }, "arg": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz", - "integrity": "sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, "argparse": { @@ -8088,9 +8094,9 @@ } }, "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "mamacro": { @@ -9616,6 +9622,73 @@ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", "dev": true }, + "raw-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.1.tgz", + "integrity": "sha512-baolhQBSi3iNh1cglJjA0mYzga+wePk7vdEX//1dTFd+v4TsQlQE0jitJSNF1OIP82rdYulH7otaVmdlDaJ64A==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -11045,23 +11118,33 @@ } }, "ts-node": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz", - "integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==", + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", "dev": true, "requires": { "arg": "^4.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "^3.0.0" + "source-map-support": "^0.5.17", + "yn": "3.1.1" }, "dependencies": { "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } } } }, @@ -11155,9 +11238,9 @@ } }, "typescript": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", - "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", + "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", "dev": true }, "uid2": { diff --git a/package.json b/package.json index 97623bc1..f4adcf0b 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "test": "run-s test:ava test:puppeteer:basic test:puppeteer:webpack", "test:ava": "cross-env TS_NODE_FILES=true ava", "test:puppeteer:basic": "puppet-run --plugin=mocha --bundle=./test/workers/:/workers/ --serve=./bundle/worker.js:/worker.js ./test/*.chromium*.ts", - "test:puppeteer:webpack": "puppet-run --serve ./test/webpack/dist.web/0.worker.js --serve ./test/webpack/dist.web/1.worker.js --plugin=mocha ./test/webpack/webpack.chromium.mocha.ts", + "test:puppeteer:webpack": "puppet-run --serve ./test/webpack/dist/app.web/0.worker.js --serve ./test/webpack/dist/app.web/1.worker.js --plugin=mocha ./test/webpack/webpack.chromium.mocha.ts", "posttest": "tslint --project .", "prepare": "run-s build" }, @@ -71,6 +71,7 @@ "npm-run-all": "^4.1.5", "puppet-run": "^0.11.1", "puppet-run-plugin-mocha": "^0.10.0-alpha", + "raw-loader": "^4.0.1", "rimraf": "^2.6.3", "rollup": "^1.16.2", "rollup-plugin-commonjs": "^10.0.1", @@ -78,10 +79,10 @@ "threads-plugin": "^1.2.0", "tiny-worker": "^2.2.0", "ts-loader": "^6.0.1", - "ts-node": "^8.1.0", + "ts-node": "^8.10.2", "tslint": "^5.16.0", "tslint-config-prettier": "^1.18.0", - "typescript": "^3.9.3", + "typescript": "^3.9.5", "wavy": "^1.0.4", "webpack": "^4.32.2", "worker-plugin": "^3.1.0" diff --git a/test/webpack/app-with-inlined-worker.ts b/test/webpack/app-with-inlined-worker.ts new file mode 100644 index 00000000..b10ebc95 --- /dev/null +++ b/test/webpack/app-with-inlined-worker.ts @@ -0,0 +1,24 @@ +/// + +import { spawn, BlobWorker } from "../../src/index" +import AdditionWorkerNodeBundle from "raw-loader!./dist/addition-worker.node/worker.js" +import AdditionWorkerWebBundle from "raw-loader!./dist/addition-worker.web/worker.js" + +const AdditionWorkerBundle = (process as any).browser ? AdditionWorkerWebBundle : AdditionWorkerNodeBundle +type AdditionWorker = (a: number, b: number) => number + +async function test() { + // We also want to test if referencing multiple different workers in a module + // built using webpack works + + const add = await spawn(BlobWorker.fromText(AdditionWorkerBundle)) + const result = await add(2, 3) + + if (result !== 5) { + throw Error("Unexpected result returned by addition worker: " + result) + } + + return "test succeeded" +} + +export default test diff --git a/test/webpack/raw-loader.d.ts b/test/webpack/raw-loader.d.ts new file mode 100644 index 00000000..886820bd --- /dev/null +++ b/test/webpack/raw-loader.d.ts @@ -0,0 +1,4 @@ +declare module "raw-loader!*" { + const content: string + export = content +} diff --git a/test/webpack/webpack.chromium.mocha.ts b/test/webpack/webpack.chromium.mocha.ts index f547e6a9..f148e5f4 100644 --- a/test/webpack/webpack.chromium.mocha.ts +++ b/test/webpack/webpack.chromium.mocha.ts @@ -1,11 +1,20 @@ // NOTE: -// We are gonna test the bundle that previously been built by the AVA tests (see webpack.test.ts) +// We are gonna test the bundles previously built by the AVA tests (see webpack.test.ts) describe("threads webpack browser bundle", function() { this.timeout(8000) it("works fine", async function() { - const bundle = require("./dist.web/main") + const bundle = require("./dist/app.web/main") + await bundle.test() + }) +}) + +describe("threads webpack browser bundle with inlined worker", function() { + this.timeout(8000) + + it("works fine", async function() { + const bundle = require("./dist/app-inlined.web/main") await bundle.test() }) }) diff --git a/test/webpack/webpack.node.config.js b/test/webpack/webpack.node.config.js index 5675edc2..8db142f8 100644 --- a/test/webpack/webpack.node.config.js +++ b/test/webpack/webpack.node.config.js @@ -13,7 +13,7 @@ module.exports = { library: "test", libraryExport: "default", libraryTarget: "commonjs", - path: path.resolve(__dirname, "./dist.node") + path: path.resolve(__dirname, "./dist/app.node") }, module: { rules: [ diff --git a/test/webpack/webpack.test.ts b/test/webpack/webpack.test.ts index 0e222f74..367c2d08 100644 --- a/test/webpack/webpack.test.ts +++ b/test/webpack/webpack.test.ts @@ -1,4 +1,5 @@ import test from "ava" +import * as path from "path" import Webpack from "webpack" const browserConfig = require("./webpack.web.config") @@ -30,6 +31,58 @@ test("can create a working server bundle with webpack", async t => { const stats = await runWebpack(serverConfig) t.deepEqual(stats.compilation.errors, [], stringifyWebpackError(stats.compilation.errors[0])) - const bundle = require("./dist.node/main") + const bundle = require("./dist/app.node/main") await bundle.test() }) + +test("can inline a worker into an app bundle", async t => { + // Bundle browser worker + let stats = await runWebpack({ + ...browserConfig, + entry: require.resolve("./addition-worker"), + output: { + filename: "worker.js", + path: path.resolve(__dirname, "dist/addition-worker.web") + }, + target: "webworker" + }) + t.deepEqual(stats.compilation.errors, [], stringifyWebpackError(stats.compilation.errors[0])) + + // Bundle server worker + stats = await runWebpack({ + ...serverConfig, + entry: require.resolve("./addition-worker"), + output: { + filename: "worker.js", + path: path.resolve(__dirname, "dist/addition-worker.node") + } + }) + t.deepEqual(stats.compilation.errors, [], stringifyWebpackError(stats.compilation.errors[0])) + + // Bundle browser app + stats = await runWebpack({ + ...browserConfig, + entry: require.resolve("./app-with-inlined-worker"), + output: { + ...serverConfig.output, + path: path.resolve(__dirname, "dist/app-inlined.web") + } + }) + t.deepEqual(stats.compilation.errors, [], stringifyWebpackError(stats.compilation.errors[0])) + + // Bundle server app + stats = await runWebpack({ + ...serverConfig, + entry: require.resolve("./app-with-inlined-worker"), + output: { + ...serverConfig.output, + path: path.resolve(__dirname, "dist/app-inlined.node") + } + }) + t.deepEqual(stats.compilation.errors, [], stringifyWebpackError(stats.compilation.errors[0])) + + const bundle = require("./dist/app-inlined.node/main") + const result = await bundle.test() + + t.is(result, "test succeeded") +}) diff --git a/test/webpack/webpack.web.config.js b/test/webpack/webpack.web.config.js index 127e6c27..f4934744 100644 --- a/test/webpack/webpack.web.config.js +++ b/test/webpack/webpack.web.config.js @@ -10,7 +10,7 @@ module.exports = { library: "test", libraryExport: "default", libraryTarget: "commonjs", - path: path.resolve(__dirname, "./dist.web") + path: path.resolve(__dirname, "./dist/app.web") }, module: { rules: [ From 63b9599b6b58f2336c441b1ba3c1987b32bce7bb Mon Sep 17 00:00:00 2001 From: Andy Wermke Date: Fri, 12 Jun 2020 10:43:28 +0200 Subject: [PATCH 5/5] Document BlobWorker --- docs/usage.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/usage.md b/docs/usage.md index 375a8dcf..a1a65bcd 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -143,6 +143,29 @@ try { } ``` +## Blob workers + +Sometimes you need to ship master and worker code in a single file. There is an alternative way to create a worker for those situations, allowing you to inline the worker code in the master code. + +The `BlobWorker` class works just like the regular `Worker` class, but instead of taking a path to a worker, the constructor takes the worker source code as a binary blob. + +There is also a convenience function `BlobWorker.fromText()` that creates a new `BlobWorker`, but allows you to pass a source string instead of a binary buffer. + +Here is a webpack-based example, leveraging the `raw-loader` to inline the worker code. The worker code that we load using the `raw-loader` is the content of bundles that have been created by two previous webpack runs: one worker build targetting node.js, one for web browsers. + +```js +import { spawn, BlobWorker } from "threads" +import MyWorkerNode from "raw-loader!../dist/worker.node/worker.js" +import MyWorkerWeb from "raw-loader!../dist/worker.web/worker.js" + +const MyWorker = process.browser ? MyWorkerWeb : MyWorkerNode + +const worker = await spawn(BlobWorker.fromText(MyWorker)) +// Now use this worker as always +``` + +Bundle this module and you will obtain a stand-alone bundle that has its worker inlined. This is particularly useful for libraries using threads.js. + ## TypeScript ### Type-safe workers