Skip to content

Commit

Permalink
fix(chunksorter): Don't sort chunks by default
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Chunks aren't sorted anymore by default
  • Loading branch information
jantimon committed Jun 3, 2018
1 parent a0a0f0d commit 22fb03f
Show file tree
Hide file tree
Showing 2 changed files with 1 addition and 165 deletions.
105 changes: 1 addition & 104 deletions lib/chunksorter.js
@@ -1,101 +1,5 @@
'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
Expand Down Expand Up @@ -129,11 +33,4 @@ module.exports.manual = (chunks, options) => {
/**
* 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;
}
module.exports.auto = module.exports.none;
61 changes: 0 additions & 61 deletions spec/BasicSpec.js
Expand Up @@ -1546,67 +1546,6 @@ describe('HtmlWebpackPlugin', function () {
}, [/<script type="text\/javascript" src="c_bundle.js">.+<script type="text\/javascript" src="b_bundle.js">.+<script type="text\/javascript" src="a_bundle.js">/], null, done);
});

it('should sort the chunks by chunk dependencies', function (done) {
testHtmlPlugin({
entry: {
util: path.join(__dirname, 'fixtures/util.js'),
aTheme: path.join(__dirname, 'fixtures/theme.js')
},
output: {
path: OUTPUT_DIR,
filename: '[name]_bundle.js'
},
module: {
loaders: [
{ test: /\.css$/, loader: 'css-loader' }
]
},
__commonsChunk: {
name: 'common',
filename: 'common_bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
chunksSortMode: 'dependency'
})
]
}, [
// theme and util don't depend on each other, so the order of those doesn't matter
/<script type="text\/javascript" src="common_bundle.js">.+(<script type="text\/javascript" src="aTheme_bundle.js">.+<script type="text\/javascript" src="util_bundle.js">|<script type="text\/javascript" src="util_bundle.js">.+<script type="text\/javascript" src="aTheme_bundle.js">)/
], null, done);
});

it('should sort the chunks by chunk dependencies even if a parent chunk is excluded', function (done) {
testHtmlPlugin({
entry: {
util: path.join(__dirname, 'fixtures/util.js'),
aTheme: path.join(__dirname, 'fixtures/theme.js')
},
output: {
path: OUTPUT_DIR,
filename: '[name]_bundle.js'
},
module: {
loaders: [
{ test: /\.css$/, loader: 'css-loader' }
]
},
__commonsChunk: {
name: 'common',
filename: 'common_bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
chunksSortMode: 'dependency',
excludeChunks: ['common']
})
]
}, [
// theme and util don't depend on each other, so the order of those doesn't matter
/(<script type="text\/javascript" src="aTheme_bundle.js">.+<script type="text\/javascript" src="util_bundle.js">|<script type="text\/javascript" src="util_bundle.js">.+<script type="text\/javascript" src="aTheme_bundle.js">)/
], null, done);
});

it('should sort manually by the chunks', function (done) {
testHtmlPlugin({
entry: {
Expand Down

0 comments on commit 22fb03f

Please sign in to comment.