You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					140 lines
				
				4.7 KiB
			
		
		
			
		
	
	
					140 lines
				
				4.7 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const toposort = require('toposort');
							 | 
						||
| 
								 | 
							
								const _ = require('lodash');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								  Sorts dependencies between chunks by their "parents" attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  This function sorts chunks based on their dependencies with each other.
							 | 
						||
| 
								 | 
							
								  The parent relation between chunks as generated by Webpack for each chunk
							 | 
						||
| 
								 | 
							
								  is used to define a directed (and hopefully acyclic) graph, which is then
							 | 
						||
| 
								 | 
							
								  topologically sorted in order to retrieve the correct order in which
							 | 
						||
| 
								 | 
							
								  chunks need to be embedded into HTML. A directed edge in this graph is
							 | 
						||
| 
								 | 
							
								  describing a "is parent of" relationship from a chunk to another (distinct)
							 | 
						||
| 
								 | 
							
								  chunk. Thus topological sorting orders chunks from bottom-layer chunks to
							 | 
						||
| 
								 | 
							
								  highest level chunks that use the lower-level chunks.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @param {Array} chunks an array of chunks as generated by the html-webpack-plugin.
							 | 
						||
| 
								 | 
							
								  - For webpack < 4, It is assumed that each entry contains at least the properties
							 | 
						||
| 
								 | 
							
								  "id" (containing the chunk id) and "parents" (array containing the ids of the
							 | 
						||
| 
								 | 
							
								  parent chunks).
							 | 
						||
| 
								 | 
							
								  - For webpack 4+ the see the chunkGroups param for parent-child relationships
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @param {Array} chunks an array of ChunkGroups that has a getParents method.
							 | 
						||
