webpack-cascade-optimizer-plugin
Version:
A Webpack plugin that distributes common code along output files on a First-come, First-served basis.
125 lines (101 loc) • 4.49 kB
JavaScript
;
/** @license webpack-cascade-optimizer-plugin v1.0.5
*
* Copyright (c) 2019, ernestostifano
*
* This source code is licensed under the ISC license found in the
* LICENSE.md file in the root directory of this source tree.
*/
module.exports = class CascadeOptimizer {
/**
* @param {Object} options
* @param {Array} options.fileOrder
*/
constructor(options) {
this.options = options;
}
/**
* @param {Object} compiler
* @param {Object} compiler.options
* @param {Object} compiler.options.optimization
* @param {Object} compiler.options.splitChunks
* @param {Object} compiler.hooks
* @param {Object} compiler.hooks.thisCompilation
* @param {function} compiler.hooks.thisCompilation.tap
*/
apply(compiler) {
// OVERRIDE OPTIONS
compiler.options.optimization.splitChunks.chunks = 'async';
compiler.options.optimization.splitChunks.name = true;
compiler.options.optimization.splitChunks.automaticNameDelimiter = '~';
compiler.options.optimization.splitChunks.cacheGroups = {
default: false,
vendors: false,
custom: {
test: /(?:node_modules)/,
chunks: 'all',
enforce: true
}
};
compiler.options.optimization.runtimeChunk = typeof this.options.fileOrder[0] === "string" ? {
name: this.options.fileOrder[0]
} : compiler.options.optimization.runtimeChunk;
compiler.hooks.thisCompilation.tap('CascadeOptimizer',
/**
* @param {Object} compilation
* @param {Object} compilation.hooks
* @param {Object} compilation.hooks.afterOptimizeChunks
* @param {function} compilation.hooks.afterOptimizeChunks.tap
*/
(compilation) => {
compilation.hooks.afterOptimizeChunks.tap('CascadeOptimizer',
/**
* @param {Array[]} chunks
* @param {function} chunks[].moveModule
* @param {function} chunks[].isEmpty
* @param {function} chunks[].hasRuntime
* @param {function} chunks[].hasEntryModule
* @param {Array} chunks[].modulesIterable
*/
(chunks) => {
let targetName = null;
let targetIndex = null;
let c = null, t = null;
let length = chunks.length;
// DISTRIBUTE COMMON CODE ALONG OUTPUT FILES
for (c = length - 1; c >= 0; c--) {
// SEARCH FOR A CUSTOM CHUNK
if (chunks[c].name.match(/^custom~.+$/)) {
// CHOOSE TARGET CHUNK BASED ON PROVIDED FILE NAME ORDER
targetName = null;
targetIndex = null;
chunks[c].name.replace(/^custom~/, '').split('~').forEach((name) => {
this.options.fileOrder.forEach((fileName, index) => {
if (name === fileName && (targetName === null || index < targetIndex)) {
targetName = fileName;
targetIndex = index;
}
});
});
// SEARCH FOR TARGET CHUNK
for (t = 0; t < length; t++) {
if (chunks[t].name === targetName) {
// MOVE MODULES FROM CUSTOM CHUNK TO TARGET CHUNK
chunks[c].modulesIterable.forEach((module) => {
chunks[c].moveModule(module, chunks[t]);
});
// REMOVE CUSTOM CHUNK
if (chunks[c].isEmpty() && !chunks[c].hasRuntime() && !chunks[c].hasEntryModule()) {
chunks[c].remove();
chunks.splice(c, 1);
length--;
}
break;
}
}
}
}
});
});
};
};