From de98e0b232509d5f40c135d540a70e415272ff85 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 3 May 2017 15:35:00 +0200 Subject: node_modules --- .../lib/optimize/AggressiveMergingPlugin.js | 121 +++++++ .../lib/optimize/AggressiveSplittingPlugin.js | 192 +++++++++++ .../lib/optimize/ChunkModuleIdRangePlugin.js | 55 ++++ .../webpack/lib/optimize/CommonsChunkPlugin.js | 362 +++++++++++++++++++++ node_modules/webpack/lib/optimize/DedupePlugin.js | 15 + .../lib/optimize/EnsureChunkConditionsPlugin.js | 36 ++ .../lib/optimize/FlagIncludedChunksPlugin.js | 35 ++ .../webpack/lib/optimize/LimitChunkCountPlugin.js | 59 ++++ .../lib/optimize/MergeDuplicateChunksPlugin.js | 33 ++ .../webpack/lib/optimize/MinChunkSizePlugin.js | 65 ++++ .../webpack/lib/optimize/OccurrenceOrderPlugin.js | 116 +++++++ .../lib/optimize/RemoveEmptyChunksPlugin.js | 21 ++ .../lib/optimize/RemoveParentModulesPlugin.js | 91 ++++++ .../webpack/lib/optimize/UglifyJsPlugin.js | 236 ++++++++++++++ 14 files changed, 1437 insertions(+) create mode 100644 node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js create mode 100644 node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js create mode 100644 node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js create mode 100644 node_modules/webpack/lib/optimize/CommonsChunkPlugin.js create mode 100644 node_modules/webpack/lib/optimize/DedupePlugin.js create mode 100644 node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js create mode 100644 node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js create mode 100644 node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js create mode 100644 node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js create mode 100644 node_modules/webpack/lib/optimize/MinChunkSizePlugin.js create mode 100644 node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js create mode 100644 node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js create mode 100644 node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js create mode 100644 node_modules/webpack/lib/optimize/UglifyJsPlugin.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 new file mode 100644 index 000000000..826a6baa9 --- /dev/null +++ b/node_modules/webpack/lib/optimize/AggressiveMergingPlugin.js @@ -0,0 +1,121 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class AggressiveMergingPlugin { + constructor(options) { + if(options !== undefined && typeof options !== "object" || Array.isArray(options)) { + throw new Error("Argument should be an options object. To use defaults, pass in nothing.\nFor more info on options, see https://webpack.js.org/plugins/"); + } + this.options = options || {}; + } + + apply(compiler) { + const options = this.options; + const minSizeReduce = options.minSizeReduce || 1.5; + + function getParentsWeight(chunk) { + return chunk.parents.map((p) => { + return p.isInitial() ? options.entryChunkMultiplicator || 10 : 1; + }).reduce((a, b) => { + return a + b; + }, 0); + } + compiler.plugin("compilation", (compilation) => { + compilation.plugin("optimize-chunks-advanced", (chunks) => { + let combinations = []; + chunks.forEach((a, idx) => { + if(a.isInitial()) return; + for(let i = 0; i < idx; i++) { + const b = chunks[i]; + if(b.isInitial()) continue; + combinations.push([b, a]); + } + }); + + combinations.forEach((pair) => { + const a = pair[0].size({ + chunkOverhead: 0 + }); + const b = pair[1].size({ + chunkOverhead: 0 + }); + const ab = pair[0].integratedSize(pair[1], { + chunkOverhead: 0 + }); + pair.push({ + a: a, + b: b, + ab: ab + }); + let newSize; + if(ab === false) { + pair.unshift(false); + } 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 + }); + } else { + newSize = ab; + } + + pair.unshift((a + b) / newSize); + }); + combinations = combinations.filter((pair) => { + return pair[0] !== false; + }); + combinations.sort((a, b) => { + return b[0] - a[0]; + }); + + const pair = combinations[0]; + + if(!pair) return; + if(pair[0] < minSizeReduce) return; + + if(options.moveToParents) { + const commonModules = pair[1].modules.filter((m) => { + return pair[2].modules.indexOf(m) >= 0; + }); + const aOnlyModules = pair[1].modules.filter((m) => { + return commonModules.indexOf(m) < 0; + }); + const bOnlyModules = pair[2].modules.filter((m) => { + return commonModules.indexOf(m) < 0; + }); + aOnlyModules.forEach((m) => { + pair[1].removeModule(m); + m.removeChunk(pair[1]); + pair[1].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) => { + c.addModule(m); + m.addChunk(c); + }); + }); + } + if(pair[1].integrate(pair[2], "aggressive-merge")) { + chunks.splice(chunks.indexOf(pair[2]), 1); + return true; + } + }); + }); + } +} + +module.exports = AggressiveMergingPlugin; diff --git a/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js new file mode 100644 index 000000000..e05b3eb4c --- /dev/null +++ b/node_modules/webpack/lib/optimize/AggressiveSplittingPlugin.js @@ -0,0 +1,192 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +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); + }; +} + +function isNotAEntryModule(entryModule) { + return function(module) { + return entryModule !== module; + }; +} + +function copyWithReason(obj) { + const newObj = {}; + Object.keys(obj).forEach((key) => { + newObj[key] = obj[key]; + }); + if(!newObj.reasons || newObj.reasons.indexOf("aggressive-splitted") < 0) + newObj.reasons = (newObj.reasons || []).concat("aggressive-splitted"); + return newObj; +} + +class AggressiveSplittingPlugin { + constructor(options) { + this.options = options || {}; + if(typeof this.options.minSize !== "number") this.options.minSize = 30 * 1024; + if(typeof this.options.maxSize !== "number") this.options.maxSize = 50 * 1024; + if(typeof this.options.chunkOverhead !== "number") this.options.chunkOverhead = 0; + if(typeof this.options.entryChunkMultiplicator !== "number") this.options.entryChunkMultiplicator = 1; + } + apply(compiler) { + compiler.plugin("compilation", (compilation) => { + compilation.plugin("optimize-chunks-advanced", (chunks) => { + const savedSplits = compilation.records && compilation.records.aggressiveSplits || []; + const usedSplits = compilation._aggressiveSplittingSplits ? + savedSplits.concat(compilation._aggressiveSplittingSplits) : savedSplits; + + const minSize = this.options.minSize; + const maxSize = this.options.maxSize; + // 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())); + + 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; + } + } + } + } + } + // 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) { + const newChunk = compilation.addChunk(); + const modules = chunk.modules + .filter(isNotAEntryModule(chunk.entryModule)) + .sort((a, b) => { + a = a.identifier(); + b = b.identifier(); + if(a > b) return 1; + if(a < b) return -1; + return 0; + }); + for(let k = 0; k < modules.length; k++) { + chunk.moveModule(modules[k], newChunk); + const newSize = newChunk.size(this.options); + const chunkSize = chunk.size(this.options); + // break early if it's fine + if(chunkSize < maxSize && newSize < maxSize && newSize >= minSize && chunkSize >= minSize) + break; + if(newSize > maxSize && k === 0) { + // break if there is a single module which is bigger than maxSize + break; + } + if(newSize > maxSize || chunkSize < minSize) { + // move it back + newChunk.moveModule(modules[k], chunk); + // check if it's fine now + if(newSize < maxSize && newSize >= minSize && chunkSize >= minSize) + break; + } + } + if(newChunk.modules.length > 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())) + }); + return true; + } else { + chunks.splice(chunks.indexOf(newChunk), 1); + } + } + } + }); + compilation.plugin("record-hash", (records) => { + // 3. save to made splittings to records + const minSize = this.options.minSize; + if(!records.aggressiveSplits) records.aggressiveSplits = []; + compilation.chunks.forEach((chunk) => { + 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())); + if(typeof chunk._fromAggressiveSplittingIndex === "undefined") { + if(incorrectSize) return; + chunk.recorded = true; + records.aggressiveSplits.push({ + modules: modules, + hash: chunk.hash, + id: chunk.id + }); + } else { + const splitData = records.aggressiveSplits[chunk._fromAggressiveSplittingIndex]; + if(splitData.hash !== chunk.hash || incorrectSize) { + if(chunk._fromAggressiveSplitting) { + chunk._aggressiveSplittingInvalid = true; + splitData.invalid = true; + } else { + splitData.hash = chunk.hash; + } + } + } + }); + records.aggressiveSplits = records.aggressiveSplits.filter((splitData) => { + return !splitData.invalid; + }); + }); + compilation.plugin("need-additional-seal", (callback) => { + const invalid = compilation.chunks.some((chunk) => { + return chunk._aggressiveSplittingInvalid; + }); + if(invalid) + return true; + }); + }); + } +} +module.exports = AggressiveSplittingPlugin; diff --git a/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js b/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js new file mode 100644 index 000000000..8166fc315 --- /dev/null +++ b/node_modules/webpack/lib/optimize/ChunkModuleIdRangePlugin.js @@ -0,0 +1,55 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +class ChunkModuleIdRangePlugin { + constructor(options) { + this.options = options; + } + apply(compiler) { + 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]; + if(!chunk) throw new Error("ChunkModuleIdRangePlugin: Chunk with name '" + options.name + "' was not found"); + let currentId = options.start; + let chunkModules; + if(options.order) { + chunkModules = chunk.modules.slice(); + switch(options.order) { + case "index": + chunkModules.sort((a, b) => { + return a.index - b.index; + }); + break; + case "index2": + chunkModules.sort((a, b) => { + return a.index2 - b.index2; + }); + break; + default: + throw new Error("ChunkModuleIdRangePlugin: unexpected value of order"); + } + + } else { + chunkModules = modules.filter((m) => { + return m.chunks.indexOf(chunk) >= 0; + }); + } + + for(let i = 0; i < chunkModules.length; i++) { + const m = chunkModules[i]; + if(m.id === null) { + m.id = currentId++; + } + if(options.end && currentId > options.end) + break; + } + }); + }); + } +} +module.exports = ChunkModuleIdRangePlugin; diff --git a/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js b/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js new file mode 100644 index 000000000..d7c4849fe --- /dev/null +++ b/node_modules/webpack/lib/optimize/CommonsChunkPlugin.js @@ -0,0 +1,362 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; +let nextIdent = 0; +class CommonsChunkPlugin { + constructor(options) { + if(arguments.length > 1) { + throw new Error(`Deprecation notice: CommonsChunkPlugin now only takes a single argument. Either an options +object *or* the name of the chunk. +Example: if your old code looked like this: + new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js') +You would change it to: + new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' }) +The available options are: + name: string + names: string[] + filename: string + minChunks: number + chunks: string[] + children: boolean + async: boolean + minSize: number`); + } + + const normalizedOptions = this.normalizeOptions(options); + + this.chunkNames = normalizedOptions.chunkNames; + this.filenameTemplate = normalizedOptions.filenameTemplate; + this.minChunks = normalizedOptions.minChunks; + this.selectedChunks = normalizedOptions.selectedChunks; + this.children = normalizedOptions.children; + this.async = normalizedOptions.async; + this.minSize = normalizedOptions.minSize; + this.ident = __filename + (nextIdent++); + } + + normalizeOptions(options) { + if(Array.isArray(options)) { + return { + chunkNames: options, + }; + } + + if(typeof options === "string") { + return { + chunkNames: [options], + }; + } + + // options.children and options.chunk may not be used together + if(options.children && options.chunks) { + throw new Error("You can't and it does not make any sense to use \"children\" and \"chunk\" options together."); + } + + /** + * options.async and options.filename are also not possible together + * as filename specifies how the chunk is called but "async" implies + * 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.`); + } + + /** + * Make sure this is either an array or undefined. + * "name" can be a string and + * "names" a string or an array + */ + const chunkNames = options.name || options.names ? [].concat(options.name || options.names) : undefined; + return { + chunkNames: chunkNames, + filenameTemplate: options.filename, + minChunks: options.minChunks, + selectedChunks: options.chunks, + children: options.children, + async: options.async, + minSize: options.minSize + }; + } + + apply(compiler) { + compiler.plugin("this-compilation", (compilation) => { + compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], (chunks) => { + // only optimize once + if(compilation[this.ident]) return; + compilation[this.ident] = true; + + /** + * Creates a list of "common"" chunks based on the options. + * The list is made up of preexisting or newly created chunks. + * - If chunk has the name as specified in the chunkNames it is put in the list + * - If no chunk with the name as given in chunkNames exists a new chunk is created and added to the list + * + * These chunks are the "targets" for extracted modules. + */ + const targetChunks = this.getTargetChunks(chunks, compilation, this.chunkNames, this.children, this.async); + + // iterate over all our new chunks + targetChunks.forEach((targetChunk, idx) => { + + /** + * These chunks are subject to get "common" modules extracted and moved to the common chunk + */ + const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children); + + // bail if no chunk is affected + if(!affectedChunks) { + return; + } + + // If we are async create an async chunk now + // 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); + targetChunk = asyncChunk; + } + + /** + * Check which modules are "common" and could be extracted to a "common" chunk + */ + const extractableModules = this.getExtractableModules(this.minChunks, affectedChunks, targetChunk); + + // If the minSize option is set check if the size extracted from the chunk is reached + // else bail out here. + // As all modules/commons are interlinked with each other, common modules would be extracted + // if we reach this mark at a later common chunk. (quirky I guess). + if(this.minSize) { + const modulesSize = this.calculateModulesSize(extractableModules); + // if too small, bail + if(modulesSize < this.minSize) + return; + } + + // Remove modules that are moved to commons chunk from their original chunks + // return all chunks that are affected by having modules removed - we need them later (apparently) + const chunksWithExtractedModules = this.extractModulesAndReturnAffectedChunks(extractableModules, affectedChunks); + + // connect all extracted modules with the common chunk + this.addExtractedModulesToTargetChunk(targetChunk, extractableModules); + + // set filenameTemplate for chunk + if(this.filenameTemplate) + targetChunk.filenameTemplate = this.filenameTemplate; + + // if we are async connect the blocks of the "reallyUsedChunk" - the ones that had modules removed - + // with the commonChunk and get the origins for the asyncChunk (remember "asyncChunk === commonChunk" at this moment). + // bail out + if(this.async) { + this.moveExtractedChunkBlocksToTargetChunk(chunksWithExtractedModules, targetChunk); + asyncChunk.origins = this.extractOriginsOfChunksWithExtractedModules(chunksWithExtractedModules); + return; + } + + // we are not in "async" mode + // connect used chunks with commonChunk - shouldnt this be reallyUsedChunks here? + this.makeTargetChunkParentOfAffectedChunks(affectedChunks, targetChunk); + }); + return true; + }); + }); + } + + getTargetChunks(allChunks, compilation, chunkNames, children, asyncOption) { + const asyncOrNoSelectedChunk = children || asyncOption; + + // we have specified chunk names + if(chunkNames) { + // map chunks by chunkName for quick access + const allChunksNameMap = allChunks.reduce((map, chunk) => { + if(chunk.name) { + map.set(chunk.name, chunk); + } + return map; + }, new Map()); + + // Ensure we have a chunk per specified chunk name. + // Reuse existing chunks if possible + return chunkNames.map(chunkName => { + if(allChunksNameMap.has(chunkName)) { + return allChunksNameMap.get(chunkName); + } + // add the filtered chunks to the compilation + return compilation.addChunk(chunkName); + }); + } + + // we dont have named chunks specified, so we just take all of them + if(asyncOrNoSelectedChunk) { + return allChunks; + } + + /** + * No chunk name(s) was specified nor is this an async/children commons chunk + */ + throw new Error(`You did not specify any valid target chunk settings. +Take a look at the "name"/"names" or async/children option.`); + } + + getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, children) { + const asyncOrNoSelectedChunk = children || asyncOption; + + if(Array.isArray(selectedChunks)) { + return allChunks.filter(chunk => { + const notCommmonChunk = chunk !== targetChunk; + const isSelectedChunk = selectedChunks.indexOf(chunk.name) > -1; + return notCommmonChunk && isSelectedChunk; + }); + } + + if(asyncOrNoSelectedChunk) { + // nothing to do here + if(!targetChunk.chunks) { + return []; + } + + return targetChunk.chunks.filter((chunk) => { + // we can only move modules from this chunk if the "commonChunk" is the only parent + return asyncOption || chunk.parents.length === 1; + }); + } + + /** + * past this point only entry chunks are allowed to become commonChunks + */ + if(targetChunk.parents.length > 0) { + compilation.errors.push(new Error("CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (" + targetChunk.name + ")")); + return; + } + + /** + * If we find a "targetchunk" that is also a normal chunk (meaning it is probably specified as an entry) + * and the current target chunk comes after that and the found chunk has a runtime* + * make that chunk be an 'affected' chunk of the current target chunk. + * + * To understand what that means take a look at the "examples/chunkhash", this basically will + * result in the runtime to be extracted to the current target chunk. + * + * *runtime: the "runtime" is the "webpack"-block you may have seen in the bundles that resolves modules etc. + */ + return allChunks.filter((chunk) => { + const found = targetChunks.indexOf(chunk); + if(found >= currentIndex) return false; + return chunk.hasRuntime(); + }); + } + + createAsyncChunk(compilation, asyncOption, targetChunk) { + const asyncChunk = compilation.addChunk(typeof asyncOption === "string" ? asyncOption : undefined); + asyncChunk.chunkReason = "async commons chunk"; + asyncChunk.extraAsync = true; + asyncChunk.addParent(targetChunk); + targetChunk.addChunk(asyncChunk); + return asyncChunk; + } + + // If minChunks is a function use that + // otherwhise check if a module is used at least minChunks or 2 or usedChunks.length time + getModuleFilter(minChunks, targetChunk, usedChunksLength) { + if(typeof minChunks === "function") { + return minChunks; + } + const minCount = (minChunks || Math.max(2, usedChunksLength)); + const isUsedAtLeastMinTimes = (module, count) => count >= minCount; + return isUsedAtLeastMinTimes; + } + + getExtractableModules(minChunks, usedChunks, targetChunk) { + if(minChunks === Infinity) { + return []; + } + + // count how many chunks contain a module + const commonModulesToCountMap = usedChunks.reduce((map, chunk) => { + for(let module of chunk.modules) { + const count = map.has(module) ? map.get(module) : 0; + map.set(module, count + 1); + } + return map; + }, new Map()); + + // filter by minChunks + const moduleFilterCount = this.getModuleFilter(minChunks, targetChunk, usedChunks.length); + // filter by condition + const moduleFilterCondition = (module, chunk) => { + if(!module.chunkCondition) { + return true; + } + return module.chunkCondition(chunk); + }; + + return Array.from(commonModulesToCountMap).filter(entry => { + const module = entry[0]; + const count = entry[1]; + // if the module passes both filters, keep it. + return moduleFilterCount(module, count) && moduleFilterCondition(module, targetChunk); + }).map(entry => entry[0]); + } + + calculateModulesSize(modules) { + return modules.reduce((totalSize, module) => totalSize + module.size(), 0); + } + + extractModulesAndReturnAffectedChunks(reallyUsedModules, usedChunks) { + return reallyUsedModules.reduce((affectedChunksSet, module) => { + for(let 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)) { + affectedChunksSet.add(chunk); + } + } + return affectedChunksSet; + }, new Set()); + } + + addExtractedModulesToTargetChunk(chunk, modules) { + for(let module of modules) { + chunk.addModule(module); + module.addChunk(chunk); + } + } + + makeTargetChunkParentOfAffectedChunks(usedChunks, commonChunk) { + for(let 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) { + entrypoint.insertChunk(commonChunk, chunk); + } + } + } + + moveExtractedChunkBlocksToTargetChunk(chunks, targetChunk) { + for(let chunk of chunks) { + for(let block of chunk.blocks) { + block.chunks.unshift(targetChunk); + targetChunk.addBlock(block); + } + } + } + + extractOriginsOfChunksWithExtractedModules(chunks) { + const origins = []; + for(let chunk of chunks) { + for(let origin of chunk.origins) { + const newOrigin = Object.create(origin); + newOrigin.reasons = (origin.reasons || []).concat("async commons"); + origins.push(newOrigin); + } + } + return origins; + } +} + +module.exports = CommonsChunkPlugin; diff --git a/node_modules/webpack/lib/optimize/DedupePlugin.js b/node_modules/webpack/lib/optimize/DedupePlugin.js new file mode 100644 index 000000000..cffa43aaf --- /dev/null +++ b/node_modules/webpack/lib/optimize/DedupePlugin.js @@ -0,0 +1,15 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class DedupePlugin { + apply(compiler) { + compiler.plugin("compilation", (compilation) => { + compilation.warnings.push(new Error("DedupePlugin: This plugin was removed from webpack. Remove it from your configuration.")); + }); + } +} + +module.exports = DedupePlugin; diff --git a/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js new file mode 100644 index 000000000..71ee18533 --- /dev/null +++ b/node_modules/webpack/lib/optimize/EnsureChunkConditionsPlugin.js @@ -0,0 +1,36 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class EnsureChunkConditionsPlugin { + + apply(compiler) { + compiler.plugin("compilation", (compilation) => { + compilation.plugin(["optimize-chunks-basic", "optimize-extracted-chunks-basic"], (chunks) => { + let changed = false; + chunks.forEach((chunk) => { + chunk.modules.slice().forEach((module) => { + if(!module.chunkCondition) return; + if(!module.chunkCondition(chunk)) { + const usedChunks = module._EnsureChunkConditionsPlugin_usedChunks = (module._EnsureChunkConditionsPlugin_usedChunks || []).concat(chunk); + const newChunks = []; + chunk.parents.forEach((parent) => { + if(usedChunks.indexOf(parent) < 0) { + parent.addModule(module); + newChunks.push(parent); + } + }); + module.rewriteChunkInReasons(chunk, newChunks); + chunk.removeModule(module); + changed = true; + } + }); + }); + if(changed) return true; + }); + }); + } +} +module.exports = EnsureChunkConditionsPlugin; diff --git a/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js new file mode 100644 index 000000000..e8b5a9457 --- /dev/null +++ b/node_modules/webpack/lib/optimize/FlagIncludedChunksPlugin.js @@ -0,0 +1,35 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class FlagIncludedChunksPlugin { + + apply(compiler) { + compiler.plugin("compilation", (compilation) => { + compilation.plugin("optimize-chunk-ids", (chunks) => { + chunks.forEach((chunkA) => { + chunks.forEach((chunkB) => { + // as we iterate the same iterables twice + // skip if we find ourselves + if(chunkA === chunkB) return; + + // 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(chunkB.modules.length === 0) return; + + // is chunkB in chunkA? + for(let i = 0; i < chunkB.modules.length; i++) { + if(chunkA.modules.indexOf(chunkB.modules[i]) < 0) return; + } + chunkA.ids.push(chunkB.id); + }); + }); + }); + }); + } +} +module.exports = FlagIncludedChunksPlugin; diff --git a/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js b/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js new file mode 100644 index 000000000..c156338ff --- /dev/null +++ b/node_modules/webpack/lib/optimize/LimitChunkCountPlugin.js @@ -0,0 +1,59 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class LimitChunkCountPlugin { + constructor(options) { + if(options !== undefined && typeof options !== "object" || Array.isArray(options)) { + throw new Error("Argument should be an options object.\nFor more info on options, see https://webpack.js.org/plugins/"); + } + this.options = options || {}; + } + apply(compiler) { + const options = this.options; + compiler.plugin("compilation", (compilation) => { + compilation.plugin("optimize-chunks-advanced", (chunks) => { + const maxChunks = options.maxChunks; + if(!maxChunks) return; + if(maxChunks < 1) return; + if(chunks.length <= maxChunks) return; + + if(chunks.length > maxChunks) { + const sortedExtendedPairCombinations = chunks.reduce((combinations, a, idx) => { + // create combination pairs + for(let i = 0; i < idx; i++) { + const b = chunks[i]; + combinations.push([b, a]); + } + return combinations; + }, []).map((pair) => { + // extend combination pairs with size and integrated size + const a = pair[0].size(options); + const b = pair[1].size(options); + const ab = pair[0].integratedSize(pair[1], options); + return [a + b - ab, ab, pair[0], pair[1], a, b]; + }).filter((extendedPair) => { + // filter pairs that do not have an integratedSize + // meaning they can NOT be integrated! + return extendedPair[1] !== false; + }).sort((a, b) => { // sadly javascript does an inplace sort here + // sort them by size + const diff = b[0] - a[0]; + if(diff !== 0) return diff; + return a[1] - b[1]; + }); + + const pair = sortedExtendedPairCombinations[0]; + + if(pair && pair[2].integrate(pair[3], "limit")) { + chunks.splice(chunks.indexOf(pair[3]), 1); + return true; + } + } + }); + }); + } +} +module.exports = LimitChunkCountPlugin; diff --git a/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js new file mode 100644 index 000000000..90df06b51 --- /dev/null +++ b/node_modules/webpack/lib/optimize/MergeDuplicateChunksPlugin.js @@ -0,0 +1,33 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"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 = {}; + chunks.slice().forEach((chunk) => { + if(chunk.hasRuntime() || chunk.hasEntryModule()) return; + const ident = getChunkIdentifier(chunk); + if(map[ident]) { + if(map[ident].integrate(chunk, "duplicate")) + chunks.splice(chunks.indexOf(chunk), 1); + return; + } + map[ident] = chunk; + }); + }); + }); + } +} +module.exports = MergeDuplicateChunksPlugin; diff --git a/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js b/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js new file mode 100644 index 000000000..87a4c21af --- /dev/null +++ b/node_modules/webpack/lib/optimize/MinChunkSizePlugin.js @@ -0,0 +1,65 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class MinChunkSizePlugin { + constructor(options) { + if(typeof options !== "object" || Array.isArray(options)) { + throw new Error("Argument should be an options object.\nFor more info on options, see https://webpack.js.org/plugins/"); + } + this.options = options; + } + + apply(compiler) { + const options = this.options; + const minChunkSize = options.minChunkSize; + compiler.plugin("compilation", (compilation) => { + compilation.plugin("optimize-chunks-advanced", (chunks) => { + const equalOptions = { + chunkOverhead: 1, + entryChunkMultiplicator: 1 + }; + + const sortedSizeFilteredExtendedPairCombinations = chunks.reduce((combinations, a, idx) => { + // create combination pairs + for(let i = 0; i < idx; i++) { + const b = chunks[i]; + combinations.push([b, a]); + } + return combinations; + }, []).filter((pair) => { + // check if one of the chunks sizes is smaller than the minChunkSize + const p0SmallerThanMinChunkSize = pair[0].size(equalOptions) < minChunkSize; + const p1SmallerThanMinChunkSize = pair[1].size(equalOptions) < minChunkSize; + return p0SmallerThanMinChunkSize || p1SmallerThanMinChunkSize; + }).map((pair) => { + // extend combination pairs with size and integrated size + const a = pair[0].size(options); + const b = pair[1].size(options); + const ab = pair[0].integratedSize(pair[1], options); + return [a + b - ab, ab, pair[0], pair[1]]; + }).filter((pair) => { + // filter pairs that do not have an integratedSize + // meaning they can NOT be integrated! + return pair[1] !== false; + }).sort((a, b) => { // sadly javascript does an inplace sort here + // sort by size + const diff = b[0] - a[0]; + if(diff !== 0) return diff; + return a[1] - b[1]; + }); + + if(sortedSizeFilteredExtendedPairCombinations.length === 0) return; + + const pair = sortedSizeFilteredExtendedPairCombinations[0]; + + pair[2].integrate(pair[3], "min-size"); + chunks.splice(chunks.indexOf(pair[3]), 1); + return true; + }); + }); + } +} +module.exports = MinChunkSizePlugin; diff --git a/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js b/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js new file mode 100644 index 000000000..a6bb30b34 --- /dev/null +++ b/node_modules/webpack/lib/optimize/OccurrenceOrderPlugin.js @@ -0,0 +1,116 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class OccurrenceOrderPlugin { + constructor(preferEntry) { + if(preferEntry !== undefined && typeof preferEntry !== "boolean") { + throw new Error("Argument should be a boolean.\nFor more info on this plugin, see https://webpack.js.org/plugins/"); + } + this.preferEntry = preferEntry; + } + apply(compiler) { + 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); + } + + 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; + } + + 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; + } + modules.sort((a, b) => { + if(preferEntry) { + const aEntryOccurs = occursInEntry(a); + const bEntryOccurs = occursInEntry(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.identifier() > b.identifier()) return 1; + if(a.identifier() < b.identifier()) 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; + } + + 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); + 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; + }); + }); + }); + } +} + +module.exports = OccurrenceOrderPlugin; diff --git a/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js b/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js new file mode 100644 index 000000000..4b75e4617 --- /dev/null +++ b/node_modules/webpack/lib/optimize/RemoveEmptyChunksPlugin.js @@ -0,0 +1,21 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"use strict"; + +class RemoveEmptyChunksPlugin { + + apply(compiler) { + compiler.plugin("compilation", (compilation) => { + compilation.plugin(["optimize-chunks-basic", "optimize-extracted-chunks-basic"], (chunks) => { + chunks.filter((chunk) => chunk.isEmpty() && !chunk.hasRuntime() && !chunk.hasEntryModule()) + .forEach((chunk) => { + chunk.remove("empty"); + chunks.splice(chunks.indexOf(chunk), 1); + }); + }); + }); + } +} +module.exports = RemoveEmptyChunksPlugin; diff --git a/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js new file mode 100644 index 000000000..e73add989 --- /dev/null +++ b/node_modules/webpack/lib/optimize/RemoveParentModulesPlugin.js @@ -0,0 +1,91 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"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.parents.length === 0) return false; + return allHaveModule(chunk.parents.filter((c) => { + return checkedChunks.indexOf(c) < 0; + }), module, checkedChunks); +} + +function allHaveModule(someChunks, module, checkedChunks) { + if(!checkedChunks) checkedChunks = []; + var chunks = []; + for(var i = 0; i < someChunks.length; i++) { + checkedChunks.push(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); + } + } + } + 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) => { + compilation.plugin(["optimize-chunks-basic", "optimize-extracted-chunks-basic"], (chunks) => { + for(var index = 0; index < chunks.length; index++) { + var chunk = chunks[index]; + if(chunk.parents.length === 0) continue; + + // TODO consider Map when performance has improved https://gist.github.com/sokra/b36098368da7b8f6792fd7c85fca6311 + var cache = Object.create(null); + var modules = chunk.modules.slice(); + for(var i = 0; i < modules.length; i++) { + var module = modules[i]; + + var dId = debugIds(module.chunks); + var parentChunksWithModule; + if((dId in cache) && dId !== "no") { + parentChunksWithModule = cache[dId]; + } else { + parentChunksWithModule = cache[dId] = allHaveModule(chunk.parents, module); + } + if(parentChunksWithModule) { + module.rewriteChunkInReasons(chunk, parentChunksWithModule); + chunk.removeModule(module); + } + } + } + }); + }); + } +} +module.exports = RemoveParentModulesPlugin; diff --git a/node_modules/webpack/lib/optimize/UglifyJsPlugin.js b/node_modules/webpack/lib/optimize/UglifyJsPlugin.js new file mode 100644 index 000000000..f95dc8eef --- /dev/null +++ b/node_modules/webpack/lib/optimize/UglifyJsPlugin.js @@ -0,0 +1,236 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra +*/ +"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(); + }); + }); + } +} + +module.exports = UglifyJsPlugin; -- cgit v1.2.3