| 
								 | 
							
								  Each ChunkGroup contains a list of chunks in order.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @return {Array} A topologically sorted version of the input chunks
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								module.exports.dependency = (chunks, options, compilation) => {
							 | 
						||
| 
								 | 
							
								  const chunkGroups = compilation.chunkGroups;
							 | 
						||
| 
								 | 
							
								  if (!chunks) {
							 | 
						||
| 
								 | 
							
								    return chunks;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // We build a map (chunk-id -> chunk) for faster access during graph building.
							 | 
						||
| 
								 | 
							
								  const nodeMap = {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  chunks.forEach(chunk => {
							 | 
						||
| 
								 | 
							
								    nodeMap[chunk.id] = chunk;
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Next, we add an edge for each parent relationship into the graph
							 | 
						||
| 
								 | 
							
								  let edges = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (chunkGroups) {
							 | 
						||
| 
								 | 
							
								    // Add an edge for each parent (parent -> child)
							 | 
						||
| 
								 | 
							
								    edges = chunkGroups.reduce((result, chunkGroup) => result.concat(
							 | 
						||
| 
								 | 
							
								      Array.from(chunkGroup.parentsIterable, parentGroup => [parentGroup, chunkGroup])
							 | 
						||
| 
								 | 
							
								    ), []);
							 | 
						||
| 
								 | 
							
								    const sortedGroups = toposort.array(chunkGroups, edges);
							 | 
						||
| 
								 | 
							
								    // flatten chunkGroup into chunks
							 | 
						||
| 
								 | 
							
								    const sortedChunks = sortedGroups
							 | 
						||
| 
								 | 
							
								      .reduce((result, chunkGroup) => result.concat(chunkGroup.chunks), [])
							 | 
						||
| 
								 | 
							
								      .map(chunk => // use the chunk from the list passed in, since it may be a filtered list
							 | 
						||
| 
								 | 
							
								    nodeMap[chunk.id])
							 | 
						||
| 
								 | 
							
								      .filter((chunk, index, self) => {
							 | 
						||
| 
								 | 
							
								        // make sure exists (ie excluded chunks not in nodeMap)
							 | 
						||
| 
								 | 
							
								        const exists = !!chunk;
							 | 
						||
| 
								 | 
							
								        // make sure we have a unique list
							 | 
						||
| 
								 | 
							
								        const unique = self.indexOf(chunk) === index;
							 | 
						||
| 
								 | 
							
								        return exists && unique;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    return sortedChunks;
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    // before webpack 4 there was no chunkGroups
							 | 
						||
| 
								 | 
							
								    chunks.forEach(chunk => {
							 | 
						||
| 
								 | 
							
								      if (chunk.parents) {
							 | 
						||
| 
								 | 
							
								        // Add an edge for each parent (parent -> child)
							 | 
						||
| 
								 | 
							
								        chunk.parents.forEach(parentId => {
							 | 
						||
| 
								 | 
							
								          // webpack2 chunk.parents are chunks instead of string id(s)
							 | 
						||
| 
								 | 
							
								          const parentChunk = _.isObject(parentId) ? parentId : nodeMap[parentId];
							 | 
						||
| 
								 | 
							
								          // If the parent chunk does not exist (e.g. because of an excluded chunk)
							 | 
						||
| 
								 | 
							
								          // we ignore that parent
							 | 
						||
| 
								 | 
							
								          if (parentChunk) {
							 | 
						||
| 
								 | 
							
								            edges.push([parentChunk, chunk]);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    // We now perform a topological sorting on the input chunks and built edges
							 | 
						||
| 
								 | 
							
								    return toposort.array(chunks, edges);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Sorts the chunks based on the chunk id.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param  {Array} chunks the list of chunks to sort
							 | 
						||
| 
								 | 
							
								 * @return {Array} The sorted list of chunks
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports.id = chunks => chunks.sort(function orderEntryLast (a, b) {
							 | 
						||
| 
								 | 
							
								  if (a.entry !== b.entry) {
							 | 
						||
| 
								 | 
							
								    return b.entry ? 1 : -1;
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    return b.id - a.id;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Performs identity mapping (no-sort).
							 | 
						||
| 
								 | 
							
								 * @param  {Array} chunks the chunks to sort
							 | 
						||
| 
								 | 
							
								 * @return {Array} The sorted chunks
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports.none = chunks => chunks;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Sort manually by the chunks
							 | 
						||
| 
								 | 
							
								 * @param  {Array} chunks the chunks to sort
							 | 
						||
| 
								 | 
							
								 * @return {Array} The sorted chunks
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports.manual = (chunks, options) => {
							 | 
						||
| 
								 | 
							
								  const specifyChunks = options.chunks;
							 | 
						||
| 
								 | 
							
								  const chunksResult = [];
							 | 
						||
| 
								 | 
							
								  let filterResult = [];
							 | 
						||
| 
								 | 
							
								  if (Array.isArray(specifyChunks)) {
							 | 
						||
| 
								 | 
							
								    for (var i = 0; i < specifyChunks.length; i++) {
							 | 
						||
| 
								 | 
							
								      filterResult = chunks.filter(chunk => {
							 | 
						||
| 
								 | 
							
								        if (chunk.names[0] && chunk.names[0] === specifyChunks[i]) {
							 | 
						||
| 
								 | 
							
								          return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return false;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								      filterResult.length > 0 && chunksResult.push(filterResult[0]);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return chunksResult;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Defines the default sorter.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports.auto = module.exports.id;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// In webpack 2 the ids have been flipped.
							 | 
						||
| 
								 | 
							
								// Therefore the id sort doesn't work the same way as it did for webpack 1
							 | 
						||
| 
								 | 
							
								// Luckily the dependency sort is working as expected
							 | 
						||
| 
								 | 
							
								if (Number(require('webpack/package.json').version.split('.')[0]) > 1) {
							 | 
						||
| 
								 | 
							
								  module.exports.auto = module.exports.dependency;
							 | 
						||
| 
								 | 
							
								}
							 |