From 363723fc84f7b8477592e0105aeb331ec9a017af Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 14 Aug 2017 05:01:11 +0200 Subject: node_modules --- .../lib/optimize/AggressiveMergingPlugin.js | 62 +- .../lib/optimize/AggressiveSplittingPlugin.js | 101 +-- .../lib/optimize/ChunkModuleIdRangePlugin.js | 4 +- .../webpack/lib/optimize/CommonsChunkPlugin.js | 51 +- .../webpack/lib/optimize/ConcatenatedModule.js | 816 +++++++++++++++++++++ .../lib/optimize/EnsureChunkConditionsPlugin.js | 9 +- .../lib/optimize/FlagIncludedChunksPlugin.js | 8 +- .../lib/optimize/MergeDuplicateChunksPlugin.js | 15 +- .../lib/optimize/ModuleConcatenationPlugin.js | 307 ++++++++ .../webpack/lib/optimize/OccurrenceOrderPlugin.js | 120 ++- .../lib/optimize/RemoveParentModulesPlugin.js | 50 +- .../webpack/lib/optimize/UglifyJsPlugin.js | 229 +----- 12 files changed, 1321 insertions(+), 451 deletions(-) create mode 100644 node_modules/webpack/lib/optimize/ConcatenatedModule.js create mode 100644 node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js (limited to 'node_modules/webpack/lib/optimize') diff --git a/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js index 826a6baa9..dc14ac300 100644 --- a/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js +++ b/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js @@ -23,7 +23,7 @@ class AggressiveMergingPlugin { return a + b; }, 0); } - compiler.plugin("compilation", (compilation) => { + compiler.plugin("this-compilation", (compilation) => { compilation.plugin("optimize-chunks-advanced", (chunks) => { let combinations = []; chunks.forEach((a, idx) => { @@ -31,86 +31,80 @@ class AggressiveMergingPlugin { for(let i = 0; i < idx; i++) { const b = chunks[i]; if(b.isInitial()) continue; - combinations.push([b, a]); + combinations.push({ + a, + b, + improvement: undefined + }); } }); combinations.forEach((pair) => { - const a = pair[0].size({ + const a = pair.b.size({ chunkOverhead: 0 }); - const b = pair[1].size({ + const b = pair.a.size({ chunkOverhead: 0 }); - const ab = pair[0].integratedSize(pair[1], { + const ab = pair.b.integratedSize(pair.a, { chunkOverhead: 0 }); - pair.push({ - a: a, - b: b, - ab: ab - }); let newSize; if(ab === false) { - pair.unshift(false); + pair.improvement = false; + return; } else if(options.moveToParents) { const aOnly = ab - b; const bOnly = ab - a; const common = a + b - ab; - newSize = common + getParentsWeight(pair[0]) * aOnly + getParentsWeight(pair[1]) * bOnly; - pair.push({ - aOnly: aOnly, - bOnly: bOnly, - common: common, - newSize: newSize - }); + newSize = common + getParentsWeight(pair.b) * aOnly + getParentsWeight(pair.a) * bOnly; } else { newSize = ab; } - pair.unshift((a + b) / newSize); + pair.improvement = (a + b) / newSize; }); combinations = combinations.filter((pair) => { - return pair[0] !== false; + return pair.improvement !== false; }); combinations.sort((a, b) => { - return b[0] - a[0]; + return b.improvement - a.improvement; }); const pair = combinations[0]; if(!pair) return; - if(pair[0] < minSizeReduce) return; + if(pair.improvement < minSizeReduce) return; if(options.moveToParents) { - const commonModules = pair[1].modules.filter((m) => { - return pair[2].modules.indexOf(m) >= 0; + const commonModules = pair.b.modules.filter((m) => { + return pair.a.modules.indexOf(m) >= 0; }); - const aOnlyModules = pair[1].modules.filter((m) => { + const aOnlyModules = pair.b.modules.filter((m) => { return commonModules.indexOf(m) < 0; }); - const bOnlyModules = pair[2].modules.filter((m) => { + const bOnlyModules = pair.a.modules.filter((m) => { return commonModules.indexOf(m) < 0; }); aOnlyModules.forEach((m) => { - pair[1].removeModule(m); - m.removeChunk(pair[1]); - pair[1].parents.forEach((c) => { + pair.b.removeModule(m); + m.removeChunk(pair.b); + pair.b.parents.forEach((c) => { c.addModule(m); m.addChunk(c); }); }); bOnlyModules.forEach((m) => { - pair[2].removeModule(m); - m.removeChunk(pair[2]); - pair[2].parents.forEach((c) => { + pair.a.removeModule(m); + m.removeChunk(pair.a); + pair.a.parents.forEach((c) => { c.addModule(m); m.addChunk(c); }); }); } - if(pair[1].integrate(pair[2], "aggressive-merge")) { - chunks.splice(chunks.indexOf(pair[2]), 1); + if(pair.b.integrate(pair.a, "aggressive-merge")) { + chunks.splice(chunks.indexOf(pair.a), 1); return true; } }); diff --git a/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js index e05b3eb4c..b6f566a1c 100644 --- a/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js +++ b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js @@ -6,18 +6,6 @@ const identifierUtils = require("../util/identifier"); -function toIndexOf(list) { - return function(item) { - return list.indexOf(item); - }; -} - -function toChunkModuleIndices(modules) { - return function(idx) { - return modules[idx]; - }; -} - function moveModuleBetween(oldChunk, newChunk) { return function(module) { oldChunk.moveModule(module, newChunk); @@ -49,8 +37,15 @@ class AggressiveSplittingPlugin { if(typeof this.options.entryChunkMultiplicator !== "number") this.options.entryChunkMultiplicator = 1; } apply(compiler) { - compiler.plugin("compilation", (compilation) => { + compiler.plugin("this-compilation", (compilation) => { compilation.plugin("optimize-chunks-advanced", (chunks) => { + // Precompute stuff + const nameToModuleMap = new Map(); + compilation.modules.forEach(m => { + const name = identifierUtils.makePathsRelative(compiler.context, m.identifier(), compilation.cache); + nameToModuleMap.set(name, m); + }); + const savedSplits = compilation.records && compilation.records.aggressiveSplits || []; const usedSplits = compilation._aggressiveSplittingSplits ? savedSplits.concat(compilation._aggressiveSplittingSplits) : savedSplits; @@ -60,50 +55,58 @@ class AggressiveSplittingPlugin { // 1. try to restore to recorded splitting for(let j = 0; j < usedSplits.length; j++) { const splitData = usedSplits[j]; - for(let i = 0; i < chunks.length; i++) { - const chunk = chunks[i]; - const chunkModuleNames = chunk.modules.map(m => identifierUtils.makePathsRelative(compiler.context, m.identifier())); + const selectedModules = splitData.modules.map(name => nameToModuleMap.get(name)); - if(chunkModuleNames.length < splitData.modules.length) - continue; - const moduleIndicies = splitData.modules.map(toIndexOf(chunkModuleNames)); - const hasAllModules = moduleIndicies.every((idx) => { - return idx >= 0; - }); - if(hasAllModules) { - if(chunkModuleNames.length > splitData.modules.length) { - const selectedModules = moduleIndicies.map(toChunkModuleIndices(chunk.modules)); - const newChunk = compilation.addChunk(); - selectedModules.forEach(moveModuleBetween(chunk, newChunk)); - chunk.split(newChunk); - chunk.name = null; - newChunk._fromAggressiveSplitting = true; - if(j < savedSplits.length) - newChunk._fromAggressiveSplittingIndex = j; - if(splitData.id !== null && splitData.id !== undefined) { - newChunk.id = splitData.id; - } - newChunk.origins = chunk.origins.map(copyWithReason); - chunk.origins = chunk.origins.map(copyWithReason); - return true; - } else { - if(j < savedSplits.length) - chunk._fromAggressiveSplittingIndex = j; - chunk.name = null; - if(splitData.id !== null && splitData.id !== undefined) { - chunk.id = splitData.id; + // Does the modules exist at all? + if(selectedModules.every(Boolean)) { + + // Find all chunks containing all modules in the split + for(let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + + // Cheap check if chunk is suitable at all + if(chunk.getNumberOfModules() < splitData.modules.length) + continue; + + // Check if all modules are in the chunk + if(selectedModules.every(m => chunk.containsModule(m))) { + + // Is chunk identical to the split or do we need to split it? + if(chunk.getNumberOfModules() > splitData.modules.length) { + // split the chunk into two parts + const newChunk = compilation.addChunk(); + selectedModules.forEach(moveModuleBetween(chunk, newChunk)); + chunk.split(newChunk); + chunk.name = null; + newChunk._fromAggressiveSplitting = true; + if(j < savedSplits.length) + newChunk._fromAggressiveSplittingIndex = j; + if(splitData.id !== null && splitData.id !== undefined) { + newChunk.id = splitData.id; + } + newChunk.origins = chunk.origins.map(copyWithReason); + chunk.origins = chunk.origins.map(copyWithReason); + return true; + } else { // chunk is identical to the split + if(j < savedSplits.length) + chunk._fromAggressiveSplittingIndex = j; + chunk.name = null; + if(splitData.id !== null && splitData.id !== undefined) { + chunk.id = splitData.id; + } } } } } } + // 2. for any other chunk which isn't splitted yet, split it for(let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; const size = chunk.size(this.options); - if(size > maxSize && chunk.modules.length > 1) { + if(size > maxSize && chunk.getNumberOfModules() > 1) { const newChunk = compilation.addChunk(); - const modules = chunk.modules + const modules = chunk.getModules() .filter(isNotAEntryModule(chunk.entryModule)) .sort((a, b) => { a = a.identifier(); @@ -131,13 +134,13 @@ class AggressiveSplittingPlugin { break; } } - if(newChunk.modules.length > 0) { + if(newChunk.getNumberOfModules() > 0) { chunk.split(newChunk); chunk.name = null; newChunk.origins = chunk.origins.map(copyWithReason); chunk.origins = chunk.origins.map(copyWithReason); compilation._aggressiveSplittingSplits = (compilation._aggressiveSplittingSplits || []).concat({ - modules: newChunk.modules.map(m => identifierUtils.makePathsRelative(compiler.context, m.identifier())) + modules: newChunk.mapModules(m => identifierUtils.makePathsRelative(compiler.context, m.identifier(), compilation.cache)) }); return true; } else { @@ -154,7 +157,7 @@ class AggressiveSplittingPlugin { if(chunk.hasEntryModule()) return; const size = chunk.size(this.options); const incorrectSize = size < minSize; - const modules = chunk.modules.map(m => identifierUtils.makePathsRelative(compiler.context, m.identifier())); + const modules = chunk.mapModules(m => identifierUtils.makePathsRelative(compiler.context, m.identifier(), compilation.cache)); if(typeof chunk._fromAggressiveSplittingIndex === "undefined") { if(incorrectSize) return; chunk.recorded = true; diff --git a/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js b/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js index 8166fc315..262014dc5 100644 --- a/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js +++ b/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js @@ -11,9 +11,7 @@ class ChunkModuleIdRangePlugin { const options = this.options; compiler.plugin("compilation", (compilation) => { compilation.plugin("module-ids", (modules) => { - const chunk = this.chunks.filter((chunk) => { - return chunk.name === options.name; - })[0]; + const chunk = this.chunks.find((chunk) => chunk.name === options.name); if(!chunk) throw new Error("ChunkModuleIdRangePlugin: Chunk with name '" + options.name + "' was not found"); let currentId = options.start; let chunkModules; diff --git a/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js b/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js index 3ef414198..465b7ff7a 100644 --- a/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js +++ b/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js @@ -60,8 +60,8 @@ The available options are: * that webpack will take care of loading this file. */ if(options.async && options.filename) { - throw new Error(`You can not specify a filename if you use the \"async\" option. -You can however specify the name of the async chunk by passing the desired string as the \"async\" option.`); + throw new Error(`You can not specify a filename if you use the "async" option. +You can however specify the name of the async chunk by passing the desired string as the "async" option.`); } /** @@ -115,7 +115,18 @@ You can however specify the name of the async chunk by passing the desired strin // override the "commonChunk" with the newly created async one and use it as commonChunk from now on let asyncChunk; if(this.async) { - asyncChunk = this.createAsyncChunk(compilation, this.async, targetChunk); + // If async chunk is one of the affected chunks, just use it + asyncChunk = affectedChunks.filter(c => c.name === this.async)[0]; + // Elsewise create a new one + if(!asyncChunk) { + asyncChunk = this.createAsyncChunk( + compilation, + targetChunks.length <= 1 || typeof this.async !== "string" ? this.async : + targetChunk.name ? `${this.async}-${targetChunk.name}` : + true, + targetChunk + ); + } targetChunk = asyncChunk; } @@ -190,7 +201,7 @@ You can however specify the name of the async chunk by passing the desired strin // we dont have named chunks specified, so we just take all of them if(asyncOrNoSelectedChunk) { - return allChunks.filter(chunk => !chunk.isInitial()); + return allChunks; } /** @@ -218,8 +229,15 @@ Take a look at the "name"/"names" or async/children option.`); } return targetChunk.chunks.filter((chunk) => { + // we only are interested in on-demand chunks + if(chunk.isInitial()) + return false; + // we can only move modules from this chunk if the "commonChunk" is the only parent - return asyncOption || chunk.parents.length === 1; + if(!asyncOption) + return chunk.parents.length === 1; + + return true; }); } @@ -275,7 +293,7 @@ Take a look at the "name"/"names" or async/children option.`); // count how many chunks contain a module const commonModulesToCountMap = usedChunks.reduce((map, chunk) => { - for(let module of chunk.modules) { + for(const module of chunk.modulesIterable) { const count = map.has(module) ? map.get(module) : 0; map.set(module, count + 1); } @@ -306,7 +324,7 @@ Take a look at the "name"/"names" or async/children option.`); extractModulesAndReturnAffectedChunks(reallyUsedModules, usedChunks) { return reallyUsedModules.reduce((affectedChunksSet, module) => { - for(let chunk of usedChunks) { + for(const chunk of usedChunks) { // removeChunk returns true if the chunk was contained and succesfully removed // false if the module did not have a connection to the chunk in question if(module.removeChunk(chunk)) { @@ -318,29 +336,32 @@ Take a look at the "name"/"names" or async/children option.`); } addExtractedModulesToTargetChunk(chunk, modules) { - for(let module of modules) { + for(const module of modules) { chunk.addModule(module); module.addChunk(chunk); } } makeTargetChunkParentOfAffectedChunks(usedChunks, commonChunk) { - for(let chunk of usedChunks) { + for(const chunk of usedChunks) { // set commonChunk as new sole parent chunk.parents = [commonChunk]; // add chunk to commonChunk commonChunk.addChunk(chunk); - for(let entrypoint of chunk.entrypoints) { + for(const entrypoint of chunk.entrypoints) { entrypoint.insertChunk(commonChunk, chunk); } } } moveExtractedChunkBlocksToTargetChunk(chunks, targetChunk) { - for(let chunk of chunks) { - for(let block of chunk.blocks) { - block.chunks.unshift(targetChunk); + for(const chunk of chunks) { + if(chunk === targetChunk) continue; + for(const block of chunk.blocks) { + if(block.chunks.indexOf(targetChunk) === -1) { + block.chunks.unshift(targetChunk); + } targetChunk.addBlock(block); } } @@ -348,8 +369,8 @@ Take a look at the "name"/"names" or async/children option.`); extractOriginsOfChunksWithExtractedModules(chunks) { const origins = []; - for(let chunk of chunks) { - for(let origin of chunk.origins) { + for(const chunk of chunks) { + for(const origin of chunk.origins) { const newOrigin = Object.create(origin); newOrigin.reasons = (origin.reasons || []).concat("async commons"); origins.push(newOrigin); diff --git a/node_modules/webpack/lib/optimize/ConcatenatedModule.js b/node_modules/webpack/lib/optimize/ConcatenatedModule.js new file mode 100644 index 000000000..6cb503f0d --- /dev/null +++ b/node_modules/webpack/lib/optimize/ConcatenatedModule.js @@ -0,0 +1,816 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const Module = require("../Module"); +const Template = require("../Template"); +const Parser = require("../Parser"); +const acorn = require("acorn"); +const escope = require("escope"); +const ReplaceSource = require("webpack-sources/lib/ReplaceSource"); +const ConcatSource = require("webpack-sources/lib/ConcatSource"); +const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); +const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); +const HarmonyExportSpecifierDependency = require("../dependencies/HarmonyExportSpecifierDependency"); +const HarmonyExportExpressionDependency = require("../dependencies/HarmonyExportExpressionDependency"); +const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); +const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); +const HarmonyModulesHelpers = require("../dependencies/HarmonyModulesHelpers"); + +function ensureNsObjSource(info, moduleToInfoMap, requestShortener) { + if(!info.hasNamespaceObject) { + info.hasNamespaceObject = true; + const name = info.exportMap.get(true); + const nsObj = [`var ${name} = {};`]; + for(const exportName of info.module.providedExports) { + const finalName = getFinalName(info, exportName, moduleToInfoMap, requestShortener, false); + nsObj.push(`__webpack_require__.d(${name}, ${JSON.stringify(exportName)}, function() { return ${finalName}; });`); + } + info.namespaceObjectSource = nsObj.join("\n") + "\n"; + } +} + +function getExternalImport(importedModule, info, exportName, asCall) { + if(exportName === true) return info.name; + const used = importedModule.isUsed(exportName); + if(!used) return "/* unused reexport */undefined"; + if(info.interop && exportName === "default") { + return asCall ? `${info.interopName}()` : `${info.interopName}.a`; + } + // TODO use Template.toNormalComment when merging with pure-module + const comment = used !== exportName ? ` /* ${exportName} */` : ""; + const reference = `${info.name}[${JSON.stringify(used)}${comment}]`; + if(asCall) + return `Object(${reference})`; + return reference; +} + +function getFinalName(info, exportName, moduleToInfoMap, requestShortener, asCall) { + switch(info.type) { + case "concatenated": + { + const directExport = info.exportMap.get(exportName); + if(directExport) { + if(exportName === true) + ensureNsObjSource(info, moduleToInfoMap, requestShortener); + const name = info.internalNames.get(directExport); + if(!name) + throw new Error(`The export "${directExport}" in "${info.module.readableIdentifier(requestShortener)}" has no internal name`); + return name; + } + const reexport = info.reexportMap.get(exportName); + if(reexport) { + const refInfo = moduleToInfoMap.get(reexport.module); + if(refInfo) { + // module is in the concatenation + return getFinalName(refInfo, reexport.exportName, moduleToInfoMap, requestShortener, asCall); + } + } + const problem = `Cannot get final name for export "${exportName}" in "${info.module.readableIdentifier(requestShortener)}"` + + ` (known exports: ${Array.from(info.exportMap.keys()).filter(name => name !== true).join(" ")}, ` + + `known reexports: ${Array.from(info.reexportMap.keys()).join(" ")})`; + // TODO use Template.toNormalComment when merging with pure-module + return `/* ${problem} */ undefined`; + } + case "external": + { + const importedModule = info.module; + return getExternalImport(importedModule, info, exportName, asCall); + } + } +} + +function getSymbolsFromScope(s, untilScope) { + const allUsedNames = new Set(); + let scope = s; + while(scope) { + if(untilScope === scope) break; + scope.variables.forEach(variable => allUsedNames.add(variable.name)); + scope = scope.upper; + } + return allUsedNames; +} + +function getAllReferences(variable) { + let set = variable.references; + // Look for inner scope variables too (like in class Foo { t() { Foo } }) + const identifiers = new Set(variable.identifiers); + for(const scope of variable.scope.childScopes) { + for(const innerVar of scope.variables) { + if(innerVar.identifiers.some(id => identifiers.has(id))) { + set = set.concat(innerVar.references); + break; + } + } + } + return set; +} + +function reduceSet(a, b) { + for(const item of b) + a.add(item); + return a; +} + +function getPathInAst(ast, node) { + if(ast === node) { + return []; + } + const nr = node.range; + var i; + if(Array.isArray(ast)) { + for(i = 0; i < ast.length; i++) { + const enterResult = enterNode(ast[i]); + if(typeof enterResult !== "undefined") + return enterResult; + } + } else if(ast && typeof ast === "object") { + const keys = Object.keys(ast); + for(i = 0; i < keys.length; i++) { + const value = ast[keys[i]]; + if(Array.isArray(value)) { + const pathResult = getPathInAst(value, node); + if(typeof pathResult !== "undefined") + return pathResult; + } else if(value && typeof value === "object") { + const enterResult = enterNode(value); + if(typeof enterResult !== "undefined") + return enterResult; + } + } + } + + function enterNode(n) { + const r = n.range; + if(r) { + if(r[0] <= nr[0] && r[1] >= nr[1]) { + const path = getPathInAst(n, node); + if(path) { + path.push(n); + return path; + } + } + } + return undefined; + } +} + +class ConcatenatedModule extends Module { + constructor(rootModule, modules) { + super(); + super.setChunks(rootModule._chunks); + this.rootModule = rootModule; + this.usedExports = rootModule.usedExports; + this.providedExports = rootModule.providedExports; + this.optimizationBailout = rootModule.optimizationBailout; + this.used = rootModule.used; + this.index = rootModule.index; + this.index2 = rootModule.index2; + this.depth = rootModule.depth; + this.built = modules.some(m => m.built); + this.cacheable = modules.every(m => m.cacheable); + const modulesSet = new Set(modules); + this.reasons = rootModule.reasons.filter(reason => !modulesSet.has(reason.module)); + this.meta = rootModule.meta; + this.moduleArgument = rootModule.moduleArgument; + this.exportsArgument = rootModule.exportsArgument; + this.strict = true; + this._numberOfConcatenatedModules = modules.length; + + this.dependencies = []; + this.dependenciesWarnings = []; + this.dependenciesErrors = []; + this.fileDependencies = []; + this.contextDependencies = []; + this.warnings = []; + this.errors = []; + this.assets = {}; + this._orderedConcatenationList = this._createOrderedConcatenationList(rootModule, modulesSet); + for(const info of this._orderedConcatenationList) { + if(info.type === "concatenated") { + const m = info.module; + + // populate dependencies + m.dependencies.filter(dep => !modulesSet.has(dep.module)) + .forEach(d => this.dependencies.push(d)); + // populate dep warning + m.dependenciesWarnings.forEach(depWarning => this.dependenciesWarnings.push(depWarning)); + // populate dep errors + m.dependenciesErrors.forEach(depError => this.dependenciesErrors.push(depError)); + // populate file dependencies + if(m.fileDependencies) m.fileDependencies.forEach(file => this.fileDependencies.push(file)); + // populate context dependencies + if(m.contextDependencies) m.contextDependencies.forEach(context => this.contextDependencies.push(context)); + // populate warnings + m.warnings.forEach(warning => this.warnings.push(warning)); + // populate errors + m.errors.forEach(error => this.errors.push(error)); + + Object.assign(this.assets, m.assets); + } + } + } + + get modules() { + return this._orderedConcatenationList + .filter(info => info.type === "concatenated") + .map(info => info.module); + } + + identifier() { + return this._orderedConcatenationList.map(info => { + switch(info.type) { + case "concatenated": + return info.module.identifier(); + } + }).filter(Boolean).join(" "); + } + + readableIdentifier(requestShortener) { + return this.rootModule.readableIdentifier(requestShortener) + ` + ${this._numberOfConcatenatedModules - 1} modules`; + } + + libIdent(options) { + return this.rootModule.libIdent(options); + } + + nameForCondition() { + return this.rootModule.nameForCondition(); + } + + build(options, compilation, resolver, fs, callback) { + throw new Error("Cannot build this module. It should be already built."); + } + + size() { + // Guess size from embedded modules + return this._orderedConcatenationList.reduce((sum, info) => { + switch(info.type) { + case "concatenated": + return sum + info.module.size(); + case "external": + return sum + 5; + } + return sum; + }, 0); + } + + _createOrderedConcatenationList(rootModule, modulesSet) { + const list = []; + const set = new Set(); + + function getConcatenatedImports(module) { + // TODO need changes when merging with the pure-module branch + const allDeps = module.dependencies + .filter(dep => dep instanceof HarmonyImportDependency && dep.module); + + return allDeps.map(dep => () => dep.module); + } + + function enterModule(getModule) { + const module = getModule(); + if(set.has(module)) return; + set.add(module); + if(modulesSet.has(module)) { + const imports = getConcatenatedImports(module); + imports.forEach(enterModule); + list.push({ + type: "concatenated", + module + }); + } else { + list.push({ + type: "external", + get module() { + // We need to use a getter here, because the module in the dependency + // could be replaced by some other process (i. e. also replaced with a + // concatenated module) + return getModule(); + } + }); + } + } + + enterModule(() => rootModule); + + return list; + } + + source(dependencyTemplates, outputOptions, requestShortener) { + // Metainfo for each module + const modulesWithInfo = this._orderedConcatenationList.map((info, idx) => { + switch(info.type) { + case "concatenated": + { + const exportMap = new Map(); + const reexportMap = new Map(); + info.module.dependencies.forEach(dep => { + if(dep instanceof HarmonyExportSpecifierDependency) { + exportMap.set(dep.name, dep.id); + } else if(dep instanceof HarmonyExportExpressionDependency) { + exportMap.set("default", "__WEBPACK_MODULE_DEFAULT_EXPORT__"); + } else if(dep instanceof HarmonyExportImportedSpecifierDependency) { + const exportName = dep.name; + const importName = dep.id; + const importedModule = dep.importDependency.module; + if(exportName && importName) { + reexportMap.set(exportName, { + module: importedModule, + exportName: importName, + dependency: dep + }); + } else if(exportName) { + reexportMap.set(exportName, { + module: importedModule, + exportName: true, + dependency: dep + }); + } else { + var activeExports = new Set(HarmonyModulesHelpers.getActiveExports(dep.originModule, dep)); + importedModule.providedExports.forEach(name => { + if(activeExports.has(name) || name === "default") + return; + reexportMap.set(name, { + module: importedModule, + exportName: name, + dependency: dep + }); + }); + } + } + }); + return { + type: "concatenated", + module: info.module, + index: idx, + ast: undefined, + source: undefined, + globalScope: undefined, + moduleScope: undefined, + internalNames: new Map(), + exportMap: exportMap, + reexportMap: reexportMap, + needCompatibilityFlag: false, + hasNamespaceObject: false, + namespaceObjectSource: null + }; + } + case "external": + return { + type: "external", + module: info.module, + index: idx, + name: undefined, + interopName: undefined, + interop: undefined + }; + default: + throw new Error(`Unsupported concatenation entry type ${info.type}`); + } + }); + + // Create mapping from module to info + const moduleToInfoMap = new Map(); + modulesWithInfo.forEach(m => moduleToInfoMap.set(m.module, m)); + + // Configure template decorators for dependencies + const innerDependencyTemplates = new Map(dependencyTemplates); + + innerDependencyTemplates.set(HarmonyImportSpecifierDependency, new HarmonyImportSpecifierDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyImportSpecifierDependency), + moduleToInfoMap + )); + innerDependencyTemplates.set(HarmonyImportDependency, new HarmonyImportDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyImportDependency), + moduleToInfoMap + )); + innerDependencyTemplates.set(HarmonyExportSpecifierDependency, new HarmonyExportSpecifierDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyExportSpecifierDependency), + this.rootModule + )); + innerDependencyTemplates.set(HarmonyExportExpressionDependency, new HarmonyExportExpressionDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyExportExpressionDependency), + this.rootModule, + moduleToInfoMap + )); + innerDependencyTemplates.set(HarmonyExportImportedSpecifierDependency, new HarmonyExportImportedSpecifierDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyExportImportedSpecifierDependency), + this.rootModule, + moduleToInfoMap + )); + innerDependencyTemplates.set(HarmonyCompatibilityDependency, new HarmonyCompatibilityDependencyConcatenatedTemplate( + dependencyTemplates.get(HarmonyCompatibilityDependency), + this.rootModule, + moduleToInfoMap + )); + innerDependencyTemplates.set("hash", innerDependencyTemplates.get("hash") + this.rootModule.identifier()); + + // Generate source code and analyse scopes + // Prepare a ReplaceSource for the final source + modulesWithInfo.forEach(info => { + if(info.type === "concatenated") { + const m = info.module; + const source = m.source(innerDependencyTemplates, outputOptions, requestShortener); + const code = source.source(); + let ast; + try { + ast = acorn.parse(code, { + ranges: true, + locations: true, + ecmaVersion: Parser.ECMA_VERSION, + sourceType: "module" + }); + } catch(err) { + if(err.loc && typeof err.loc === "object" && typeof err.loc.line === "number") { + const lineNumber = err.loc.line; + const lines = code.split("\n"); + err.message += "\n| " + lines.slice(Math.max(0, lineNumber - 3), lineNumber + 2).join("\n| "); + } + throw err; + } + const scopeManager = escope.analyze(ast, { + ecmaVersion: 6, + sourceType: "module", + optimistic: true, + ignoreEval: true, + impliedStrict: true + }); + const globalScope = scopeManager.acquire(ast); + const moduleScope = globalScope.childScopes[0]; + const resultSource = new ReplaceSource(source); + info.ast = ast; + info.source = resultSource; + info.globalScope = globalScope; + info.moduleScope = moduleScope; + } + }); + + // List of all used names to avoid conflicts + const allUsedNames = new Set([ + "__WEBPACK_MODULE_DEFAULT_EXPORT__", // avoid using this internal name + + "abstract", "arguments", "await", "boolean", "break", "byte", "case", "catch", "char", "class", + "const", "continue", "debugger", "default", "delete", "do", "double", "else", "enum", "eval", + "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if", + "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", + "null", "package", "private", "protected", "public", "return", "short", "static", "super", + "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof", + "var", "void", "volatile", "while", "with", "yield", + + "module", "__dirname", "__filename", "exports", + + "Array", "Date", "eval", "function", "hasOwnProperty", "Infinity", "isFinite", "isNaN", + "isPrototypeOf", "length", "Math", "NaN", "name", "Number", "Object", "prototype", "String", + "toString", "undefined", "valueOf", + + "alert", "all", "anchor", "anchors", "area", "assign", "blur", "button", "checkbox", + "clearInterval", "clearTimeout", "clientInformation", "close", "closed", "confirm", "constructor", + "crypto", "decodeURI", "decodeURIComponent", "defaultStatus", "document", "element", "elements", + "embed", "embeds", "encodeURI", "encodeURIComponent", "escape", "event", "fileUpload", "focus", + "form", "forms", "frame", "innerHeight", "innerWidth", "layer", "layers", "link", "location", + "mimeTypes", "navigate", "navigator", "frames", "frameRate", "hidden", "history", "image", + "images", "offscreenBuffering", "open", "opener", "option", "outerHeight", "outerWidth", + "packages", "pageXOffset", "pageYOffset", "parent", "parseFloat", "parseInt", "password", "pkcs11", + "plugin", "prompt", "propertyIsEnum", "radio", "reset", "screenX", "screenY", "scroll", "secure", + "select", "self", "setInterval", "setTimeout", "status", "submit", "taint", "text", "textarea", + "top", "unescape", "untaint", "window", + + "onblur", "onclick", "onerror", "onfocus", "onkeydown", "onkeypress", "onkeyup", "onmouseover", + "onload", "onmouseup", "onmousedown", "onsubmit" + ]); + + // get all global names + modulesWithInfo.forEach(info => { + if(info.globalScope) { + info.globalScope.through.forEach(reference => { + const name = reference.identifier.name; + if(/^__WEBPACK_MODULE_REFERENCE__\d+_([\da-f]+|ns)(_call)?__$/.test(name)) { + for(const s of getSymbolsFromScope(reference.from, info.moduleScope)) { + allUsedNames.add(s); + } + } else { + allUsedNames.add(name); + } + }); + } + }); + + // generate names for symbols + modulesWithInfo.forEach(info => { + switch(info.type) { + case "concatenated": + { + const namespaceObjectName = this.findNewName("namespaceObject", allUsedNames, null, info.module.readableIdentifier(requestShortener)); + allUsedNames.add(namespaceObjectName); + info.internalNames.set(namespaceObjectName, namespaceObjectName); + info.exportMap.set(true, namespaceObjectName); + info.moduleScope.variables.forEach(variable => { + const name = variable.name; + if(allUsedNames.has(name)) { + const references = getAllReferences(variable); + const symbolsInReferences = references.map(ref => getSymbolsFromScope(ref.from, info.moduleScope)).reduce(reduceSet, new Set()); + const newName = this.findNewName(name, allUsedNames, symbolsInReferences, info.module.readableIdentifier(requestShortener)); + allUsedNames.add(newName); + info.internalNames.set(name, newName); + const source = info.source; + const allIdentifiers = new Set(references.map(r => r.identifier).concat(variable.identifiers)); + for(const identifier of allIdentifiers) { + const r = identifier.range; + const path = getPathInAst(info.ast, identifier); + if(path && path.length > 1 && path[1].type === "Property" && path[1].shorthand) { + source.insert(r[1], `: ${newName}`); + } else { + source.replace(r[0], r[1] - 1, newName); + } + } + } else { + allUsedNames.add(name); + info.internalNames.set(name, name); + } + }); + break; + } + case "external": + { + info.interop = info.module.meta && !info.module.meta.harmonyModule; + const externalName = this.findNewName("", allUsedNames, null, info.module.readableIdentifier(requestShortener)); + allUsedNames.add(externalName); + info.name = externalName; + if(info.interop) { + const externalNameInterop = this.findNewName("default", allUsedNames, null, info.module.readableIdentifier(requestShortener)); + allUsedNames.add(externalNameInterop); + info.interopName = externalNameInterop; + } + break; + } + } + }); + + // Find and replace referenced to modules + modulesWithInfo.forEach(info => { + if(info.type === "concatenated") { + info.globalScope.through.forEach(reference => { + const name = reference.identifier.name; + const match = /^__WEBPACK_MODULE_REFERENCE__(\d+)_([\da-f]+|ns)(_call)?__$/.exec(name); + if(match) { + const referencedModule = modulesWithInfo[+match[1]]; + let exportName; + if(match[2] === "ns") { + exportName = true; + } else { + const exportData = match[2]; + exportName = new Buffer(exportData, "hex").toString("utf-8"); // eslint-disable-line node/no-deprecated-api + } + const asCall = !!match[3]; + const finalName = getFinalName(referencedModule, exportName, moduleToInfoMap, requestShortener, asCall); + const r = reference.identifier.range; + const source = info.source; + source.replace(r[0], r[1] - 1, finalName); + } + }); + } + }); + + const result = new ConcatSource(); + + // add harmony compatibility flag (must be first because of possible circular dependencies) + if(moduleToInfoMap.get(this.rootModule).needCompatibilityFlag) { + result.add(`Object.defineProperty(${this.exportsArgument || "exports"}, "__esModule", { value: true });\n`); + } + + // define required namespace objects (must be before evaluation modules) + modulesWithInfo.forEach(info => { + if(info.namespaceObjectSource) { + result.add(info.namespaceObjectSource); + } + }); + + // evaluate modules in order + modulesWithInfo.forEach(info => { + switch(info.type) { + case "concatenated": + result.add(`\n// CONCATENATED MODULE: ${info.module.readableIdentifier(requestShortener)}\n`); + result.add(info.source); + break; + case "external": + result.add(`\n// EXTERNAL MODULE: ${info.module.readableIdentifier(requestShortener)}\n`); + result.add(`var ${info.name} = __webpack_require__(${JSON.stringify(info.module.id)});\n`); + if(info.interop) { + result.add(`var ${info.interopName} = /*#__PURE__*/__webpack_require__.n(${info.name});\n`); + } + break; + default: + throw new Error(`Unsupported concatenation entry type ${info.type}`); + } + }); + + return result; + } + + findNewName(oldName, usedNamed1, usedNamed2, extraInfo) { + let name = oldName; + + if(name === "__WEBPACK_MODULE_DEFAULT_EXPORT__") + name = ""; + + // Remove uncool stuff + extraInfo = extraInfo.replace(/\.+\/|(\/index)?\.([a-zA-Z0-9]{1,4})($|\s|\?)|\s*\+\s*\d+\s*modules/g, ""); + + const splittedInfo = extraInfo.split("/"); + while(splittedInfo.length) { + name = splittedInfo.pop() + (name ? "_" + name : ""); + const nameIdent = Template.toIdentifier(name); + if(!usedNamed1.has(nameIdent) && (!usedNamed2 || !usedNamed2.has(nameIdent))) return nameIdent; + } + + let i = 0; + let nameWithNumber = Template.toIdentifier(`${name}_${i}`); + while(usedNamed1.has(nameWithNumber) || (usedNamed2 && usedNamed2.has(nameWithNumber))) { + i++; + nameWithNumber = Template.toIdentifier(`${name}_${i}`); + } + return nameWithNumber; + } + + updateHash(hash) { + for(const info of this._orderedConcatenationList) { + switch(info.type) { + case "concatenated": + info.module.updateHash(hash); + break; + case "external": + hash.update(`${info.module.id}`); + break; + } + } + super.updateHash(hash); + } + +} + +class HarmonyImportSpecifierDependencyConcatenatedTemplate { + constructor(originalTemplate, modulesMap) { + this.originalTemplate = originalTemplate; + this.modulesMap = modulesMap; + } + + apply(dep, source, outputOptions, requestShortener, dependencyTemplates) { + const module = dep.importDependency.module; + const info = this.modulesMap.get(module); + if(!info) { + this.originalTemplate.apply(dep, source, outputOptions, requestShortener, dependencyTemplates); + return; + } + let content; + if(dep.id === null) { + content = `__WEBPACK_MODULE_REFERENCE__${info.index}_ns__`; + } else if(dep.namespaceObjectAsContext) { + content = `__WEBPACK_MODULE_REFERENCE__${info.index}_ns__[${JSON.stringify(dep.id)}]`; + } else { + const exportData = new Buffer(dep.id, "utf-8").toString("hex"); // eslint-disable-line node/no-deprecated-api + content = `__WEBPACK_MODULE_REFERENCE__${info.index}_${exportData}${dep.call ? "_call" : ""}__`; + } + if(dep.shorthand) { + content = dep.name + ": " + content; + } + source.replace(dep.range[0], dep.range[1] - 1, content); + } +} + +class HarmonyImportDependencyConcatenatedTemplate { + constructor(originalTemplate, modulesMap) { + this.originalTemplate = originalTemplate; + this.modulesMap = modulesMap; + } + + apply(dep, source, outputOptions, requestShortener, dependencyTemplates) { + const module = dep.module; + const info = this.modulesMap.get(module); + if(!info) { + this.originalTemplate.apply(dep, source, outputOptions, requestShortener, dependencyTemplates); + return; + } + source.replace(dep.range[0], dep.range[1] - 1, ""); + } +} + +class HarmonyExportSpecifierDependencyConcatenatedTemplate { + constructor(originalTemplate, rootModule) { + this.originalTemplate = originalTemplate; + this.rootModule = rootModule; + } + + apply(dep, source, outputOptions, requestShortener, dependencyTemplates) { + if(dep.originModule === this.rootModule) { + this.originalTemplate.apply(dep, source, outputOptions, requestShortener, dependencyTemplates); + } + } +} + +class HarmonyExportExpressionDependencyConcatenatedTemplate { + constructor(originalTemplate, rootModule) { + this.originalTemplate = originalTemplate; + this.rootModule = rootModule; + } + + apply(dep, source, outputOptions, requestShortener, dependencyTemplates) { + let content = "/* harmony default export */ var __WEBPACK_MODULE_DEFAULT_EXPORT__ = "; + if(dep.originModule === this.rootModule) { + const used = dep.originModule.isUsed("default"); + const exportsName = dep.originModule.exportsArgument || "exports"; + if(used) content += `${exportsName}[${JSON.stringify(used)}] = `; + } + + if(dep.range) { + source.replace(dep.rangeStatement[0], dep.range[0] - 1, content + "("); + source.replace(dep.range[1], dep.rangeStatement[1] - 1, ");"); + return; + } + + source.replace(dep.rangeStatement[0], dep.rangeStatement[1] - 1, content); + } +} + +class HarmonyExportImportedSpecifierDependencyConcatenatedTemplate { + constructor(originalTemplate, rootModule, modulesMap) { + this.originalTemplate = originalTemplate; + this.rootModule = rootModule; + this.modulesMap = modulesMap; + } + + getExports(dep) { + const active = HarmonyModulesHelpers.isActive(dep.originModule, dep); + if(!active) return []; + const importModule = dep.importDependency.module; + if(dep.id) { + // export { named } from "module" + return [{ + name: dep.name, + id: dep.id, + module: importModule + }]; + } + if(dep.name) { + // export * as abc from "module" + return [{ + name: dep.name, + id: true, + module: importModule + }]; + } + // export * from "module" + const activeExports = new Set(HarmonyModulesHelpers.getActiveExports(dep.originModule, dep)); + return importModule.providedExports.filter(exp => exp !== "default" && !activeExports.has(exp)).map(exp => { + return { + name: exp, + id: exp, + module: importModule + }; + }); + } + + apply(dep, source, outputOptions, requestShortener, dependencyTemplates) { + if(dep.originModule === this.rootModule) { + if(this.modulesMap.get(dep.importDependency.module)) { + const exportDefs = this.getExports(dep); + exportDefs.forEach(def => { + const info = this.modulesMap.get(def.module); + const used = dep.originModule.isUsed(def.name); + if(!used) { + source.insert(-1, `/* unused concated harmony import ${dep.name} */\n`); + } + let finalName; + if(def.id === true) { + finalName = `__WEBPACK_MODULE_REFERENCE__${info.index}_ns__`; + } else { + const exportData = new Buffer(def.id, "utf-8").toString("hex"); // eslint-disable-line node/no-deprecated-api + finalName = `__WEBPACK_MODULE_REFERENCE__${info.index}_${exportData}__`; + } + const exportsName = this.rootModule.exportsArgument || "exports"; + const content = `/* concated harmony reexport */__webpack_require__.d(${exportsName}, ${JSON.stringify(used)}, function() { return ${finalName}; });\n`; + source.insert(-1, content); + }); + } else { + this.originalTemplate.apply(dep, source, outputOptions, requestShortener, dependencyTemplates); + } + } + } +} + +class HarmonyCompatibilityDependencyConcatenatedTemplate { + constructor(originalTemplate, rootModule, modulesMap) { + this.originalTemplate = originalTemplate; + this.rootModule = rootModule; + this.modulesMap = modulesMap; + } + + apply(dep, source, outputOptions, requestShortener, dependencyTemplates) { + if(dep.originModule === this.rootModule) { + this.modulesMap.get(this.rootModule).needCompatibilityFlag = true; + } + } +} + +module.exports = ConcatenatedModule; diff --git a/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js index 71ee18533..46324c4e9 100644 --- a/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js +++ b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js @@ -8,16 +8,19 @@ class EnsureChunkConditionsPlugin { apply(compiler) { compiler.plugin("compilation", (compilation) => { + const triesMap = new Map(); compilation.plugin(["optimize-chunks-basic", "optimize-extracted-chunks-basic"], (chunks) => { let changed = false; chunks.forEach((chunk) => { - chunk.modules.slice().forEach((module) => { + chunk.forEachModule((module) => { if(!module.chunkCondition) return; if(!module.chunkCondition(chunk)) { - const usedChunks = module._EnsureChunkConditionsPlugin_usedChunks = (module._EnsureChunkConditionsPlugin_usedChunks || []).concat(chunk); + let usedChunks = triesMap.get(module); + if(!usedChunks) triesMap.set(module, usedChunks = new Set()); + usedChunks.add(chunk); const newChunks = []; chunk.parents.forEach((parent) => { - if(usedChunks.indexOf(parent) < 0) { + if(!usedChunks.has(parent)) { parent.addModule(module); newChunks.push(parent); } diff --git a/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js index e8b5a9457..75277b5aa 100644 --- a/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js +++ b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js @@ -17,13 +17,13 @@ class FlagIncludedChunksPlugin { // instead of swapping A and B just bail // as we loop twice the current A will be B and B then A - if(chunkA.modules.length < chunkB.modules.length) return; + if(chunkA.getNumberOfModules() < chunkB.getNumberOfModules()) return; - if(chunkB.modules.length === 0) return; + if(chunkB.getNumberOfModules() === 0) return; // is chunkB in chunkA? - for(let i = 0; i < chunkB.modules.length; i++) { - if(chunkA.modules.indexOf(chunkB.modules[i]) < 0) return; + for(const m of chunkB.modulesIterable) { + if(!chunkA.containsModule(m)) return; } chunkA.ids.push(chunkB.id); }); diff --git a/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js index 90df06b51..7b006fd17 100644 --- a/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js +++ b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js @@ -4,23 +4,18 @@ */ "use strict"; -function getChunkIdentifier(chunk) { - return chunk.modules.map((m) => { - return m.identifier(); - }).sort().join(", "); -} - class MergeDuplicateChunksPlugin { apply(compiler) { compiler.plugin("compilation", (compilation) => { compilation.plugin("optimize-chunks-basic", (chunks) => { - const map = {}; + const map = Object.create(null); chunks.slice().forEach((chunk) => { if(chunk.hasRuntime() || chunk.hasEntryModule()) return; - const ident = getChunkIdentifier(chunk); - if(map[ident]) { - if(map[ident].integrate(chunk, "duplicate")) + const ident = chunk.getModulesIdent(); + const otherChunk = map[ident]; + if(otherChunk) { + if(otherChunk.integrate(chunk, "duplicate")) chunks.splice(chunks.indexOf(chunk), 1); return; } diff --git a/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js b/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js new file mode 100644 index 000000000..9e797c75e --- /dev/null +++ b/node_modules/webpack/lib/optimize/ModuleConcatenationPlugin.js @@ -0,0 +1,307 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); +const ModuleHotAcceptDependency = require("../dependencies/ModuleHotAcceptDependency"); +const ModuleHotDeclineDependency = require("../dependencies/ModuleHotDeclineDependency"); +const ConcatenatedModule = require("./ConcatenatedModule"); +const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); +const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); + +function formatBailoutReason(msg) { + return "ModuleConcatenation bailout: " + msg; +} + +class ModuleConcatenationPlugin { + constructor(options) { + if(typeof options !== "object") options = {}; + this.options = options; + } + + apply(compiler) { + compiler.plugin("compilation", (compilation, params) => { + params.normalModuleFactory.plugin("parser", (parser, parserOptions) => { + parser.plugin("call eval", () => { + parser.state.module.meta.hasEval = true; + }); + }); + const bailoutReasonMap = new Map(); + + function setBailoutReason(module, reason) { + bailoutReasonMap.set(module, reason); + module.optimizationBailout.push(typeof reason === "function" ? (rs) => formatBailoutReason(reason(rs)) : formatBailoutReason(reason)); + } + + function getBailoutReason(module, requestShortener) { + const reason = bailoutReasonMap.get(module); + if(typeof reason === "function") return reason(requestShortener); + return reason; + } + + compilation.plugin("optimize-chunk-modules", (chunks, modules) => { + const relevantModules = []; + const possibleInners = new Set(); + for(const module of modules) { + // Only harmony modules are valid for optimization + if(!module.meta || !module.meta.harmonyModule || !module.dependencies.some(d => d instanceof HarmonyCompatibilityDependency)) { + setBailoutReason(module, "Module is not an ECMAScript module"); + continue; + } + + // Because of variable renaming we can't use modules with eval + if(module.meta && module.meta.hasEval) { + setBailoutReason(module, "Module uses eval()"); + continue; + } + + // Exports must be known (and not dynamic) + if(!Array.isArray(module.providedExports)) { + setBailoutReason(module, "Module exports are unknown"); + continue; + } + + // Using dependency variables is not possible as this wraps the code in a function + if(module.variables.length > 0) { + setBailoutReason(module, `Module uses injected variables (${module.variables.map(v => v.name).join(", ")})`); + continue; + } + + // Hot Module Replacement need it's own module to work correctly + if(module.dependencies.some(dep => dep instanceof ModuleHotAcceptDependency || dep instanceof ModuleHotDeclineDependency)) { + setBailoutReason(module, "Module uses Hot Module Replacement"); + continue; + } + + relevantModules.push(module); + + // Module must not be the entry points + if(module.getChunks().some(chunk => chunk.entryModule === module)) { + setBailoutReason(module, "Module is an entry point"); + continue; + } + + // Module must only be used by Harmony Imports + const nonHarmonyReasons = module.reasons.filter(reason => !(reason.dependency instanceof HarmonyImportDependency)); + if(nonHarmonyReasons.length > 0) { + const importingModules = new Set(nonHarmonyReasons.map(r => r.module)); + const importingModuleTypes = new Map(Array.from(importingModules).map(m => [m, new Set(nonHarmonyReasons.filter(r => r.module === m).map(r => r.dependency.type).sort())])); + setBailoutReason(module, (requestShortener) => { + const names = Array.from(importingModules).map(m => `${m.readableIdentifier(requestShortener)} (referenced with ${Array.from(importingModuleTypes.get(m)).join(", ")})`).sort(); + return `Module is referenced from these modules with unsupported syntax: ${names.join(", ")}`; + }); + continue; + } + + possibleInners.add(module); + } + // sort by depth + // modules with lower depth are more likely suited as roots + // this improves performance, because modules already selected as inner are skipped + relevantModules.sort((a, b) => { + return a.depth - b.depth; + }); + const concatConfigurations = []; + const usedAsInner = new Set(); + for(const currentRoot of relevantModules) { + // when used by another configuration as inner: + // the other configuration is better and we can skip this one + if(usedAsInner.has(currentRoot)) + continue; + + // create a configuration with the root + const currentConfiguration = new ConcatConfiguration(currentRoot); + + // cache failures to add modules + const failureCache = new Map(); + + // try to add all imports + for(const imp of this.getImports(currentRoot)) { + const problem = this.tryToAdd(currentConfiguration, imp, possibleInners, failureCache); + if(problem) { + failureCache.set(imp, problem); + currentConfiguration.addWarning(imp, problem); + } + } + if(!currentConfiguration.isEmpty()) { + concatConfigurations.push(currentConfiguration); + for(const module of currentConfiguration.modules) { + if(module !== currentConfiguration.rootModule) + usedAsInner.add(module); + } + } + } + // HACK: Sort configurations by length and start with the longest one + // to get the biggers groups possible. Used modules are marked with usedModules + // TODO: Allow to reuse existing configuration while trying to add dependencies. + // This would improve performance. O(n^2) -> O(n) + concatConfigurations.sort((a, b) => { + return b.modules.size - a.modules.size; + }); + const usedModules = new Set(); + for(const concatConfiguration of concatConfigurations) { + if(usedModules.has(concatConfiguration.rootModule)) + continue; + const newModule = new ConcatenatedModule(concatConfiguration.rootModule, Array.from(concatConfiguration.modules)); + concatConfiguration.sortWarnings(); + for(const warning of concatConfiguration.warnings) { + newModule.optimizationBailout.push((requestShortener) => { + const reason = getBailoutReason(warning[0], requestShortener); + const reasonWithPrefix = reason ? ` (<- ${reason})` : ""; + if(warning[0] === warning[1]) + return formatBailoutReason(`Cannot concat with ${warning[0].readableIdentifier(requestShortener)}${reasonWithPrefix}`); + else + return formatBailoutReason(`Cannot concat with ${warning[0].readableIdentifier(requestShortener)} because of ${warning[1].readableIdentifier(requestShortener)}${reasonWithPrefix}`); + }); + } + const chunks = concatConfiguration.rootModule.getChunks(); + for(const m of concatConfiguration.modules) { + usedModules.add(m); + chunks.forEach(chunk => chunk.removeModule(m)); + } + chunks.forEach(chunk => { + chunk.addModule(newModule); + if(chunk.entryModule === concatConfiguration.rootModule) + chunk.entryModule = newModule; + }); + compilation.modules.push(newModule); + newModule.reasons.forEach(reason => reason.dependency.module = newModule); + newModule.dependencies.forEach(dep => { + if(dep.module) { + dep.module.reasons.forEach(reason => { + if(reason.dependency === dep) + reason.module = newModule; + }); + } + }); + } + compilation.modules = compilation.modules.filter(m => !usedModules.has(m)); + }); + }); + } + + getImports(module) { + return Array.from(new Set(module.dependencies + + // Only harmony Dependencies + .filter(dep => dep instanceof HarmonyImportDependency && dep.module) + + // Dependencies are simple enough to concat them + .filter(dep => { + return !module.dependencies.some(d => + d instanceof HarmonyExportImportedSpecifierDependency && + d.importDependency === dep && + !d.id && + !Array.isArray(dep.module.providedExports) + ); + }) + + // Take the imported module + .map(dep => dep.module) + )); + } + + tryToAdd(config, module, possibleModules, failureCache) { + const cacheEntry = failureCache.get(module); + if(cacheEntry) { + return cacheEntry; + } + + // Already added? + if(config.has(module)) { + return null; + } + + // Not possible to add? + if(!possibleModules.has(module)) { + failureCache.set(module, module); // cache failures for performance + return module; + } + + // module must be in the same chunks + if(!config.rootModule.hasEqualsChunks(module)) { + failureCache.set(module, module); // cache failures for performance + return module; + } + + // Clone config to make experimental changes + const testConfig = config.clone(); + + // Add the module + testConfig.add(module); + + // Every module which depends on the added module must be in the configuration too. + for(const reason of module.reasons) { + const problem = this.tryToAdd(testConfig, reason.module, possibleModules, failureCache); + if(problem) { + failureCache.set(module, problem); // cache failures for performance + return problem; + } + } + + // Eagerly try to add imports too if possible + for(const imp of this.getImports(module)) { + const problem = this.tryToAdd(testConfig, imp, possibleModules, failureCache); + if(problem) { + config.addWarning(module, problem); + } + } + + // Commit experimental changes + config.set(testConfig); + return null; + } +} + +class ConcatConfiguration { + constructor(rootModule) { + this.rootModule = rootModule; + this.modules = new Set([rootModule]); + this.warnings = new Map(); + } + + add(module) { + this.modules.add(module); + } + + has(module) { + return this.modules.has(module); + } + + isEmpty() { + return this.modules.size === 1; + } + + addWarning(module, problem) { + this.warnings.set(module, problem); + } + + sortWarnings() { + this.warnings = new Map(Array.from(this.warnings).sort((a, b) => { + const ai = a[0].identifier(); + const bi = b[0].identifier(); + if(ai < bi) return -1; + if(ai > bi) return 1; + return 0; + })); + } + + clone() { + const clone = new ConcatConfiguration(this.rootModule); + for(const module of this.modules) + clone.add(module); + for(const pair of this.warnings) + clone.addWarning(pair[0], pair[1]); + return clone; + } + + set(config) { + this.rootModule = config.rootModule; + this.modules = new Set(config.modules); + this.warnings = new Map(config.warnings); + } +} + +module.exports = ModuleConcatenationPlugin; diff --git a/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js b/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js index a6bb30b34..45ec34719 100644 --- a/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js +++ b/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js @@ -15,98 +15,84 @@ class OccurrenceOrderPlugin { const preferEntry = this.preferEntry; compiler.plugin("compilation", (compilation) => { compilation.plugin("optimize-module-order", (modules) => { - function entryChunks(m) { - return m.chunks.map((c) => { - const sum = (c.isInitial() ? 1 : 0) + (c.entryModule === m ? 1 : 0); - return sum; - }).reduce((a, b) => { - return a + b; - }, 0); - } + const occursInInitialChunksMap = new Map(); + const occursInAllChunksMap = new Map(); - function occursInEntry(m) { - if(typeof m.__OccurenceOrderPlugin_occursInEntry === "number") return m.__OccurenceOrderPlugin_occursInEntry; - const result = m.reasons.map((r) => { - if(!r.module) return 0; - return entryChunks(r.module); - }).reduce((a, b) => { - return a + b; - }, 0) + entryChunks(m); - return m.__OccurenceOrderPlugin_occursInEntry = result; - } + const initialChunkChunkMap = new Map(); + const entryCountMap = new Map(); + modules.forEach(m => { + let initial = 0; + let entry = 0; + m.forEachChunk(c => { + if(c.isInitial()) initial++; + if(c.entryModule === m) entry++; + }); + initialChunkChunkMap.set(m, initial); + entryCountMap.set(m, entry); + }); + + const countOccursInEntry = (sum, r) => { + if(!r.module) return sum; + return sum + initialChunkChunkMap.get(r.module); + }; + const countOccurs = (sum, r) => { + if(!r.module) return sum; + return sum + r.module.getNumberOfChunks(); + }; - function occurs(m) { - if(typeof m.__OccurenceOrderPlugin_occurs === "number") return m.__OccurenceOrderPlugin_occurs; - const result = m.reasons.map((r) => { - if(!r.module) return 0; - return r.module.chunks.length; - }).reduce((a, b) => { - return a + b; - }, 0) + m.chunks.length + m.chunks.filter((c) => { - return c.entryModule === m; - }).length; - return m.__OccurenceOrderPlugin_occurs = result; + if(preferEntry) { + modules.forEach(m => { + const result = m.reasons.reduce(countOccursInEntry, 0) + initialChunkChunkMap.get(m) + entryCountMap.get(m); + occursInInitialChunksMap.set(m, result); + }); } + + modules.forEach(m => { + const result = m.reasons.reduce(countOccurs, 0) + m.getNumberOfChunks() + entryCountMap.get(m); + occursInAllChunksMap.set(m, result); + }); + modules.sort((a, b) => { if(preferEntry) { - const aEntryOccurs = occursInEntry(a); - const bEntryOccurs = occursInEntry(b); + const aEntryOccurs = occursInInitialChunksMap.get(a); + const bEntryOccurs = occursInInitialChunksMap.get(b); if(aEntryOccurs > bEntryOccurs) return -1; if(aEntryOccurs < bEntryOccurs) return 1; } - const aOccurs = occurs(a); - const bOccurs = occurs(b); + const aOccurs = occursInAllChunksMap.get(a); + const bOccurs = occursInAllChunksMap.get(b); if(aOccurs > bOccurs) return -1; if(aOccurs < bOccurs) return 1; - if(a.identifier() > b.identifier()) return 1; - if(a.identifier() < b.identifier()) return -1; + if(a.index > b.index) return 1; + if(a.index < b.index) return -1; return 0; }); - // TODO refactor to Map - modules.forEach((m) => { - m.__OccurenceOrderPlugin_occursInEntry = undefined; - m.__OccurenceOrderPlugin_occurs = undefined; - }); }); compilation.plugin("optimize-chunk-order", (chunks) => { - function occursInEntry(c) { - if(typeof c.__OccurenceOrderPlugin_occursInEntry === "number") return c.__OccurenceOrderPlugin_occursInEntry; - const result = c.parents.filter((p) => { - return p.isInitial(); - }).length; - return c.__OccurenceOrderPlugin_occursInEntry = result; - } + const occursInInitialChunksMap = new Map(); + + chunks.forEach(c => { + const result = c.parents.reduce((sum, p) => { + if(p.isInitial()) return sum + 1; + return sum; + }, 0); + return occursInInitialChunksMap.set(c, result); + }); function occurs(c) { return c.blocks.length; } - chunks.forEach((c) => { - c.modules.sort((a, b) => { - if(a.identifier() > b.identifier()) return 1; - if(a.identifier() < b.identifier()) return -1; - return 0; - }); - }); + chunks.sort((a, b) => { - const aEntryOccurs = occursInEntry(a); - const bEntryOccurs = occursInEntry(b); + const aEntryOccurs = occursInInitialChunksMap.get(a); + const bEntryOccurs = occursInInitialChunksMap.get(b); if(aEntryOccurs > bEntryOccurs) return -1; if(aEntryOccurs < bEntryOccurs) return 1; const aOccurs = occurs(a); const bOccurs = occurs(b); if(aOccurs > bOccurs) return -1; if(aOccurs < bOccurs) return 1; - if(a.modules.length > b.modules.length) return -1; - if(a.modules.length < b.modules.length) return 1; - for(let i = 0; i < a.modules.length; i++) { - if(a.modules[i].identifier() > b.modules[i].identifier()) return -1; - if(a.modules[i].identifier() < b.modules[i].identifier()) return 1; - } - return 0; - }); - // TODO refactor to Map - chunks.forEach((c) => { - c.__OccurenceOrderPlugin_occursInEntry = undefined; + return a.compareTo(b); }); }); }); diff --git a/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js index e73add989..43550819c 100644 --- a/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js +++ b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js @@ -4,59 +4,31 @@ */ "use strict"; -function chunkContainsModule(chunk, module) { - const chunks = module.chunks; - const modules = chunk.modules; - if(chunks.length < modules.length) { - return chunks.indexOf(chunk) >= 0; - } else { - return modules.indexOf(module) >= 0; - } -} - function hasModule(chunk, module, checkedChunks) { - if(chunkContainsModule(chunk, module)) return [chunk]; + if(chunk.containsModule(module)) return [chunk]; if(chunk.parents.length === 0) return false; return allHaveModule(chunk.parents.filter((c) => { - return checkedChunks.indexOf(c) < 0; + return !checkedChunks.has(c); }), module, checkedChunks); } function allHaveModule(someChunks, module, checkedChunks) { - if(!checkedChunks) checkedChunks = []; - var chunks = []; + if(!checkedChunks) checkedChunks = new Set(); + var chunks = new Set(); for(var i = 0; i < someChunks.length; i++) { - checkedChunks.push(someChunks[i]); + checkedChunks.add(someChunks[i]); var subChunks = hasModule(someChunks[i], module, checkedChunks); if(!subChunks) return false; for(var index = 0; index < subChunks.length; index++) { var item = subChunks[index]; - if(!chunks.length || chunks.indexOf(item) < 0) { - chunks.push(item); - } + chunks.add(item); } } return chunks; } -function debugIds(chunks) { - var list = []; - for(var i = 0; i < chunks.length; i++) { - var debugId = chunks[i].debugId; - - if(typeof debugId !== "number") { - return "no"; - } - - list.push(debugId); - } - - list.sort(); - return list.join(","); -} - class RemoveParentModulesPlugin { apply(compiler) { compiler.plugin("compilation", (compilation) => { @@ -67,19 +39,21 @@ class RemoveParentModulesPlugin { // TODO consider Map when performance has improved https://gist.github.com/sokra/b36098368da7b8f6792fd7c85fca6311 var cache = Object.create(null); - var modules = chunk.modules.slice(); + var modules = chunk.getModules(); for(var i = 0; i < modules.length; i++) { var module = modules[i]; - var dId = debugIds(module.chunks); + var dId = module.getChunkIdsIdent(); var parentChunksWithModule; - if((dId in cache) && dId !== "no") { + if(dId === null) { + parentChunksWithModule = allHaveModule(chunk.parents, module); + } else if(dId in cache) { parentChunksWithModule = cache[dId]; } else { parentChunksWithModule = cache[dId] = allHaveModule(chunk.parents, module); } if(parentChunksWithModule) { - module.rewriteChunkInReasons(chunk, parentChunksWithModule); + module.rewriteChunkInReasons(chunk, Array.from(parentChunksWithModule)); chunk.removeModule(module); } } diff --git a/node_modules/webpack/lib/optimize/UglifyJsPlugin.js b/node_modules/webpack/lib/optimize/UglifyJsPlugin.js index f95dc8eef..1caa10817 100644 --- a/node_modules/webpack/lib/optimize/UglifyJsPlugin.js +++ b/node_modules/webpack/lib/optimize/UglifyJsPlugin.js @@ -4,233 +4,6 @@ */ "use strict"; -const SourceMapConsumer = require("source-map").SourceMapConsumer; -const SourceMapSource = require("webpack-sources").SourceMapSource; -const RawSource = require("webpack-sources").RawSource; -const ConcatSource = require("webpack-sources").ConcatSource; -const RequestShortener = require("../RequestShortener"); -const ModuleFilenameHelpers = require("../ModuleFilenameHelpers"); -const uglify = require("uglify-js"); - -class UglifyJsPlugin { - constructor(options) { - if(typeof options !== "object" || Array.isArray(options)) options = {}; - if(typeof options.compressor !== "undefined") options.compress = options.compressor; - this.options = options; - } - - apply(compiler) { - const options = this.options; - options.test = options.test || /\.js($|\?)/i; - const warningsFilter = options.warningsFilter || (() => true); - - const requestShortener = new RequestShortener(compiler.context); - compiler.plugin("compilation", (compilation) => { - if(options.sourceMap) { - compilation.plugin("build-module", (module) => { - // to get detailed location info about errors - module.useSourceMap = true; - }); - } - compilation.plugin("optimize-chunk-assets", (chunks, callback) => { - const files = []; - chunks.forEach((chunk) => files.push.apply(files, chunk.files)); - files.push.apply(files, compilation.additionalChunkAssets); - const filterdFiles = files.filter(ModuleFilenameHelpers.matchObject.bind(undefined, options)); - filterdFiles.forEach((file) => { - const oldWarnFunction = uglify.AST_Node.warn_function; - const warnings = []; - let sourceMap; - try { - const asset = compilation.assets[file]; - if(asset.__UglifyJsPlugin) { - compilation.assets[file] = asset.__UglifyJsPlugin; - return; - } - let input; - let inputSourceMap; - if(options.sourceMap) { - if(asset.sourceAndMap) { - const sourceAndMap = asset.sourceAndMap(); - inputSourceMap = sourceAndMap.map; - input = sourceAndMap.source; - } else { - inputSourceMap = asset.map(); - input = asset.source(); - } - sourceMap = new SourceMapConsumer(inputSourceMap); - uglify.AST_Node.warn_function = (warning) => { // eslint-disable-line camelcase - const match = /\[.+:([0-9]+),([0-9]+)\]/.exec(warning); - const line = +match[1]; - const column = +match[2]; - const original = sourceMap.originalPositionFor({ - line: line, - column: column - }); - if(!original || !original.source || original.source === file) return; - if(!warningsFilter(original.source)) return; - warnings.push(warning.replace(/\[.+:([0-9]+),([0-9]+)\]/, "") + - "[" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "]"); - }; - } else { - input = asset.source(); - uglify.AST_Node.warn_function = (warning) => { // eslint-disable-line camelcase - warnings.push(warning); - }; - } - uglify.base54.reset(); - let ast = uglify.parse(input, { - filename: file - }); - if(options.compress !== false) { - ast.figure_out_scope(); - const compress = uglify.Compressor(options.compress || { - warnings: false - }); // eslint-disable-line new-cap - ast = compress.compress(ast); - } - if(options.mangle !== false) { - ast.figure_out_scope(options.mangle || {}); - ast.compute_char_frequency(options.mangle || {}); - ast.mangle_names(options.mangle || {}); - if(options.mangle && options.mangle.props) { - uglify.mangle_properties(ast, options.mangle.props); - } - } - const output = {}; - output.comments = Object.prototype.hasOwnProperty.call(options, "comments") ? options.comments : /^\**!|@preserve|@license/; - output.beautify = options.beautify; - for(let k in options.output) { - output[k] = options.output[k]; - } - const extractedComments = []; - if(options.extractComments) { - const condition = {}; - if(typeof options.extractComments === "string" || options.extractComments instanceof RegExp) { - // extractComments specifies the extract condition and output.comments specifies the preserve condition - condition.preserve = output.comments; - condition.extract = options.extractComments; - } else if(Object.prototype.hasOwnProperty.call(options.extractComments, "condition")) { - // Extract condition is given in extractComments.condition - condition.preserve = output.comments; - condition.extract = options.extractComments.condition; - } else { - // No extract condition is given. Extract comments that match output.comments instead of preserving them - condition.preserve = false; - condition.extract = output.comments; - } - - // Ensure that both conditions are functions - ["preserve", "extract"].forEach(key => { - switch(typeof condition[key]) { - case "boolean": - var b = condition[key]; - condition[key] = () => b; - break; - case "function": - break; - case "string": - if(condition[key] === "all") { - condition[key] = () => true; - break; - } - var regex = new RegExp(condition[key]); - condition[key] = (astNode, comment) => regex.test(comment.value); - break; - default: - regex = condition[key]; - condition[key] = (astNode, comment) => regex.test(comment.value); - } - }); - - // Redefine the comments function to extract and preserve - // comments according to the two conditions - output.comments = (astNode, comment) => { - if(condition.extract(astNode, comment)) { - extractedComments.push( - comment.type === "comment2" ? "/*" + comment.value + "*/" : "//" + comment.value - ); - } - return condition.preserve(astNode, comment); - }; - } - let map; - if(options.sourceMap) { - map = uglify.SourceMap({ // eslint-disable-line new-cap - file: file, - root: "" - }); - output.source_map = map; // eslint-disable-line camelcase - } - const stream = uglify.OutputStream(output); // eslint-disable-line new-cap - ast.print(stream); - if(map) map = map + ""; - const stringifiedStream = stream + ""; - let outputSource = (map ? - new SourceMapSource(stringifiedStream, file, JSON.parse(map), input, inputSourceMap) : - new RawSource(stringifiedStream)); - if(extractedComments.length > 0) { - let commentsFile = options.extractComments.filename || file + ".LICENSE"; - if(typeof commentsFile === "function") { - commentsFile = commentsFile(file); - } - - // Write extracted comments to commentsFile - const commentsSource = new RawSource(extractedComments.join("\n\n") + "\n"); - if(commentsFile in compilation.assets) { - // commentsFile already exists, append new comments... - if(compilation.assets[commentsFile] instanceof ConcatSource) { - compilation.assets[commentsFile].add("\n"); - compilation.assets[commentsFile].add(commentsSource); - } else { - compilation.assets[commentsFile] = new ConcatSource( - compilation.assets[commentsFile], "\n", commentsSource - ); - } - } else { - compilation.assets[commentsFile] = commentsSource; - } - - // Add a banner to the original file - if(options.extractComments.banner !== false) { - let banner = options.extractComments.banner || "For license information please see " + commentsFile; - if(typeof banner === "function") { - banner = banner(commentsFile); - } - if(banner) { - outputSource = new ConcatSource( - "/*! " + banner + " */\n", outputSource - ); - } - } - } - asset.__UglifyJsPlugin = compilation.assets[file] = outputSource; - if(warnings.length > 0) { - compilation.warnings.push(new Error(file + " from UglifyJs\n" + warnings.join("\n"))); - } - } catch(err) { - if(err.line) { - const original = sourceMap && sourceMap.originalPositionFor({ - line: err.line, - column: err.col - }); - if(original && original.source) { - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + requestShortener.shorten(original.source) + ":" + original.line + "," + original.column + "][" + file + ":" + err.line + "," + err.col + "]")); - } else { - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.message + " [" + file + ":" + err.line + "," + err.col + "]")); - } - } else if(err.msg) { - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.msg)); - } else - compilation.errors.push(new Error(file + " from UglifyJs\n" + err.stack)); - } finally { - uglify.AST_Node.warn_function = oldWarnFunction; // eslint-disable-line camelcase - } - }); - callback(); - }); - }); - } -} +const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); module.exports = UglifyJsPlugin; -- cgit v1.2.3