From c6a7db6537ec7dc7127b7fb31dd851da62ac007e Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 25 Sep 2020 11:11:09 +0200 Subject: [PATCH] allow to pass custom worker syntax --- lib/dependencies/WorkerPlugin.js | 64 +++++++++++++------ .../configCases/worker/custom-worker/index.js | 25 ++++++++ .../worker/custom-worker/module.js | 3 + .../custom-worker/node_modules/web-worker.js | 1 + .../worker/custom-worker/test.config.js | 5 ++ .../worker/custom-worker/test.filter.js | 5 ++ .../worker/custom-worker/webpack.config.js | 16 +++++ .../worker/custom-worker/worker.js | 4 ++ 8 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 test/configCases/worker/custom-worker/index.js create mode 100644 test/configCases/worker/custom-worker/module.js create mode 100644 test/configCases/worker/custom-worker/node_modules/web-worker.js create mode 100644 test/configCases/worker/custom-worker/test.config.js create mode 100644 test/configCases/worker/custom-worker/test.filter.js create mode 100644 test/configCases/worker/custom-worker/webpack.config.js create mode 100644 test/configCases/worker/custom-worker/worker.js diff --git a/lib/dependencies/WorkerPlugin.js b/lib/dependencies/WorkerPlugin.js index b2bc97e65..a6a87f55c 100644 --- a/lib/dependencies/WorkerPlugin.js +++ b/lib/dependencies/WorkerPlugin.js @@ -11,6 +11,7 @@ const CommentCompilationWarning = require("../CommentCompilationWarning"); const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning"); const formatLocation = require("../formatLocation"); const EnableChunkLoadingPlugin = require("../javascript/EnableChunkLoadingPlugin"); +const { equals } = require("../util/ArrayHelpers"); const { harmonySpecifierTag } = require("./HarmonyImportDependencyParserPlugin"); @@ -27,6 +28,13 @@ const getUrl = module => { return pathToFileURL(module.resource).toString(); }; +const DEFAULT_SYNTAX = [ + "Worker", + "SharedWorker", + "navigator.serviceWorker.register()", + "Worker from worker_threads" +]; + class WorkerPlugin { constructor(chunkLoading) { this._chunkLoading = chunkLoading; @@ -115,6 +123,9 @@ class WorkerPlugin { */ const parserPlugin = (parser, parserOptions) => { if (parserOptions.worker === false) return; + const options = !Array.isArray(parserOptions.worker) + ? ["..."] + : parserOptions.worker; const handleNewWorker = expr => { if (expr.arguments.length === 0 || expr.arguments.length > 2) return; @@ -224,27 +235,40 @@ class WorkerPlugin { return true; } }; - parser.hooks.new.for("Worker").tap("WorkerPlugin", handleNewWorker); - parser.hooks.new - .for("SharedWorker") - .tap("WorkerPlugin", handleNewWorker); - parser.hooks.call - .for("navigator.serviceWorker.register") - .tap("WorkerPlugin", handleNewWorker); - parser.hooks.new - .for(harmonySpecifierTag) - .tap("WorkerPlugin", expr => { - const settings = /** @type {HarmonySettings} */ (parser.currentTagData); - if ( - !settings || - settings.source !== "worker_threads" || - settings.ids.length !== 1 || - settings.ids[0] !== "Worker" - ) { - return; + const processItem = item => { + if (item.endsWith("()")) { + parser.hooks.call + .for(item.slice(0, -2)) + .tap("WorkerPlugin", handleNewWorker); + } else { + const match = /^(.+?)(\(\))?\s+from\s+(.+)$/.exec(item); + if (match) { + const ids = match[1].split("."); + const call = match[2]; + const source = match[3]; + (call ? parser.hooks.call : parser.hooks.new) + .for(harmonySpecifierTag) + .tap("WorkerPlugin", expr => { + const settings = /** @type {HarmonySettings} */ (parser.currentTagData); + if ( + !settings || + settings.source !== source || + !equals(settings.ids, ids) + ) { + return; + } + return handleNewWorker(expr); + }); + } else { + parser.hooks.new.for(item).tap("WorkerPlugin", handleNewWorker); } - return handleNewWorker(expr); - }); + } + }; + for (const item of options) { + if (item === "...") { + DEFAULT_SYNTAX.forEach(processItem); + } else processItem(item); + } }; normalModuleFactory.hooks.parser .for("javascript/auto") diff --git a/test/configCases/worker/custom-worker/index.js b/test/configCases/worker/custom-worker/index.js new file mode 100644 index 000000000..efec115b5 --- /dev/null +++ b/test/configCases/worker/custom-worker/index.js @@ -0,0 +1,25 @@ +import Worker from "web-worker"; + +it("should allow to create a WebWorker", async () => { + const worker = new Worker(new URL("./worker.js", import.meta.url), { + type: "module" + }); + worker.postMessage("ok"); + const result = await new Promise(resolve => { + worker.onmessage = event => { + resolve(event.data); + }; + }); + expect(result).toBe("data: OK, thanks"); +}); + +it("should allow to share chunks", async () => { + const promise = import("./module"); + const script = document.head._children[0]; + const src = script.src; + const file = src.slice(src.lastIndexOf("/")); + __non_webpack_require__(`./${file}`); + script.onload(); + const { upper } = await promise; + expect(upper("ok")).toBe("OK"); +}); diff --git a/test/configCases/worker/custom-worker/module.js b/test/configCases/worker/custom-worker/module.js new file mode 100644 index 000000000..3a0b527ff --- /dev/null +++ b/test/configCases/worker/custom-worker/module.js @@ -0,0 +1,3 @@ +export function upper(str) { + return str.toUpperCase(); +} diff --git a/test/configCases/worker/custom-worker/node_modules/web-worker.js b/test/configCases/worker/custom-worker/node_modules/web-worker.js new file mode 100644 index 000000000..b10d2db26 --- /dev/null +++ b/test/configCases/worker/custom-worker/node_modules/web-worker.js @@ -0,0 +1 @@ +export default Worker; diff --git a/test/configCases/worker/custom-worker/test.config.js b/test/configCases/worker/custom-worker/test.config.js new file mode 100644 index 000000000..65ddf7b1d --- /dev/null +++ b/test/configCases/worker/custom-worker/test.config.js @@ -0,0 +1,5 @@ +module.exports = { + findBundle: function(i, options) { + return ["main.js"]; + } +}; diff --git a/test/configCases/worker/custom-worker/test.filter.js b/test/configCases/worker/custom-worker/test.filter.js new file mode 100644 index 000000000..703962334 --- /dev/null +++ b/test/configCases/worker/custom-worker/test.filter.js @@ -0,0 +1,5 @@ +var supportsWorker = require("../../../helpers/supportsWorker"); + +module.exports = function (config) { + return supportsWorker(); +}; diff --git a/test/configCases/worker/custom-worker/webpack.config.js b/test/configCases/worker/custom-worker/webpack.config.js new file mode 100644 index 000000000..53c10fff3 --- /dev/null +++ b/test/configCases/worker/custom-worker/webpack.config.js @@ -0,0 +1,16 @@ +module.exports = { + output: { + filename: "[name].js" + }, + target: "web", + module: { + rules: [ + { + test: /\.[cm]?js$/, + parser: { + worker: ["default from web-worker", "..."] + } + } + ] + } +}; diff --git a/test/configCases/worker/custom-worker/worker.js b/test/configCases/worker/custom-worker/worker.js new file mode 100644 index 000000000..fc12b94a6 --- /dev/null +++ b/test/configCases/worker/custom-worker/worker.js @@ -0,0 +1,4 @@ +onmessage = async event => { + const { upper } = await import("./module"); + postMessage(`data: ${upper(event.data)}, thanks`); +};