From 0d8058858245a408b7176d774c9e9b44a65cd585 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 19 Feb 2020 17:49:05 +0200 Subject: [PATCH 1/2] fix: worker compilation should not be async In some cases, when using the AOT of Angular applications, multiple worker compilations may happen at the same time. As they share the same Angular Compiler instance, the compilation itself may fail. To resolve this, ensure there's only one compilation of a worker in a specified moment - start the next one after the current one finishes. --- src/index.js | 197 +++++++++++++++++++++++-------------------- src/package.json | 2 +- src/test/test.es6.js | 4 +- 3 files changed, 110 insertions(+), 93 deletions(-) diff --git a/src/index.js b/src/index.js index c28f89d..f57b4e6 100644 --- a/src/index.js +++ b/src/index.js @@ -37,103 +37,120 @@ module.exports = function workerLoader() { }; const requests = []; +let pitchPromise = Promise.resolve(); module.exports.pitch = function pitch(request) { - if (!this.webpack) { - throw new Error("Only usable with webpack"); - } - const callback = this.async(); - const options = loaderUtils.getOptions(this) || {}; - const compilerOptions = this._compiler.options || {}; - const pluginOptions = compilerOptions.plugins.find(p => p[NATIVESCRIPT_WORKER_PLUGIN_SYMBOL]).options; - - // handle calls to itself to avoid an infinite loop - if (requests.indexOf(request) === -1) { - requests.push(request); - } else { - return callback(null, ""); - } - validateSchema(optionsSchema, options, "Worker Loader"); - if (!this._compilation.workerChunks) { - this._compilation.workerChunks = []; - } + pitchPromise = pitchPromise.then(() => + new Promise((resolve) => { + if (!this.webpack) { + const error = new Error("Only usable with webpack"); + resolve(); + return callback(error); + } - const filename = loaderUtils.interpolateName(this, options.name || "[hash].worker.js", { - context: options.context || this.rootContext, - regExp: options.regExp, - }); - - const outputOptions = { - filename, - chunkFilename: `[id].${filename}`, - namedChunkFilename: null, - }; - - const plugins = (pluginOptions.plugins || []).map(plugin => { - if (typeof plugin !== "string") { - return plugin; - } - const found = compilerOptions.plugins.find(p => p.constructor.name === plugin); - if (!found) { - console.warn(`Warning (worker-plugin): Plugin "${plugin}" is not found.`); - } - return found; - }); - - const workerCompiler = this._compilation.createChildCompiler("worker", outputOptions, plugins); - new WebWorkerTemplatePlugin(outputOptions).apply(workerCompiler); - if (this.target !== "webworker" && this.target !== "web") { - new NodeTargetPlugin().apply(workerCompiler); - } + const options = loaderUtils.getOptions(this) || {}; + const compilerOptions = this._compiler.options || {}; + const pluginOptions = compilerOptions.plugins.find(p => p[NATIVESCRIPT_WORKER_PLUGIN_SYMBOL]).options; + + // handle calls to itself to avoid an infinite loop + if (requests.indexOf(request) === -1) { + requests.push(request); + } else { + resolve(); + return callback(null, ""); + } + + try { + validateSchema(optionsSchema, options, "Worker Loader"); + } catch (err) { + resolve(); + return callback(err); + } + + if (!this._compilation.workerChunks) { + this._compilation.workerChunks = []; + } + + const filename = loaderUtils.interpolateName(this, options.name || "[hash].worker.js", { + context: options.context || this.rootContext, + regExp: options.regExp, + }); - new SingleEntryPlugin(this.context, `!!${request}`, "main").apply(workerCompiler); - const plugin = { name: "WorkerLoader" }; - - workerCompiler.hooks.thisCompilation.tap(plugin, compilation => { - /** - * A dirty hack to disable HMR plugin in childCompilation: - * https://github.com/webpack/webpack/blob/4056506488c1e071dfc9a0127daa61bf531170bf/lib/HotModuleReplacementPlugin.js#L154 - * - * Once we update to webpack@4.40.3 and above this can be removed: - * https://github.com/webpack/webpack/commit/1c4138d6ac04b7b47daa5ec4475c0ae1b4f596a2 - */ - compilation.hotUpdateChunkTemplate = null; - }); - - workerCompiler.runAsChild((err, entries, childCompilation) => { - if (err) { - return callback(err); - } - - if (entries[0]) { - const fileDeps = Array.from(childCompilation.fileDependencies); - this.clearDependencies(); - fileDeps.forEach(fileName => { - this.addDependency(fileName); + const outputOptions = { + filename, + chunkFilename: `[id].${filename}`, + namedChunkFilename: null, + }; + + const plugins = (pluginOptions.plugins || []).map(plugin => { + if (typeof plugin !== "string") { + return plugin; + } + const found = compilerOptions.plugins.find(p => p.constructor.name === plugin); + if (!found) { + console.warn(`Warning (worker-plugin): Plugin "${plugin}" is not found.`); + } + return found; }); - /** - * Clears the hash of the child compilation as it affects the hash of the parent compilation: - * https://github.com/webpack/webpack/blob/4056506488c1e071dfc9a0127daa61bf531170bf/lib/Compilation.js#L2281 - * - * If we don't clear the hash an emit of runtime.js and an empty [somehash].hot-update.json will happen on save without changes. - * This will restart the NS application. - */ - childCompilation.hash = ""; - const workerFile = entries[0].files[0]; - this._compilation.workerChunks.push(workerFile); - const workerFactory = getWorker(workerFile); - - // invalidate cache - const processedIndex = requests.indexOf(request); - if (processedIndex > -1) { - requests.splice(processedIndex, 1); + + const workerCompiler = this._compilation.createChildCompiler("worker", outputOptions, plugins); + new WebWorkerTemplatePlugin(outputOptions).apply(workerCompiler); + if (this.target !== "webworker" && this.target !== "web") { + new NodeTargetPlugin().apply(workerCompiler); } - return callback(null, `module.exports = function() {\n\treturn ${workerFactory};\n};`); - } + new SingleEntryPlugin(this.context, `!!${request}`, "main").apply(workerCompiler); + const plugin = { name: "WorkerLoader" }; + + workerCompiler.hooks.thisCompilation.tap(plugin, compilation => { + /** + * A dirty hack to disable HMR plugin in childCompilation: + * https://github.com/webpack/webpack/blob/4056506488c1e071dfc9a0127daa61bf531170bf/lib/HotModuleReplacementPlugin.js#L154 + * + * Once we update to webpack@4.40.3 and above this can be removed: + * https://github.com/webpack/webpack/commit/1c4138d6ac04b7b47daa5ec4475c0ae1b4f596a2 + */ + compilation.hotUpdateChunkTemplate = null; + }); - return callback(null, ""); - }); + workerCompiler.runAsChild((err, entries, childCompilation) => { + if (err) { + resolve(); + return callback(err); + } + + if (entries[0]) { + const fileDeps = Array.from(childCompilation.fileDependencies); + this.clearDependencies(); + fileDeps.forEach(fileName => { + this.addDependency(fileName); + }); + /** + * Clears the hash of the child compilation as it affects the hash of the parent compilation: + * https://github.com/webpack/webpack/blob/4056506488c1e071dfc9a0127daa61bf531170bf/lib/Compilation.js#L2281 + * + * If we don't clear the hash an emit of runtime.js and + * an empty [somehash].hot-update.json will happen on save without changes. + * This will restart the NS application. + */ + childCompilation.hash = ""; + const workerFile = entries[0].files[0]; + this._compilation.workerChunks.push(workerFile); + const workerFactory = getWorker(workerFile); + + // invalidate cache + const processedIndex = requests.indexOf(request); + if (processedIndex > -1) { + requests.splice(processedIndex, 1); + } + + resolve(); + return callback(null, `module.exports = function() {\n\treturn ${workerFactory};\n};`); + } + + resolve(); + return callback(null, ""); + }); + })); }; - diff --git a/src/package.json b/src/package.json index 74744dd..ff12e7c 100644 --- a/src/package.json +++ b/src/package.json @@ -5,7 +5,7 @@ "description": "nativescript worker loader module for webpack", "scripts": { "pretest": "babel ./test/test.es6.js --out-file ./test/test.es5.js", - "test": "mocha test/test.es5.js", + "test": "mocha test/test.es5.js --timeout 5000", "posttest": "eslint .", "prepare": "npm run test" }, diff --git a/src/test/test.es6.js b/src/test/test.es6.js index 4ecec21..e70d136 100644 --- a/src/test/test.es6.js +++ b/src/test/test.es6.js @@ -171,10 +171,10 @@ describe("worker-loader", () => { module: { rules: [ { - test: /worker\.js$/, + test: /(w1|w2)\.js$/, loader: "../index.js", options: { - inline: true, + name: "[name].js", fallback: false, }, }, From 4b070123d9228487f320b728d434a332b929223a Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Thu, 20 Feb 2020 08:59:34 +0200 Subject: [PATCH 2/2] release: cut 0.11.0 release --- CHANGELOG.md | 7 +++++++ src/package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3884698..8aa929b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.11.0](https://github.com/NativeScript/worker-loader/compare/0.10.0...0.11.0) (2020-02-20) + +### Bug Fixes + +* worker compilation should not be async ([#54](https://github.com/NativeScript/worker-loader/pull/54)) + + ## [0.9.5](https://github.com/NativeScript/worker-loader/compare/0.9.4...0.9.5) (2019-02-06) diff --git a/src/package.json b/src/package.json index ff12e7c..6eaba34 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "nativescript-worker-loader", - "version": "0.10.0", + "version": "0.11.0", "author": "NativeScript team", "description": "nativescript worker loader module for webpack", "scripts": {