Skip to content

Instantly share code, notes, and snippets.

@MagicDuck
Last active January 30, 2017 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MagicDuck/481a420c509f0c128e0ef99680e980c9 to your computer and use it in GitHub Desktop.
Save MagicDuck/481a420c509f0c128e0ef99680e980c9 to your computer and use it in GitHub Desktop.
"use strict";
const PluginHelper = require("../lib/PluginHelper");
var _pluginInstance;
/**
* This plugin will look at each non-entry/non-named/non-localization chunk and slice it up into additional chunks
* so that the size of each of those chunks don't exceed the specified maxSize.
* At runtime, the sliced chunks are loaded together as one in parallel.
* @param {object} options
* - enabled {boolean} whether plugin is enabled
* - maxSize {int} max slice size in bytes
* - minSize {int} min slice size in bytes (smaller slices will be absorbed into the other slices)
*/
var ChunkParallelSplitterPlugin = module.exports = function(options) {
this.options = Object.assign({
maxSize: 512 * 1024,
minSize: 50 * 1024,
enabled: true
}, options);
if (_pluginInstance) {
throw new Error("ChunkParallelSplitterPlugin: only one instance of this plugin is allowed!");
} else {
_pluginInstance = this;
}
};
function createSplitChunk(compilation, chunk) {
var splitChunk = PluginHelper.splitChunk(compilation, chunk, "parallel split chunk");
splitChunk._cps_isParallelSplitChunk = true;
chunk._cps_chunkSplits = chunk._cps_chunkSplits || [chunk];
chunk._cps_chunkSplits.push(splitChunk);
return splitChunk;
}
ChunkParallelSplitterPlugin.prototype.apply = function(compiler) {
var options = this.options;
if (options.enabled === false) {
return;
}
compiler.plugin("this-compilation", function(compilation) {
// split off large chunks into slices not exceeding maxSize
compilation.plugin("after-optimize-chunks", function(chunks) {
if (chunks.length === 0) {
return;
}
chunks.slice().forEach(function(chunk) {
if (chunk.entry || chunk._cps_isParallelSplitChunk) {
return;
}
// compute splits
var splitSize = 0;
var slices = [0];
for (let i = 0, len = chunk.modules.length; i < len; ++i) {
let mod = chunk.modules[i];
if (!mod || !mod.resource) {
continue;
}
var modSize = mod.size();
if (splitSize + modSize > options.maxSize) {
splitSize = modSize;
slices.push(i);
} else {
// keep adding modules to the split
splitSize += modSize;
}
}
if (slices.length > 1 && splitSize < options.minSize) {
slices.pop();
}
// if we have only one slice, there's nothing to do
if (slices.length === 1) {
return;
}
// create split chunks
slices.push(chunk.modules.length);
for (let i = 1, len = slices.length - 1; i < len; ++i) {
// create the new chunk
var splitChunk = createSplitChunk(compilation, chunk);
splitChunk._cps_originalChunk = chunk;
var begin = slices[i];
var end = slices[i+1];
splitChunk.modules = chunk.modules.slice(begin, end);
for (let mod of splitChunk.modules) {
mod.chunks.splice(mod.chunks.indexOf(chunk), 1);
mod.rewriteChunkInReasons(chunk, [splitChunk]);
}
}
// update original chunk to contain only first slice of modules, preserving array reference
var firstSliceModules = chunk.modules.slice(slices[0], slices[1]);
chunk.modules.length = 0;
for (let mod of firstSliceModules) {
chunk.modules.push(mod);
}
}.bind(this));
});
// at this point, we are guaranteed that each chunk has an id.
// give the split chunks some friendly unique names
compilation.plugin("after-optimize-chunk-ids", function(chunks) {
if (chunks.length === 0) {
return;
}
chunks.forEach(function(chunk) {
if (chunk._cps_isParallelSplitChunk) {
chunk.name = `${chunk.id}.slice_of_${chunk._cps_originalChunk.name || chunk._cps_originalChunk.id}`;
}
});
}.bind(this));
}.bind(this));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment