diff --git a/lib/Compilation.js b/lib/Compilation.js index 78d6623e5..d6d54c4f1 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -208,6 +208,7 @@ class Compilation extends Tapable { break; } }); + this.name = undefined; this.compiler = compiler; this.resolverFactory = compiler.resolverFactory; this.inputFileSystem = compiler.inputFileSystem; diff --git a/lib/Compiler.js b/lib/Compiler.js index 5b20c5085..e7805c4b3 100644 --- a/lib/Compiler.js +++ b/lib/Compiler.js @@ -74,6 +74,8 @@ class Compiler extends Tapable { } }); + this.name = undefined; + this.parentCompilation = undefined; this.outputPath = ""; this.outputFileSystem = null; this.inputFileSystem = null; diff --git a/lib/HotModuleReplacementPlugin.js b/lib/HotModuleReplacementPlugin.js index 2ceccf123..5258f4ed6 100644 --- a/lib/HotModuleReplacementPlugin.js +++ b/lib/HotModuleReplacementPlugin.js @@ -145,8 +145,8 @@ module.exports = class HotModuleReplacementPlugin { h: compilation.hash, c: {} }; - for (let chunkId of Object.keys(records.chunkHashs)) { - chunkId = isNaN(+chunkId) ? chunkId : +chunkId; + for (const key of Object.keys(records.chunkHashs)) { + const chunkId = isNaN(+key) ? key : +key; const currentChunk = compilation.chunks.find( chunk => chunk.id === chunkId ); diff --git a/lib/RuntimeTemplate.js b/lib/RuntimeTemplate.js index d98f097e2..36ad8d6a2 100644 --- a/lib/RuntimeTemplate.js +++ b/lib/RuntimeTemplate.js @@ -195,7 +195,7 @@ module.exports = class RuntimeTemplate { } else if (originModule.buildMeta.strictHarmonyModule) { if (exportName) { return "/* non-default import from non-esm module */undefined"; - } else if (!exportName) { + } else { if (asiSafe) { return `/*#__PURE__*/{ /* fake namespace object */ "default": ${importVar} }`; } else { diff --git a/lib/WebpackError.js b/lib/WebpackError.js index 9e44b5c30..4fd233881 100644 --- a/lib/WebpackError.js +++ b/lib/WebpackError.js @@ -5,6 +5,14 @@ "use strict"; module.exports = class WebpackError extends Error { + constructor(message) { + super(message); + + this.details = undefined; + + Error.captureStackTrace(this, this.constructor); + } + inspect() { return this.stack + (this.details ? `\n${this.details}` : ""); } diff --git a/lib/dependencies/HarmonyImportSpecifierDependency.js b/lib/dependencies/HarmonyImportSpecifierDependency.js index 995ac128d..b24ffe4fb 100644 --- a/lib/dependencies/HarmonyImportSpecifierDependency.js +++ b/lib/dependencies/HarmonyImportSpecifierDependency.js @@ -28,6 +28,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency { this.callArgs = undefined; this.call = undefined; this.directImport = undefined; + this.shorthand = undefined; } get type() { diff --git a/lib/dependencies/LoaderPlugin.js b/lib/dependencies/LoaderPlugin.js index ec0a22631..b978fc6d9 100644 --- a/lib/dependencies/LoaderPlugin.js +++ b/lib/dependencies/LoaderPlugin.js @@ -36,6 +36,7 @@ class LoaderPlugin { }` ) ); + compilation.semaphore.release(); compilation.addModuleDependencies( module, [ @@ -48,37 +49,39 @@ class LoaderPlugin { "lm", false, err => { - if (err) return callback(err); + compilation.semaphore.acquire(() => { + if (err) return callback(err); - if (!dep.module) - return callback(new Error("Cannot load the module")); + if (!dep.module) + return callback(new Error("Cannot load the module")); - if (dep.module.error) return callback(dep.module.error); - if (!dep.module._source) - throw new Error( - "The module created for a LoaderDependency must have a property _source" - ); - let source, map; - const moduleSource = dep.module._source; - if (moduleSource.sourceAndMap) { - const sourceAndMap = moduleSource.sourceAndMap(); - map = sourceAndMap.map; - source = sourceAndMap.source; - } else { - map = moduleSource.map(); - source = moduleSource.source(); - } - if (dep.module.buildInfo.fileDependencies) { - for (const d of dep.module.buildInfo.fileDependencies) { - loaderContext.addDependency(d); + if (dep.module.error) return callback(dep.module.error); + if (!dep.module._source) + throw new Error( + "The module created for a LoaderDependency must have a property _source" + ); + let source, map; + const moduleSource = dep.module._source; + if (moduleSource.sourceAndMap) { + const sourceAndMap = moduleSource.sourceAndMap(); + map = sourceAndMap.map; + source = sourceAndMap.source; + } else { + map = moduleSource.map(); + source = moduleSource.source(); } - } - if (dep.module.buildInfo.contextDependencies) { - for (const d of dep.module.buildInfo.contextDependencies) { - loaderContext.addContextDependency(d); + if (dep.module.buildInfo.fileDependencies) { + for (const d of dep.module.buildInfo.fileDependencies) { + loaderContext.addDependency(d); + } } - } - return callback(null, source, map, dep.module); + if (dep.module.buildInfo.contextDependencies) { + for (const d of dep.module.buildInfo.contextDependencies) { + loaderContext.addContextDependency(d); + } + } + return callback(null, source, map, dep.module); + }); } ); }; diff --git a/lib/optimize/ChunkModuleIdRangePlugin.js b/lib/optimize/ChunkModuleIdRangePlugin.js index 33d319747..f507e426c 100644 --- a/lib/optimize/ChunkModuleIdRangePlugin.js +++ b/lib/optimize/ChunkModuleIdRangePlugin.js @@ -3,35 +3,44 @@ Author Tobias Koppers @sokra */ "use strict"; + +const sortByIndex = (a, b) => { + return a.index - b.index; +}; + +const sortByIndex2 = (a, b) => { + return a.index2 - b.index2; +}; + class ChunkModuleIdRangePlugin { constructor(options) { this.options = options; } + apply(compiler) { const options = this.options; compiler.hooks.compilation.tap("ChunkModuleIdRangePlugin", compilation => { compilation.hooks.moduleIds.tap("ChunkModuleIdRangePlugin", modules => { - const chunk = this.chunks.find(chunk => chunk.name === options.name); - if (!chunk) + const chunk = compilation.chunks.find( + chunk => chunk.name === options.name + ); + if (!chunk) { throw new Error( - "ChunkModuleIdRangePlugin: Chunk with name '" + - options.name + - "' was not found" + `ChunkModuleIdRangePlugin: Chunk with name '${ + options.name + }"' was not found` ); - let currentId = options.start; + } + let chunkModules; if (options.order) { - chunkModules = chunk.modules.slice(); + chunkModules = Array.from(chunk.modulesIterable); switch (options.order) { case "index": - chunkModules.sort((a, b) => { - return a.index - b.index; - }); + chunkModules.sort(sortByIndex); break; case "index2": - chunkModules.sort((a, b) => { - return a.index2 - b.index2; - }); + chunkModules.sort(sortByIndex2); break; default: throw new Error( @@ -40,10 +49,11 @@ class ChunkModuleIdRangePlugin { } } else { chunkModules = modules.filter(m => { - return m.chunks.includes(chunk); + return m.chunksIterable.has(chunk); }); } + let currentId = options.start || 0; for (let i = 0; i < chunkModules.length; i++) { const m = chunkModules[i]; if (m.id === null) { diff --git a/lib/util/Semaphore.js b/lib/util/Semaphore.js index 177f94bd7..359378056 100644 --- a/lib/util/Semaphore.js +++ b/lib/util/Semaphore.js @@ -8,6 +8,7 @@ class Semaphore { constructor(available) { this.available = available; this.waiters = []; + this._continue = this._continue.bind(this); } acquire(callback) { @@ -20,11 +21,19 @@ class Semaphore { } release() { + this.available++; if (this.waiters.length > 0) { - const callback = this.waiters.pop(); - process.nextTick(callback); - } else { - this.available++; + process.nextTick(this._continue); + } + } + + _continue() { + if (this.available > 0) { + if (this.waiters.length > 0) { + this.available--; + const callback = this.waiters.pop(); + callback(); + } } } } diff --git a/package.json b/package.json index 87ec3e298..426780efb 100644 --- a/package.json +++ b/package.json @@ -89,9 +89,9 @@ ], "scripts": { "setup": "node ./setup/setup.js", - "test": "node --max-old-space-size=4096 --harmony --trace-deprecation node_modules/jest-cli/bin/jest", - "test:integration": "node --max-old-space-size=4096 --harmony --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"/test/*.test.js\"", - "test:unit": "node --max-old-space-size=4096 --harmony --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"/test/*.unittest.js\"", + "test": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest", + "test:integration": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"/test/*.test.js\"", + "test:unit": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"/test/*.unittest.js\"", "travis:integration": "yarn cover:init && yarn cover:integration --ci --reporters jest-silent-reporter --maxWorkers 4 && yarn cover:report-min", "travis:unit": "yarn cover:init && yarn cover:unit --ci --reporters jest-silent-reporter", "travis:lint": "yarn lint", @@ -99,7 +99,7 @@ "appveyor:integration": "yarn cover:init && yarn cover:integration --ci --reporters jest-silent-reporter --maxWorkers 2 && yarn cover:report-min", "appveyor:unit": "yarn cover:init && yarn cover:unit --ci --reporters jest-silent-reporter && yarn cover:report-min", "appveyor:benchmark": "yarn benchmark --ci", - "circleci:test": "node --max-old-space-size=4096 --harmony --trace-deprecation node_modules/jest-cli/bin/jest --ci --reporters jest-silent-reporter", + "circleci:test": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --ci --reporters jest-silent-reporter", "circleci:lint": "yarn lint", "build:examples": "cd examples && node buildAll.js", "pretest": "yarn lint", @@ -108,13 +108,13 @@ "code-lint": "eslint setup lib bin hot buildin \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\"", "fix": "yarn code-lint --fix", "pretty": "prettier \"setup/**/*.js\" \"lib/**/*.js\" \"bin/*.js\" \"hot/*.js\" \"buildin/*.js\" \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\" --write", - "schema-lint": "node --max-old-space-size=4096 --harmony node_modules/jest-cli/bin/jest --reporters jest-silent-reporter --testMatch \"/test/*.lint.js\"", - "benchmark": "node --max-old-space-size=4096 --harmony node_modules/jest-cli/bin/jest --reporters jest-silent-reporter --testMatch \"/test/*.benchmark.js\" --runInBand", + "schema-lint": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --reporters jest-silent-reporter --testMatch \"/test/*.lint.js\"", + "benchmark": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --reporters jest-silent-reporter --testMatch \"/test/*.benchmark.js\" --runInBand", "cover": "yarn cover:init && yarn cover:all && yarn cover:report", "cover:init": "rimraf coverage", - "cover:all": "node --max-old-space-size=4096 --harmony node_modules/jest-cli/bin/jest --coverage", - "cover:integration": "node --max-old-space-size=4096 --harmony node_modules/jest-cli/bin/jest --testMatch \"/test/*.test.js\" --coverage", - "cover:unit": "node --max-old-space-size=4096 --harmony node_modules/jest-cli/bin/jest --testMatch \"/test/*.unittest.js\" --coverage", + "cover:all": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --coverage", + "cover:integration": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"/test/*.test.js\" --coverage", + "cover:unit": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"/test/*.unittest.js\" --coverage", "cover:report": "istanbul report", "cover:report-min": "istanbul report --report lcovonly" }, diff --git a/test/configCases/race-conditions/load-module/index.js b/test/configCases/race-conditions/load-module/index.js new file mode 100644 index 000000000..668417cd2 --- /dev/null +++ b/test/configCases/race-conditions/load-module/index.js @@ -0,0 +1,4 @@ +it("should not deadlock when using loadModule", () => { + const result = require("./loader!"); + expect(result).toMatch(/console.log\(42\)/); +}); diff --git a/test/configCases/race-conditions/load-module/loader.js b/test/configCases/race-conditions/load-module/loader.js new file mode 100644 index 000000000..444c2c9da --- /dev/null +++ b/test/configCases/race-conditions/load-module/loader.js @@ -0,0 +1,15 @@ +module.exports = function() { + const callback = this.async(); + let finished = false; + this.loadModule("./module.js", (err, result) => { + if (err) return callback(err); + if (finished) return; + finished = true; + callback(null, `module.exports = ${JSON.stringify(result)};`); + }); + setTimeout(() => { + if (finished) return; + finished = true; + callback(new Error("loadModule is hanging")); + }, 2000); +}; diff --git a/test/configCases/race-conditions/load-module/module.js b/test/configCases/race-conditions/load-module/module.js new file mode 100644 index 000000000..753a47d52 --- /dev/null +++ b/test/configCases/race-conditions/load-module/module.js @@ -0,0 +1 @@ +console.log(42); diff --git a/test/configCases/race-conditions/load-module/webpack.config.js b/test/configCases/race-conditions/load-module/webpack.config.js new file mode 100644 index 000000000..e39f50108 --- /dev/null +++ b/test/configCases/race-conditions/load-module/webpack.config.js @@ -0,0 +1,3 @@ +module.exports = { + parallelism: 1 +}; diff --git a/test/statsCases/chunk-module-id-range/a.js b/test/statsCases/chunk-module-id-range/a.js new file mode 100644 index 000000000..e94fef185 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/a.js @@ -0,0 +1 @@ +export default "a"; diff --git a/test/statsCases/chunk-module-id-range/b.js b/test/statsCases/chunk-module-id-range/b.js new file mode 100644 index 000000000..eff703ff4 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/b.js @@ -0,0 +1 @@ +export default "b"; diff --git a/test/statsCases/chunk-module-id-range/c.js b/test/statsCases/chunk-module-id-range/c.js new file mode 100644 index 000000000..5d50db5bc --- /dev/null +++ b/test/statsCases/chunk-module-id-range/c.js @@ -0,0 +1 @@ +export default "c"; diff --git a/test/statsCases/chunk-module-id-range/d.js b/test/statsCases/chunk-module-id-range/d.js new file mode 100644 index 000000000..987d6d7e4 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/d.js @@ -0,0 +1 @@ +export default "d"; diff --git a/test/statsCases/chunk-module-id-range/e.js b/test/statsCases/chunk-module-id-range/e.js new file mode 100644 index 000000000..d97e38b22 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/e.js @@ -0,0 +1 @@ +export default "e"; diff --git a/test/statsCases/chunk-module-id-range/expected.txt b/test/statsCases/chunk-module-id-range/expected.txt new file mode 100644 index 000000000..a34fa06a6 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/expected.txt @@ -0,0 +1,22 @@ +Hash: 27b68d27e07b42624dae +Time: Xms +Built at: Thu Jan 01 1970 00:00:00 GMT + Asset Size Chunks Chunk Names +main2.js 3.89 KiB 0 [emitted] main2 +main1.js 3.89 KiB 1 [emitted] main1 +Entrypoint main1 = main1.js +Entrypoint main2 = main2.js +chunk {0} main2.js (main2) 136 bytes [entry] [rendered] + > ./main2 main2 + [0] ./e.js 20 bytes {0} [built] + [1] ./f.js 20 bytes {0} [built] + [2] ./main2.js 56 bytes {0} [built] + [100] ./d.js 20 bytes {0} {1} [built] + [101] ./a.js 20 bytes {0} {1} [built] +chunk {1} main1.js (main1) 136 bytes [entry] [rendered] + > ./main1 main1 + [3] ./b.js 20 bytes {1} [built] + [4] ./main1.js 56 bytes {1} [built] + [100] ./d.js 20 bytes {0} {1} [built] + [101] ./a.js 20 bytes {0} {1} [built] + [102] ./c.js 20 bytes {1} [built] \ No newline at end of file diff --git a/test/statsCases/chunk-module-id-range/f.js b/test/statsCases/chunk-module-id-range/f.js new file mode 100644 index 000000000..657d4dee8 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/f.js @@ -0,0 +1 @@ +export default "f"; diff --git a/test/statsCases/chunk-module-id-range/main1.js b/test/statsCases/chunk-module-id-range/main1.js new file mode 100644 index 000000000..e1fd20493 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/main1.js @@ -0,0 +1,4 @@ +import "./a"; +import "./b"; +import "./c"; +import "./d"; diff --git a/test/statsCases/chunk-module-id-range/main2.js b/test/statsCases/chunk-module-id-range/main2.js new file mode 100644 index 000000000..4b63b6243 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/main2.js @@ -0,0 +1,4 @@ +import "./a"; +import "./d"; +import "./e"; +import "./f"; diff --git a/test/statsCases/chunk-module-id-range/webpack.config.js b/test/statsCases/chunk-module-id-range/webpack.config.js new file mode 100644 index 000000000..621d9df44 --- /dev/null +++ b/test/statsCases/chunk-module-id-range/webpack.config.js @@ -0,0 +1,28 @@ +const webpack = require("../../../"); + +module.exports = { + mode: "none", + entry: { + main1: "./main1", + main2: "./main2" + }, + plugins: [ + new webpack.optimize.ChunkModuleIdRangePlugin({ + name: "main1", + start: 100, + end: 102 + }), + new webpack.optimize.ChunkModuleIdRangePlugin({ + name: "main2", + order: "index2" + }) + ], + stats: { + chunks: true, + chunkModules: true, + chunkOrigins: true, + entrypoints: true, + modules: false, + publicPath: true + } +};