123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- "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.deepChildren = normalizedOptions.deepChildren;
- 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],
- };
- }
-
- 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.");
- }
-
- 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.`);
- }
-
- 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,
- deepChildren: options.deepChildren,
- async: options.async,
- minSize: options.minSize
- };
- }
- apply(compiler) {
- compiler.plugin("this-compilation", (compilation) => {
- compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"], (chunks) => {
-
- if(compilation[this.ident]) return;
- compilation[this.ident] = true;
-
- const targetChunks = this.getTargetChunks(chunks, compilation, this.chunkNames, this.children, this.async);
-
- targetChunks.forEach((targetChunk, idx) => {
-
- const affectedChunks = this.getAffectedChunks(compilation, chunks, targetChunk, targetChunks, idx, this.selectedChunks, this.async, this.children, this.deepChildren);
-
- if(!affectedChunks) {
- return;
- }
-
-
- let asyncChunk;
- if(this.async) {
-
- asyncChunk = affectedChunks.filter(c => c.name === this.async)[0];
-
- 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;
- }
-
- const extractableModules = this.getExtractableModules(this.minChunks, affectedChunks, targetChunk);
-
-
-
-
- if(this.minSize) {
- const modulesSize = this.calculateModulesSize(extractableModules);
-
- if(modulesSize < this.minSize)
- return;
- }
-
-
- const chunksWithExtractedModules = this.extractModulesAndReturnAffectedChunks(extractableModules, affectedChunks);
-
- this.addExtractedModulesToTargetChunk(targetChunk, extractableModules);
-
- if(this.filenameTemplate)
- targetChunk.filenameTemplate = this.filenameTemplate;
-
-
-
- if(this.async) {
- this.moveExtractedChunkBlocksToTargetChunk(chunksWithExtractedModules, targetChunk);
- asyncChunk.origins = this.extractOriginsOfChunksWithExtractedModules(chunksWithExtractedModules);
- return;
- }
-
-
- this.makeTargetChunkParentOfAffectedChunks(affectedChunks, targetChunk);
- });
- return true;
- });
- });
- }
- getTargetChunks(allChunks, compilation, chunkNames, children, asyncOption) {
- const asyncOrNoSelectedChunk = children || asyncOption;
-
- if(chunkNames) {
-
- const allChunksNameMap = allChunks.reduce((map, chunk) => {
- if(chunk.name) {
- map.set(chunk.name, chunk);
- }
- return map;
- }, new Map());
-
-
- return chunkNames.map(chunkName => {
- if(allChunksNameMap.has(chunkName)) {
- return allChunksNameMap.get(chunkName);
- }
-
- return compilation.addChunk(chunkName);
- });
- }
-
- if(asyncOrNoSelectedChunk) {
- return allChunks;
- }
-
- throw new Error(`You did not specify any valid target chunk settings.
- Take a look at the "name"/"names" or async/children option.`);
- }
- getAffectedUnnamedChunks(affectedChunks, targetChunk, rootChunk, asyncOption, deepChildrenOption) {
- let chunks = targetChunk.chunks;
- chunks && chunks.forEach((chunk) => {
- if(chunk.isInitial()) {
- return;
- }
-
-
-
-
-
- if(asyncOption || chunk.parents.every((parentChunk) => parentChunk === rootChunk || affectedChunks.has(parentChunk))) {
-
- if(!affectedChunks.has(chunk)) {
-
-
-
- affectedChunks.add(chunk);
-
-
-
-
- if(deepChildrenOption === true) {
- this.getAffectedUnnamedChunks(affectedChunks, chunk, rootChunk, asyncOption, deepChildrenOption);
- }
- }
- }
- });
- }
- getAffectedChunks(compilation, allChunks, targetChunk, targetChunks, currentIndex, selectedChunks, asyncOption, childrenOption, deepChildrenOption) {
- const asyncOrNoSelectedChunk = childrenOption || 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) {
- let affectedChunks = new Set();
- this.getAffectedUnnamedChunks(affectedChunks, targetChunk, targetChunk, asyncOption, deepChildrenOption);
- return Array.from(affectedChunks);
- }
-
- 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;
- }
-
- 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;
- }
-
-
- 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 [];
- }
-
- const commonModulesToCountMap = usedChunks.reduce((map, chunk) => {
- for(const module of chunk.modulesIterable) {
- const count = map.has(module) ? map.get(module) : 0;
- map.set(module, count + 1);
- }
- return map;
- }, new Map());
-
- const moduleFilterCount = this.getModuleFilter(minChunks, targetChunk, usedChunks.length);
-
- 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];
-
- 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(const chunk of usedChunks) {
-
-
- if(module.removeChunk(chunk)) {
- affectedChunksSet.add(chunk);
- }
- }
- return affectedChunksSet;
- }, new Set());
- }
- addExtractedModulesToTargetChunk(chunk, modules) {
- for(const module of modules) {
- chunk.addModule(module);
- module.addChunk(chunk);
- }
- }
- makeTargetChunkParentOfAffectedChunks(usedChunks, commonChunk) {
- for(const chunk of usedChunks) {
-
- chunk.parents = [commonChunk];
-
- commonChunk.addChunk(chunk);
- for(const entrypoint of chunk.entrypoints) {
- entrypoint.insertChunk(commonChunk, chunk);
- }
- }
- }
- moveExtractedChunkBlocksToTargetChunk(chunks, 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);
- }
- }
- }
- extractOriginsOfChunksWithExtractedModules(chunks) {
- const 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);
- }
- }
- return origins;
- }
- }
- module.exports = CommonsChunkPlugin;
|