Merge pull request #7889 from webpack/refactor/chunk-graph
add ChunkGraph
This commit is contained in:
commit
655d57f2d7
|
@ -6,6 +6,7 @@
|
|||
"use strict";
|
||||
|
||||
const { ConcatSource } = require("webpack-sources");
|
||||
const ExternalModule = require("./ExternalModule");
|
||||
const Template = require("./Template");
|
||||
|
||||
/** @typedef {import("./Compilation")} Compilation */
|
||||
|
@ -27,10 +28,17 @@ class AmdMainTemplatePlugin {
|
|||
const { mainTemplate, chunkTemplate } = compilation;
|
||||
|
||||
const onRenderWithEntry = (source, chunk, hash) => {
|
||||
const externals = chunk.getModules().filter(m => m.external);
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const modules = chunkGraph
|
||||
.getChunkModules(chunk)
|
||||
.filter(m => m instanceof ExternalModule);
|
||||
const externals = /** @type {ExternalModule[]} */ (modules);
|
||||
const externalsDepsArray = JSON.stringify(
|
||||
externals.map(
|
||||
m => (typeof m.request === "object" ? m.request.amd : m.request)
|
||||
m =>
|
||||
typeof m.request === "object" && !Array.isArray(m.request)
|
||||
? m.request.amd
|
||||
: m.request
|
||||
)
|
||||
);
|
||||
const externalsArguments = externals
|
||||
|
|
|
@ -88,15 +88,6 @@ class AsyncDependenciesBlock extends DependenciesBlock {
|
|||
this.chunkGroup = undefined;
|
||||
super.unseal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts items in this module
|
||||
* @param {boolean=} sortChunks sort the chunks too
|
||||
* @returns {void}
|
||||
*/
|
||||
sortItems(sortChunks) {
|
||||
super.sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(AsyncDependenciesBlock.prototype, "module", {
|
||||
|
|
365
lib/Chunk.js
365
lib/Chunk.js
|
@ -6,14 +6,12 @@
|
|||
"use strict";
|
||||
|
||||
const Entrypoint = require("./Entrypoint");
|
||||
const {
|
||||
connectChunkAndModule,
|
||||
disconnectChunkAndModule
|
||||
} = require("./GraphHelpers");
|
||||
const { intersect } = require("./util/SetHelpers");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("./ChunkGroup")} ChunkGroup */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleReason")} ModuleReason */
|
||||
|
@ -33,17 +31,10 @@ const SortableSet = require("./util/SortableSet");
|
|||
|
||||
// TODO use @callback
|
||||
/** @typedef {(a: Module, b: Module) => -1|0|1} ModuleSortPredicate */
|
||||
/** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
|
||||
/** @typedef {(c: Chunk) => boolean} ChunkFilterPredicate */
|
||||
|
||||
let debugId = 1000;
|
||||
|
||||
const sortModuleById = (a, b) => {
|
||||
if (a.id < b.id) return -1;
|
||||
if (b.id < a.id) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compare two ChunkGroups based on their ids for sorting
|
||||
* @param {ChunkGroup} a chunk group
|
||||
|
@ -56,50 +47,6 @@ const sortChunkGroupById = (a, b) => {
|
|||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compare two Identifiables , based on their ids for sorting
|
||||
* @param {Module} a first object with ident fn
|
||||
* @param {Module} b second object with ident fn
|
||||
* @returns {-1|0|1} The order number of the sort
|
||||
*/
|
||||
const sortByIdentifier = (a, b) => {
|
||||
if (a.identifier() > b.identifier()) return 1;
|
||||
if (a.identifier() < b.identifier()) return -1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {string} a concatenation of module identifiers sorted
|
||||
* @param {SortableSet} set to pull module identifiers from
|
||||
*/
|
||||
const getModulesIdent = set => {
|
||||
set.sort();
|
||||
let str = "";
|
||||
for (const m of set) {
|
||||
str += m.identifier() + "#";
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {SortableSet<T>} set the sortable set to convert to array
|
||||
* @returns {Array<T>} the array returned from Array.from(set)
|
||||
*/
|
||||
const getArray = set => Array.from(set);
|
||||
|
||||
/**
|
||||
* @param {SortableSet<Module>} set the sortable Set to get the count/size of
|
||||
* @returns {number} the size of the modules
|
||||
*/
|
||||
const getModulesSize = set => {
|
||||
let size = 0;
|
||||
for (const module of set) {
|
||||
size += module.size();
|
||||
}
|
||||
return size;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Chunk is a unit of encapsulation for Modules.
|
||||
* Chunks are "rendered" into bundles that get emitted when the build completes.
|
||||
|
@ -121,8 +68,6 @@ class Chunk {
|
|||
this.preventIntegration = false;
|
||||
/** @type {Module=} */
|
||||
this.entryModule = undefined;
|
||||
/** @private @type {SortableSet<Module>} */
|
||||
this._modules = new SortableSet(undefined, sortByIdentifier);
|
||||
/** @type {string?} */
|
||||
this.filenameTemplate = undefined;
|
||||
/** @private @type {SortableSet<ChunkGroup>} */
|
||||
|
@ -187,52 +132,6 @@ class Chunk {
|
|||
return !!this.entryModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module that will be added to this chunk.
|
||||
* @returns {boolean} returns true if the chunk doesn't have the module and it was added
|
||||
*/
|
||||
addModule(module) {
|
||||
if (!this._modules.has(module)) {
|
||||
this._modules.add(module);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module that will be removed from this chunk
|
||||
* @returns {boolean} returns true if chunk exists and is successfully deleted
|
||||
*/
|
||||
removeModule(module) {
|
||||
if (this._modules.delete(module)) {
|
||||
module.removeChunk(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module[]} modules the new modules to be set
|
||||
* @returns {void} set new modules to this chunk and return nothing
|
||||
*/
|
||||
setModules(modules) {
|
||||
this._modules = new SortableSet(modules, sortByIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number} the amount of modules in chunk
|
||||
*/
|
||||
getNumberOfModules() {
|
||||
return this._modules.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {SortableSet<Module>} return the modules SortableSet for this chunk
|
||||
*/
|
||||
get modulesIterable() {
|
||||
return this._modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkGroup} chunkGroup the chunkGroup the chunk is being added
|
||||
* @returns {boolean} returns true if chunk is not apart of chunkGroup and is added successfully
|
||||
|
@ -276,106 +175,14 @@ class Chunk {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} otherChunk the chunk to compare itself with
|
||||
* @returns {-1|0|1} this is a comparitor function like sort and returns -1, 0, or 1 based on sort order
|
||||
* @returns {void}
|
||||
*/
|
||||
compareTo(otherChunk) {
|
||||
this._modules.sort();
|
||||
otherChunk._modules.sort();
|
||||
if (this._modules.size > otherChunk._modules.size) return -1;
|
||||
if (this._modules.size < otherChunk._modules.size) return 1;
|
||||
const a = this._modules[Symbol.iterator]();
|
||||
const b = otherChunk._modules[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const aItem = a.next();
|
||||
const bItem = b.next();
|
||||
if (aItem.done) return 0;
|
||||
const aModuleIdentifier = aItem.value.identifier();
|
||||
const bModuleIdentifier = bItem.value.identifier();
|
||||
if (aModuleIdentifier < bModuleIdentifier) return -1;
|
||||
if (aModuleIdentifier > bModuleIdentifier) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module Module to check
|
||||
* @returns {boolean} returns true if module does exist in this chunk
|
||||
*/
|
||||
containsModule(module) {
|
||||
return this._modules.has(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Module[]} an array of all modules in this chunk
|
||||
*/
|
||||
getModules() {
|
||||
return this._modules.getFromCache(getArray);
|
||||
}
|
||||
|
||||
getModulesIdent() {
|
||||
return this._modules.getFromUnorderedCache(getModulesIdent);
|
||||
}
|
||||
|
||||
remove() {
|
||||
// cleanup modules
|
||||
// Array.from is used here to create a clone, because removeChunk modifies this._modules
|
||||
for (const module of Array.from(this._modules)) {
|
||||
module.removeChunk(this);
|
||||
}
|
||||
disconnectFromGroups() {
|
||||
for (const chunkGroup of this._groups) {
|
||||
chunkGroup.removeChunk(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Module} module module to move
|
||||
* @param {Chunk} otherChunk other chunk to move it to
|
||||
* @returns {void}
|
||||
*/
|
||||
moveModule(module, otherChunk) {
|
||||
disconnectChunkAndModule(this, module);
|
||||
connectChunkAndModule(otherChunk, module);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Chunk} otherChunk the chunk to integrate with
|
||||
* @param {ModuleReason} reason reason why the module is being integrated
|
||||
* @returns {boolean} returns true or false if integration succeeds or fails
|
||||
*/
|
||||
integrate(otherChunk, reason) {
|
||||
if (!this.canBeIntegrated(otherChunk)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Array.from is used here to create a clone, because moveModule modifies otherChunk._modules
|
||||
for (const module of Array.from(otherChunk._modules)) {
|
||||
otherChunk.moveModule(module, this);
|
||||
}
|
||||
otherChunk._modules.clear();
|
||||
|
||||
for (const chunkGroup of otherChunk._groups) {
|
||||
chunkGroup.replaceChunk(otherChunk, this);
|
||||
this.addGroup(chunkGroup);
|
||||
}
|
||||
otherChunk._groups.clear();
|
||||
|
||||
if (this.name && otherChunk.name) {
|
||||
if (this.name.length !== otherChunk.name.length) {
|
||||
this.name =
|
||||
this.name.length < otherChunk.name.length
|
||||
? this.name
|
||||
: otherChunk.name;
|
||||
} else {
|
||||
this.name = this.name < otherChunk.name ? this.name : otherChunk.name;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} newChunk the new chunk that will be split out of, and then chunk raphi twil=
|
||||
* @returns {void}
|
||||
|
@ -387,15 +194,19 @@ class Chunk {
|
|||
}
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this._modules.size === 0;
|
||||
}
|
||||
|
||||
updateHash(hash) {
|
||||
/**
|
||||
* @param {Hash} hash hash (will be modified)
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash, chunkGraph) {
|
||||
hash.update(`${this.id} `);
|
||||
hash.update(this.ids ? this.ids.join(",") : "");
|
||||
hash.update(`${this.name || ""} `);
|
||||
for (const m of this._modules) {
|
||||
for (const m of chunkGraph.getOrderedChunkModulesIterable(
|
||||
this,
|
||||
compareModulesById
|
||||
)) {
|
||||
hash.update(m.hash);
|
||||
}
|
||||
}
|
||||
|
@ -434,71 +245,6 @@ class Chunk {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} size the size
|
||||
* @param {Object} options the options passed in
|
||||
* @returns {number} the multiplier returned
|
||||
*/
|
||||
addMultiplierAndOverhead(size, options) {
|
||||
const overhead =
|
||||
typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
|
||||
const multiplicator = this.canBeInitial()
|
||||
? options.entryChunkMultiplicator || 10
|
||||
: 1;
|
||||
|
||||
return size * multiplicator + overhead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number} the size of all modules
|
||||
*/
|
||||
modulesSize() {
|
||||
return this._modules.getFromUnorderedCache(getModulesSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} options the size display options
|
||||
* @returns {number} the chunk size
|
||||
*/
|
||||
size(options) {
|
||||
return this.addMultiplierAndOverhead(this.modulesSize(), options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} otherChunk the other chunk
|
||||
* @param {TODO} options the options for this function
|
||||
* @returns {number | false} the size, or false if it can't be integrated
|
||||
*/
|
||||
integratedSize(otherChunk, options) {
|
||||
// Chunk if it's possible to integrate this chunk
|
||||
if (!this.canBeIntegrated(otherChunk)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let integratedModulesSize = this.modulesSize();
|
||||
// only count modules that do not exist in this chunk!
|
||||
for (const otherModule of otherChunk._modules) {
|
||||
if (!this._modules.has(otherModule)) {
|
||||
integratedModulesSize += otherModule.size();
|
||||
}
|
||||
}
|
||||
|
||||
return this.addMultiplierAndOverhead(integratedModulesSize, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {function(Module, Module): -1|0|1=} sortByFn a predicate function used to sort modules
|
||||
* @returns {void}
|
||||
*/
|
||||
sortModules(sortByFn) {
|
||||
this._modules.sortWith(sortByFn || sortModuleById);
|
||||
}
|
||||
|
||||
sortItems() {
|
||||
this.sortModules();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Set<Chunk>} a set of all the async chunks
|
||||
*/
|
||||
|
@ -570,9 +316,10 @@ class Chunk {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @returns {Record<string, Set<TODO>[]>} a record object of names to lists of child ids(?)
|
||||
*/
|
||||
getChildIdsByOrders() {
|
||||
getChildIdsByOrders(chunkGraph) {
|
||||
const lists = new Map();
|
||||
for (const group of this.groupsIterable) {
|
||||
if (group.chunks[group.chunks.length - 1] === this) {
|
||||
|
@ -596,7 +343,7 @@ class Chunk {
|
|||
list.sort((a, b) => {
|
||||
const cmp = b.order - a.order;
|
||||
if (cmp !== 0) return cmp;
|
||||
return a.group.compareTo(b.group);
|
||||
return a.group.compareTo(chunkGraph, b.group);
|
||||
});
|
||||
result[name] = Array.from(
|
||||
list.reduce((set, item) => {
|
||||
|
@ -610,11 +357,11 @@ class Chunk {
|
|||
return result;
|
||||
}
|
||||
|
||||
getChildIdsByOrdersMap(includeDirectChildren) {
|
||||
getChildIdsByOrdersMap(chunkGraph, includeDirectChildren) {
|
||||
const chunkMaps = Object.create(null);
|
||||
|
||||
const addChildIdsByOrdersToMap = chunk => {
|
||||
const data = chunk.getChildIdsByOrders();
|
||||
const data = chunk.getChildIdsByOrders(chunkGraph);
|
||||
for (const key of Object.keys(data)) {
|
||||
let chunkMap = chunkMaps[key];
|
||||
if (chunkMap === undefined) {
|
||||
|
@ -634,80 +381,6 @@ class Chunk {
|
|||
|
||||
return chunkMaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ChunkModuleMaps
|
||||
* @property {Record<string|number, (string|number)[]>} id
|
||||
* @property {Record<string|number, string>} hash
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {ModuleFilterPredicate} filterFn function used to filter modules
|
||||
* @returns {ChunkModuleMaps} module map information
|
||||
*/
|
||||
getChunkModuleMaps(filterFn) {
|
||||
/** @type {Record<string|number, (string|number)[]>} */
|
||||
const chunkModuleIdMap = Object.create(null);
|
||||
/** @type {Record<string|number, string>} */
|
||||
const chunkModuleHashMap = Object.create(null);
|
||||
|
||||
for (const chunk of this.getAllAsyncChunks()) {
|
||||
/** @type {(string|number)[]} */
|
||||
let array;
|
||||
for (const module of chunk.modulesIterable) {
|
||||
if (filterFn(module)) {
|
||||
if (array === undefined) {
|
||||
array = [];
|
||||
chunkModuleIdMap[chunk.id] = array;
|
||||
}
|
||||
array.push(module.id);
|
||||
chunkModuleHashMap[module.id] = module.renderedHash;
|
||||
}
|
||||
}
|
||||
if (array !== undefined) {
|
||||
array.sort();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: chunkModuleIdMap,
|
||||
hash: chunkModuleHashMap
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {function(Module): boolean} filterFn predicate function used to filter modules
|
||||
* @param {function(Chunk): boolean} filterChunkFn predicate function used to filter chunks
|
||||
* @returns {boolean} return true if module exists in graph
|
||||
*/
|
||||
hasModuleInGraph(filterFn, filterChunkFn) {
|
||||
const queue = new Set(this.groupsIterable);
|
||||
const chunksProcessed = new Set();
|
||||
|
||||
for (const chunkGroup of queue) {
|
||||
for (const chunk of chunkGroup.chunks) {
|
||||
if (!chunksProcessed.has(chunk)) {
|
||||
chunksProcessed.add(chunk);
|
||||
if (!filterChunkFn || filterChunkFn(chunk)) {
|
||||
for (const module of chunk.modulesIterable) {
|
||||
if (filterFn(module)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const child of chunkGroup.childrenIterable) {
|
||||
queue.add(child);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `Chunk[${Array.from(this._modules).join()}]`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Chunk;
|
||||
|
|
|
@ -0,0 +1,537 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGroup")} ChunkGroup */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
/** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
|
||||
|
||||
/**
|
||||
* @param {Chunk} a chunk
|
||||
* @param {Chunk} b chunk
|
||||
* @returns {number} compare result
|
||||
*/
|
||||
const sortChunksByDebugId = (a, b) => {
|
||||
return a.debugId - b.debugId;
|
||||
};
|
||||
|
||||
/** @template T @typedef {(set: SortableSet<T>) => T[]} SetToArrayFunction<T> */
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {SortableSet<T>} set the set
|
||||
* @returns {T[]} set as array
|
||||
*/
|
||||
const getArray = set => {
|
||||
return Array.from(set);
|
||||
};
|
||||
|
||||
/** @type {WeakMap<Function, any>} */
|
||||
const createOrderedArrayFunctionMap = new WeakMap();
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {function(T, T): -1|0|1} comparator comparator function
|
||||
* @returns {SetToArrayFunction<T>} set as ordered array
|
||||
*/
|
||||
const createOrderedArrayFunction = comparator => {
|
||||
/** @type {SetToArrayFunction<T>} */
|
||||
let fn = createOrderedArrayFunctionMap.get(comparator);
|
||||
if (fn !== undefined) return fn;
|
||||
fn = set => {
|
||||
set.sortWith(comparator);
|
||||
return Array.from(set);
|
||||
};
|
||||
createOrderedArrayFunctionMap.set(comparator, fn);
|
||||
return fn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {SortableSet<Module>} set the sortable Set to get the count/size of
|
||||
* @returns {number} the size of the modules
|
||||
*/
|
||||
const getModulesSize = set => {
|
||||
let size = 0;
|
||||
for (const module of set) {
|
||||
size += module.size();
|
||||
}
|
||||
return size;
|
||||
};
|
||||
|
||||
class ChunkGraphModule {
|
||||
constructor() {
|
||||
/** @type {SortableSet<Chunk>} */
|
||||
this.chunks = new SortableSet();
|
||||
}
|
||||
}
|
||||
|
||||
class ChunkGraphChunk {
|
||||
constructor() {
|
||||
/** @type {SortableSet<Module>} */
|
||||
this.modules = new SortableSet();
|
||||
}
|
||||
}
|
||||
|
||||
class ChunkGraph {
|
||||
constructor() {
|
||||
/** @private @type {WeakMap<Module, ChunkGraphModule>} */
|
||||
this._modules = new WeakMap();
|
||||
/** @private @type {WeakMap<Chunk, ChunkGraphChunk>} */
|
||||
this._chunks = new WeakMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Module} module the module
|
||||
* @returns {ChunkGraphModule} internal module
|
||||
*/
|
||||
_getChunkGraphModule(module) {
|
||||
let m = this._modules.get(module);
|
||||
if (m === undefined) {
|
||||
m = new ChunkGraphModule();
|
||||
this._modules.set(module, m);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {ChunkGraphChunk} internal chunk
|
||||
*/
|
||||
_getChunkGraphChunk(chunk) {
|
||||
let c = this._chunks.get(chunk);
|
||||
if (c === undefined) {
|
||||
c = new ChunkGraphChunk();
|
||||
this._chunks.set(chunk, c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the new chunk
|
||||
* @param {Module} module the module
|
||||
* @returns {boolean} true, if the chunk could be added. false if it was already added
|
||||
*/
|
||||
connectChunkAndModule(chunk, module) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
// TODO refactor to remove return value
|
||||
if (cgm.chunks.has(chunk) && cgc.modules.has(module)) return false;
|
||||
cgm.chunks.add(chunk);
|
||||
cgc.modules.add(module);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {Module} module the module
|
||||
* @returns {void}
|
||||
*/
|
||||
disconnectChunkAndModule(chunk, module) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
cgc.modules.delete(module);
|
||||
cgm.chunks.delete(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk which will be disconnected
|
||||
* @returns {void}
|
||||
*/
|
||||
disconnectChunk(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
for (const module of cgc.modules) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
cgm.chunks.delete(chunk);
|
||||
}
|
||||
cgc.modules.clear();
|
||||
chunk.disconnectFromGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {Iterable<Module>} modules the modules
|
||||
* @returns {void}
|
||||
*/
|
||||
attachModules(chunk, modules) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
for (const module of modules) {
|
||||
cgc.modules.add(module);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} oldModule the replaced module
|
||||
* @param {Module} newModule the replacing module
|
||||
* @returns {void}
|
||||
*/
|
||||
replaceModule(oldModule, newModule) {
|
||||
const oldCgm = this._getChunkGraphModule(oldModule);
|
||||
const newCgm = this._getChunkGraphModule(newModule);
|
||||
const chunks = this.getModuleChunks(oldModule);
|
||||
for (const chunk of chunks) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
cgc.modules.delete(oldModule);
|
||||
cgc.modules.add(newModule);
|
||||
oldCgm.chunks.delete(chunk);
|
||||
newCgm.chunks.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the checked module
|
||||
* @param {Chunk} chunk the checked chunk
|
||||
* @returns {boolean} true, if the chunk contains the module
|
||||
*/
|
||||
isModuleInChunk(module, chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.modules.has(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the checked module
|
||||
* @param {ChunkGroup} chunkGroup the checked chunk group
|
||||
* @returns {boolean} true, if the chunk contains the module
|
||||
*/
|
||||
isModuleInChunkGroup(module, chunkGroup) {
|
||||
for (const chunk of chunkGroup.chunks) {
|
||||
if (this.isModuleInChunk(module, chunk)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the checked module
|
||||
* @returns {boolean} true, if the module is entry of any chunk
|
||||
*/
|
||||
isEntryModule(module) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
for (const chunk of cgm.chunks) {
|
||||
if (chunk.entryModule === module) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @returns {Iterable<Chunk>} iterable of chunks (do not modify)
|
||||
*/
|
||||
getModuleChunksIterable(module) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
return cgm.chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @param {function(Chunk, Chunk): -1|0|1} sortFn sort function
|
||||
* @returns {Iterable<Chunk>} iterable of chunks (do not modify)
|
||||
*/
|
||||
getOrderedModuleChunksIterable(module, sortFn) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
cgm.chunks.sortWith(sortFn);
|
||||
return cgm.chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @returns {Chunk[]} array of chunks (cached, do not modify)
|
||||
*/
|
||||
getModuleChunks(module) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
return cgm.chunks.getFromCache(getArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the module
|
||||
* @returns {number} the number of chunk which contain the module
|
||||
*/
|
||||
getNumberOfModuleChunks(module) {
|
||||
const cgm = this._getChunkGraphModule(module);
|
||||
return cgm.chunks.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} moduleA some module
|
||||
* @param {Module} moduleB some module
|
||||
* @returns {boolean} true, if modules are in the same chunks
|
||||
*/
|
||||
haveModulesEqualChunks(moduleA, moduleB) {
|
||||
const cgmA = this._getChunkGraphModule(moduleA);
|
||||
const cgmB = this._getChunkGraphModule(moduleB);
|
||||
if (cgmA.chunks.size !== cgmB.chunks.size) return false;
|
||||
cgmA.chunks.sortWith(sortChunksByDebugId);
|
||||
cgmB.chunks.sortWith(sortChunksByDebugId);
|
||||
const a = cgmA.chunks[Symbol.iterator]();
|
||||
const b = cgmB.chunks[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const aItem = a.next();
|
||||
if (aItem.done) return true;
|
||||
const bItem = b.next();
|
||||
if (aItem.value !== bItem.value) return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {number} the number of module which are contained in this chunk
|
||||
*/
|
||||
getNumberOfChunkModules(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.modules.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {Iterable<Module>} return the modules for this chunk
|
||||
*/
|
||||
getChunkModulesIterable(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {function(Module, Module): -1|0|1} comparator comparator function
|
||||
* @returns {Iterable<Module>} return the modules for this chunk
|
||||
*/
|
||||
getOrderedChunkModulesIterable(chunk, comparator) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
cgc.modules.sortWith(comparator);
|
||||
return cgc.modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {Module[]} return the modules for this chunk (cached, do not modify)
|
||||
*/
|
||||
getChunkModules(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.modules.getFromUnorderedCache(getArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {function(Module, Module): -1|0|1} comparator comparator function
|
||||
* @returns {Module[]} return the modules for this chunk (cached, do not modify)
|
||||
*/
|
||||
getOrderedChunkModules(chunk, comparator) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
const arrayFunction = createOrderedArrayFunction(comparator);
|
||||
return cgc.modules.getFromUnorderedCache(arrayFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ChunkModuleMaps
|
||||
* @property {Record<string|number, (string|number)[]>} id
|
||||
* @property {Record<string|number, string>} hash
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {ModuleFilterPredicate} filterFn function used to filter modules
|
||||
* @returns {ChunkModuleMaps} module map information
|
||||
*/
|
||||
getChunkModuleMaps(chunk, filterFn) {
|
||||
/** @type {Record<string|number, (string|number)[]>} */
|
||||
const chunkModuleIdMap = Object.create(null);
|
||||
/** @type {Record<string|number, string>} */
|
||||
const chunkModuleHashMap = Object.create(null);
|
||||
|
||||
for (const asyncChunk of chunk.getAllAsyncChunks()) {
|
||||
/** @type {(string|number)[]} */
|
||||
let array;
|
||||
for (const module of this.getOrderedChunkModulesIterable(
|
||||
asyncChunk,
|
||||
compareModulesById
|
||||
)) {
|
||||
if (filterFn(module)) {
|
||||
if (array === undefined) {
|
||||
array = [];
|
||||
chunkModuleIdMap[asyncChunk.id] = array;
|
||||
}
|
||||
array.push(module.id);
|
||||
chunkModuleHashMap[module.id] = module.renderedHash;
|
||||
}
|
||||
}
|
||||
if (array !== undefined) {
|
||||
array.sort();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: chunkModuleIdMap,
|
||||
hash: chunkModuleHashMap
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {function(Module): boolean} filterFn predicate function used to filter modules
|
||||
* @param {(function(Chunk): boolean)=} filterChunkFn predicate function used to filter chunks
|
||||
* @returns {boolean} return true if module exists in graph
|
||||
*/
|
||||
hasModuleInGraph(chunk, filterFn, filterChunkFn) {
|
||||
const queue = new Set(chunk.groupsIterable);
|
||||
const chunksProcessed = new Set();
|
||||
|
||||
for (const chunkGroup of queue) {
|
||||
for (const innerChunk of chunkGroup.chunks) {
|
||||
if (!chunksProcessed.has(innerChunk)) {
|
||||
chunksProcessed.add(innerChunk);
|
||||
if (!filterChunkFn || filterChunkFn(innerChunk)) {
|
||||
for (const module of this.getChunkModulesIterable(innerChunk)) {
|
||||
if (filterFn(module)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const child of chunkGroup.childrenIterable) {
|
||||
queue.add(child);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunkA first chunk
|
||||
* @param {Chunk} chunkB second chunk
|
||||
* @returns {-1|0|1} this is a comparitor function like sort and returns -1, 0, or 1 based on sort order
|
||||
*/
|
||||
compareChunks(chunkA, chunkB) {
|
||||
const cgcA = this._getChunkGraphChunk(chunkA);
|
||||
const cgcB = this._getChunkGraphChunk(chunkB);
|
||||
if (cgcA.modules.size > cgcB.modules.size) return -1;
|
||||
if (cgcA.modules.size < cgcB.modules.size) return 1;
|
||||
cgcA.modules.sortWith(compareModulesById);
|
||||
cgcB.modules.sortWith(compareModulesById);
|
||||
const a = cgcA.modules[Symbol.iterator]();
|
||||
const b = cgcB.modules[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const aItem = a.next();
|
||||
if (aItem.done) return 0;
|
||||
const bItem = b.next();
|
||||
const aModuleIdentifier = aItem.value.identifier();
|
||||
const bModuleIdentifier = bItem.value.identifier();
|
||||
if (aModuleIdentifier < bModuleIdentifier) return -1;
|
||||
if (aModuleIdentifier > bModuleIdentifier) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {number} total size of all modules in the chunk
|
||||
*/
|
||||
getChunkModulesSize(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.modules.getFromUnorderedCache(getModulesSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ChunkSizeOptions
|
||||
* @property {number=} chunkOverhead constant overhead for a chunk
|
||||
* @property {number=} entryChunkMultiplicator multiplicator for initial chunks
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {ChunkSizeOptions} options options object
|
||||
* @returns {number} total size of the chunk
|
||||
*/
|
||||
getChunkSize(chunk, options) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
const modulesSize = cgc.modules.getFromUnorderedCache(getModulesSize);
|
||||
const chunkOverhead =
|
||||
typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
|
||||
const entryChunkMultiplicator =
|
||||
typeof options.entryChunkMultiplicator === "number"
|
||||
? options.entryChunkMultiplicator
|
||||
: 10;
|
||||
return (
|
||||
chunkOverhead +
|
||||
modulesSize * (chunk.canBeInitial() ? entryChunkMultiplicator : 1)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunkA chunk
|
||||
* @param {Chunk} chunkB chunk
|
||||
* @param {ChunkSizeOptions} options options object
|
||||
* @returns {number} total size of the chunk or false if chunks can't be integrated
|
||||
*/
|
||||
getIntegratedChunksSize(chunkA, chunkB, options) {
|
||||
const cgcA = this._getChunkGraphChunk(chunkA);
|
||||
const cgcB = this._getChunkGraphChunk(chunkB);
|
||||
const allModules = new Set(cgcA.modules);
|
||||
for (const m of cgcB.modules) allModules.add(m);
|
||||
let modulesSize = 0;
|
||||
for (const module of allModules) {
|
||||
modulesSize += module.size();
|
||||
}
|
||||
const chunkOverhead =
|
||||
typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
|
||||
const entryChunkMultiplicator =
|
||||
typeof options.entryChunkMultiplicator === "number"
|
||||
? options.entryChunkMultiplicator
|
||||
: 10;
|
||||
return (
|
||||
chunkOverhead +
|
||||
modulesSize *
|
||||
(chunkA.canBeInitial() || chunkB.canBeInitial()
|
||||
? entryChunkMultiplicator
|
||||
: 1)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunkA chunk
|
||||
* @param {Chunk} chunkB chunk
|
||||
* @returns {boolean} true, if chunks could be integrated
|
||||
*/
|
||||
canChunksBeIntegrated(chunkA, chunkB) {
|
||||
return chunkA.canBeIntegrated(chunkB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunkA the target chunk
|
||||
* @param {Chunk} chunkB the chunk to integrate
|
||||
* @returns {void}
|
||||
*/
|
||||
integrateChunks(chunkA, chunkB) {
|
||||
// getChunkModules is used here to create a clone, because disconnectChunkAndModule modifies
|
||||
for (const module of this.getChunkModules(chunkB)) {
|
||||
this.disconnectChunkAndModule(chunkB, module);
|
||||
this.connectChunkAndModule(chunkA, module);
|
||||
}
|
||||
|
||||
for (const chunkGroup of chunkB.groupsIterable) {
|
||||
chunkGroup.replaceChunk(chunkB, chunkA);
|
||||
chunkA.addGroup(chunkGroup);
|
||||
chunkB.removeGroup(chunkGroup);
|
||||
}
|
||||
|
||||
// Decide for one name (deterministic)
|
||||
if (chunkA.name && chunkB.name) {
|
||||
if (chunkA.name.length !== chunkB.name.length) {
|
||||
chunkA.name =
|
||||
chunkA.name.length < chunkB.name.length ? chunkA.name : chunkB.name;
|
||||
} else {
|
||||
chunkA.name = chunkA.name < chunkB.name ? chunkA.name : chunkB.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChunkGraph;
|
|
@ -9,6 +9,7 @@ const compareLocations = require("./compareLocations");
|
|||
const SortableSet = require("./util/SortableSet");
|
||||
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleReason")} ModuleReason */
|
||||
|
@ -285,9 +286,9 @@ class ChunkGroup {
|
|||
return this._parents;
|
||||
}
|
||||
|
||||
removeParent(chunk) {
|
||||
if (this._parents.delete(chunk)) {
|
||||
chunk.removeChunk(this);
|
||||
removeParent(chunkGroup) {
|
||||
if (this._parents.delete(chunkGroup)) {
|
||||
chunkGroup.removeChunk(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -334,13 +335,6 @@ class ChunkGroup {
|
|||
});
|
||||
}
|
||||
|
||||
containsModule(module) {
|
||||
for (const chunk of this.chunks) {
|
||||
if (chunk.containsModule(module)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getFiles() {
|
||||
const files = new Set();
|
||||
|
||||
|
@ -354,7 +348,7 @@ class ChunkGroup {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {ModuleReason} reason reason for removing ChunkGroup
|
||||
* @param {string=} reason reason for removing ChunkGroup
|
||||
* @returns {void}
|
||||
*/
|
||||
remove(reason) {
|
||||
|
@ -408,10 +402,11 @@ class ChunkGroup {
|
|||
* Sorting predicate which allows current ChunkGroup to be compared against another.
|
||||
* Sorting values are based off of number of chunks in ChunkGroup.
|
||||
*
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @param {ChunkGroup} otherGroup the chunkGroup to compare this against
|
||||
* @returns {-1|0|1} sort position for comparison
|
||||
*/
|
||||
compareTo(otherGroup) {
|
||||
compareTo(chunkGraph, otherGroup) {
|
||||
if (this.chunks.length > otherGroup.chunks.length) return -1;
|
||||
if (this.chunks.length < otherGroup.chunks.length) return 1;
|
||||
const a = this.chunks[Symbol.iterator]();
|
||||
|
@ -421,12 +416,12 @@ class ChunkGroup {
|
|||
const aItem = a.next();
|
||||
const bItem = b.next();
|
||||
if (aItem.done) return 0;
|
||||
const cmp = aItem.value.compareTo(bItem.value);
|
||||
const cmp = chunkGraph.compareChunks(aItem.value, bItem.value);
|
||||
if (cmp !== 0) return cmp;
|
||||
}
|
||||
}
|
||||
|
||||
getChildrenByOrders() {
|
||||
getChildrenByOrders(chunkGraph) {
|
||||
const lists = new Map();
|
||||
for (const childGroup of this._children) {
|
||||
for (const key of Object.keys(childGroup.options)) {
|
||||
|
@ -448,7 +443,7 @@ class ChunkGroup {
|
|||
list.sort((a, b) => {
|
||||
const cmp = b.order - a.order;
|
||||
if (cmp !== 0) return cmp;
|
||||
return a.group.compareTo(b.group);
|
||||
return a.group.compareTo(chunkGraph, b.group);
|
||||
});
|
||||
result[name] = list.map(i => i.group);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ const {
|
|||
const { CachedSource } = require("webpack-sources");
|
||||
const AsyncDependencyToInitialChunkError = require("./AsyncDependencyToInitialChunkError");
|
||||
const Chunk = require("./Chunk");
|
||||
const ChunkGraph = require("./ChunkGraph");
|
||||
const ChunkGroup = require("./ChunkGroup");
|
||||
const ChunkRenderError = require("./ChunkRenderError");
|
||||
const ChunkTemplate = require("./ChunkTemplate");
|
||||
|
@ -22,7 +23,6 @@ const DependencyTemplates = require("./DependencyTemplates");
|
|||
const EntryModuleNotFoundError = require("./EntryModuleNotFoundError");
|
||||
const Entrypoint = require("./Entrypoint");
|
||||
const {
|
||||
connectChunkAndModule,
|
||||
connectChunkGroupAndChunk,
|
||||
connectChunkGroupParentAndChild,
|
||||
connectDependenciesBlockAndChunkGroup
|
||||
|
@ -389,12 +389,14 @@ class Compilation {
|
|||
};
|
||||
|
||||
this.moduleGraph = new ModuleGraph();
|
||||
this.chunkGraph = undefined;
|
||||
|
||||
this.semaphore = new Semaphore(options.parallelism || 100);
|
||||
|
||||
this.entries = [];
|
||||
/** @private @type {{name: string, request: string, module: Module}[]} */
|
||||
this._preparedEntrypoints = [];
|
||||
/** @private @type {Map<string, Entrypoint>} */
|
||||
this.entrypoints = new Map();
|
||||
/** @type {Chunk[]} */
|
||||
this.chunks = [];
|
||||
|
@ -1121,6 +1123,9 @@ class Compilation {
|
|||
* @returns {void}
|
||||
*/
|
||||
seal(callback) {
|
||||
const chunkGraph = new ChunkGraph();
|
||||
this.chunkGraph = chunkGraph;
|
||||
|
||||
this.hooks.seal.call();
|
||||
|
||||
while (
|
||||
|
@ -1145,7 +1150,7 @@ class Compilation {
|
|||
this.chunkGroups.push(entrypoint);
|
||||
|
||||
connectChunkGroupAndChunk(entrypoint, chunk);
|
||||
connectChunkAndModule(chunk, module);
|
||||
chunkGraph.connectChunkAndModule(chunk, module);
|
||||
|
||||
chunk.entryModule = module;
|
||||
chunk.name = name;
|
||||
|
@ -1452,6 +1457,7 @@ class Compilation {
|
|||
|
||||
/** @type {Map<ChunkGroup, {block: AsyncDependenciesBlock, chunkGroup: ChunkGroup}[]>} */
|
||||
const chunkDependencies = new Map();
|
||||
/** @type {Set<ChunkGroup>} */
|
||||
const allCreatedChunkGroups = new Set();
|
||||
|
||||
// PREPARE
|
||||
|
@ -1525,6 +1531,8 @@ class Compilation {
|
|||
}
|
||||
}
|
||||
|
||||
const chunkGraph = this.chunkGraph;
|
||||
|
||||
// PART ONE
|
||||
|
||||
/** @type {Map<ChunkGroup, { index: number, index2: number }>} */
|
||||
|
@ -1644,9 +1652,7 @@ class Compilation {
|
|||
switch (queueItem.action) {
|
||||
case ADD_AND_ENTER_MODULE: {
|
||||
// We connect Module and Chunk when not already done
|
||||
if (chunk.addModule(module)) {
|
||||
module.addChunk(chunk);
|
||||
} else {
|
||||
if (!chunkGraph.connectChunkAndModule(chunk, module)) {
|
||||
// already connected, skip it
|
||||
break;
|
||||
}
|
||||
|
@ -1683,7 +1689,7 @@ class Compilation {
|
|||
// Traverse all referenced modules
|
||||
for (let i = blockInfo.modules.length - 1; i >= 0; i--) {
|
||||
const refModule = blockInfo.modules[i];
|
||||
if (chunk.containsModule(refModule)) {
|
||||
if (chunkGraph.isModuleInChunk(refModule, chunk)) {
|
||||
// skip early if already connected
|
||||
continue;
|
||||
}
|
||||
|
@ -1750,7 +1756,7 @@ class Compilation {
|
|||
*/
|
||||
const areModulesAvailable = (chunkGroup, availableModules) => {
|
||||
for (const chunk of chunkGroup.chunks) {
|
||||
for (const module of chunk.modulesIterable) {
|
||||
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
if (!availableModules.has(module)) return false;
|
||||
}
|
||||
}
|
||||
|
@ -1806,7 +1812,7 @@ class Compilation {
|
|||
// 3. Create a new Set of available modules at this points
|
||||
newAvailableModules = new Set(availableModules);
|
||||
for (const chunk of chunkGroup.chunks) {
|
||||
for (const m of chunk.modulesIterable) {
|
||||
for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
newAvailableModules.add(m);
|
||||
}
|
||||
}
|
||||
|
@ -1845,7 +1851,7 @@ class Compilation {
|
|||
for (const chunk of chunkGroup.chunks) {
|
||||
const idx = this.chunks.indexOf(chunk);
|
||||
if (idx >= 0) this.chunks.splice(idx, 1);
|
||||
chunk.remove("unconnected");
|
||||
chunkGraph.disconnectChunk(chunk);
|
||||
}
|
||||
chunkGroup.remove("unconnected");
|
||||
}
|
||||
|
@ -1859,12 +1865,13 @@ class Compilation {
|
|||
* @returns {void}
|
||||
*/
|
||||
removeReasonsOfDependencyBlock(module, block) {
|
||||
const chunkGraph = this.chunkGraph;
|
||||
const iteratorDependency = d => {
|
||||
if (!d.module) {
|
||||
return;
|
||||
}
|
||||
if (d.module.removeReason(module, d)) {
|
||||
for (const chunk of d.module.chunksIterable) {
|
||||
for (const chunk of chunkGraph.getModuleChunksIterable(d.module)) {
|
||||
this.patchChunksAfterReasonRemoval(d.module, chunk);
|
||||
}
|
||||
}
|
||||
|
@ -1890,8 +1897,9 @@ class Compilation {
|
|||
if (!module.hasReasons(this.moduleGraph)) {
|
||||
this.removeReasonsOfDependencyBlock(module, module);
|
||||
}
|
||||
if (!module.hasReasonForChunk(chunk, this.moduleGraph)) {
|
||||
if (module.removeChunk(chunk)) {
|
||||
if (!module.hasReasonForChunk(chunk, this.moduleGraph, this.chunkGraph)) {
|
||||
if (this.chunkGraph.isModuleInChunk(module, chunk)) {
|
||||
this.chunkGraph.disconnectChunkAndModule(chunk, module);
|
||||
this.removeChunkFromDependencies(module, chunk);
|
||||
}
|
||||
}
|
||||
|
@ -1932,6 +1940,8 @@ class Compilation {
|
|||
}
|
||||
|
||||
applyModuleIds() {
|
||||
const chunkGraph = this.chunkGraph;
|
||||
|
||||
const unusedIds = [];
|
||||
let nextFreeModuleId = 0;
|
||||
const usedIds = new Set();
|
||||
|
@ -1972,7 +1982,7 @@ class Compilation {
|
|||
for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) {
|
||||
const module2 = modules2[indexModule2];
|
||||
// Module that are not in any chunk don't need ids
|
||||
if (module2.getNumberOfChunks() === 0) continue;
|
||||
if (chunkGraph.getNumberOfModuleChunks(module2) === 0) continue;
|
||||
if (module2.id === null) {
|
||||
if (unusedIds.length > 0) {
|
||||
module2.id = unusedIds.pop();
|
||||
|
@ -2048,16 +2058,6 @@ class Compilation {
|
|||
|
||||
sortItemsWithModuleIds() {
|
||||
this.modules.sort(byIdOrIdentifier);
|
||||
|
||||
const modules = this.modules;
|
||||
for (let indexModule = 0; indexModule < modules.length; indexModule++) {
|
||||
modules[indexModule].sortItems(false);
|
||||
}
|
||||
|
||||
const chunks = this.chunks;
|
||||
for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
|
||||
chunks[indexChunk].sortItems();
|
||||
}
|
||||
}
|
||||
|
||||
sortItemsWithChunkIds() {
|
||||
|
@ -2067,19 +2067,6 @@ class Compilation {
|
|||
|
||||
this.chunks.sort(byId);
|
||||
|
||||
for (
|
||||
let indexModule = 0;
|
||||
indexModule < this.modules.length;
|
||||
indexModule++
|
||||
) {
|
||||
this.modules[indexModule].sortItems(true);
|
||||
}
|
||||
|
||||
const chunks = this.chunks;
|
||||
for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
|
||||
chunks[indexChunk].sortItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to sort errors and warnings in compilation. this.warnings, and
|
||||
* this.errors contribute to the compilation hash and therefore should be
|
||||
|
@ -2202,7 +2189,7 @@ class Compilation {
|
|||
if (outputOptions.hashSalt) {
|
||||
chunkHash.update(outputOptions.hashSalt);
|
||||
}
|
||||
chunk.updateHash(chunkHash);
|
||||
chunk.updateHash(chunkHash, this.chunkGraph);
|
||||
const template = chunk.hasRuntime()
|
||||
? this.mainTemplate
|
||||
: this.chunkTemplate;
|
||||
|
|
|
@ -93,17 +93,6 @@ class DependenciesBlock {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts items in this module
|
||||
* @param {boolean=} sortChunks sort the chunks too
|
||||
* @returns {void}
|
||||
*/
|
||||
sortItems(sortChunks) {
|
||||
for (const block of this.blocks) {
|
||||
block.sortItems();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DependenciesBlock;
|
||||
|
|
|
@ -24,11 +24,12 @@ class FlagInitialModulesAsUsedPlugin {
|
|||
compilation.hooks.afterOptimizeChunks.tap(
|
||||
"FlagInitialModulesAsUsedPlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
for (const chunk of chunks) {
|
||||
if (!chunk.isOnlyInitial()) {
|
||||
return;
|
||||
}
|
||||
for (const module of chunk.modulesIterable) {
|
||||
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
module.setUsedExports(moduleGraph, true);
|
||||
moduleGraph.addExtraReason(module, this.explanation);
|
||||
}
|
||||
|
|
|
@ -33,27 +33,6 @@ const connectChunkGroupParentAndChild = (parent, child) => {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk Chunk to connect to Module
|
||||
* @param {Module} module Module to connect to Chunk
|
||||
* @returns {void}
|
||||
*/
|
||||
const connectChunkAndModule = (chunk, module) => {
|
||||
if (module.addChunk(chunk)) {
|
||||
chunk.addModule(module);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk Chunk being disconnected
|
||||
* @param {Module} module Module being disconnected
|
||||
* @returns {void}
|
||||
*/
|
||||
const disconnectChunkAndModule = (chunk, module) => {
|
||||
chunk.removeModule(module);
|
||||
module.removeChunk(chunk);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {AsyncDependenciesBlock} depBlock DepBlock being tied to ChunkGroup
|
||||
* @param {ChunkGroup} chunkGroup ChunkGroup being tied to DepBlock
|
||||
|
@ -67,6 +46,4 @@ const connectDependenciesBlockAndChunkGroup = (depBlock, chunkGroup) => {
|
|||
|
||||
exports.connectChunkGroupAndChunk = connectChunkGroupAndChunk;
|
||||
exports.connectChunkGroupParentAndChild = connectChunkGroupParentAndChild;
|
||||
exports.connectChunkAndModule = connectChunkAndModule;
|
||||
exports.disconnectChunkAndModule = disconnectChunkAndModule;
|
||||
exports.connectDependenciesBlockAndChunkGroup = connectDependenciesBlockAndChunkGroup;
|
||||
|
|
|
@ -20,6 +20,7 @@ const Template = require("./Template");
|
|||
const ConstDependency = require("./dependencies/ConstDependency");
|
||||
const ModuleHotAcceptDependency = require("./dependencies/ModuleHotAcceptDependency");
|
||||
const ModuleHotDeclineDependency = require("./dependencies/ModuleHotDeclineDependency");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
@ -205,6 +206,7 @@ module.exports = class HotModuleReplacementPlugin {
|
|||
"HotModuleReplacementPlugin",
|
||||
(compilation, records) => {
|
||||
if (records.hash === compilation.hash) return;
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
records.hash = compilation.hash;
|
||||
records.moduleHashs = {};
|
||||
for (const module of compilation.modules) {
|
||||
|
@ -218,7 +220,10 @@ module.exports = class HotModuleReplacementPlugin {
|
|||
records.chunkModuleIds = {};
|
||||
for (const chunk of compilation.chunks) {
|
||||
records.chunkModuleIds[chunk.id] = Array.from(
|
||||
chunk.modulesIterable,
|
||||
chunkGraph.getOrderedChunkModulesIterable(
|
||||
chunk,
|
||||
compareModulesById
|
||||
),
|
||||
m => m.id
|
||||
);
|
||||
}
|
||||
|
@ -259,6 +264,7 @@ module.exports = class HotModuleReplacementPlugin {
|
|||
compilation.hooks.additionalChunkAssets.tap(
|
||||
"HotModuleReplacementPlugin",
|
||||
() => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const records = compilation.records;
|
||||
if (records.hash === compilation.hash) return;
|
||||
if (
|
||||
|
@ -286,12 +292,14 @@ module.exports = class HotModuleReplacementPlugin {
|
|||
chunk => chunk.id === chunkId
|
||||
);
|
||||
if (currentChunk) {
|
||||
const newModules = currentChunk
|
||||
.getModules()
|
||||
const newModules = chunkGraph
|
||||
.getChunkModules(currentChunk)
|
||||
.filter(module => updatedModules.has(module));
|
||||
/** @type {Set<number|string>} */
|
||||
const allModules = new Set();
|
||||
for (const module of currentChunk.modulesIterable) {
|
||||
for (const module of chunkGraph.getChunkModulesIterable(
|
||||
currentChunk
|
||||
)) {
|
||||
allModules.add(module.id);
|
||||
}
|
||||
const removedModules = records.chunkModuleIds[chunkId].filter(
|
||||
|
@ -300,14 +308,15 @@ module.exports = class HotModuleReplacementPlugin {
|
|||
if (newModules.length > 0 || removedModules.length > 0) {
|
||||
const hotUpdateChunk = new HotUpdateChunk();
|
||||
hotUpdateChunk.id = chunkId;
|
||||
hotUpdateChunk.setModules(newModules);
|
||||
chunkGraph.attachModules(hotUpdateChunk, newModules);
|
||||
hotUpdateChunk.removedModules = removedModules;
|
||||
const source = hotUpdateChunkTemplate.render(
|
||||
{
|
||||
chunk: hotUpdateChunk,
|
||||
dependencyTemplates: compilation.dependencyTemplates,
|
||||
runtimeTemplate: compilation.runtimeTemplate,
|
||||
moduleGraph: compilation.moduleGraph
|
||||
moduleGraph: compilation.moduleGraph,
|
||||
chunkGraph: compilation.chunkGraph
|
||||
},
|
||||
compilation.moduleTemplates.javascript,
|
||||
compilation.hash
|
||||
|
|
|
@ -11,6 +11,7 @@ const Compilation = require("./Compilation");
|
|||
const JavascriptGenerator = require("./JavascriptGenerator");
|
||||
const JavascriptParser = require("./JavascriptParser");
|
||||
const Template = require("./Template");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
const createHash = require("./util/createHash");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
|
@ -126,7 +127,8 @@ class JavascriptModulesPlugin {
|
|||
chunk,
|
||||
dependencyTemplates,
|
||||
runtimeTemplate: compilation.runtimeTemplate,
|
||||
moduleGraph: compilation.moduleGraph
|
||||
moduleGraph: compilation.moduleGraph,
|
||||
chunkGraph: compilation.chunkGraph
|
||||
},
|
||||
m => typeof m.source === "function",
|
||||
moduleTemplate,
|
||||
|
@ -160,7 +162,8 @@ class JavascriptModulesPlugin {
|
|||
chunk,
|
||||
dependencyTemplates,
|
||||
runtimeTemplate: compilation.runtimeTemplate,
|
||||
moduleGraph: compilation.moduleGraph
|
||||
moduleGraph: compilation.moduleGraph,
|
||||
chunkGraph: compilation.chunkGraph
|
||||
}
|
||||
),
|
||||
filenameTemplate,
|
||||
|
@ -176,20 +179,25 @@ class JavascriptModulesPlugin {
|
|||
}
|
||||
);
|
||||
compilation.hooks.contentHash.tap("JavascriptModulesPlugin", chunk => {
|
||||
const outputOptions = compilation.outputOptions;
|
||||
const {
|
||||
hashSalt,
|
||||
hashDigest,
|
||||
hashDigestLength,
|
||||
hashFunction
|
||||
} = outputOptions;
|
||||
chunkGraph,
|
||||
outputOptions: {
|
||||
hashSalt,
|
||||
hashDigest,
|
||||
hashDigestLength,
|
||||
hashFunction
|
||||
}
|
||||
} = compilation;
|
||||
const hash = createHash(hashFunction);
|
||||
if (hashSalt) hash.update(hashSalt);
|
||||
const template = chunk.hasRuntime()
|
||||
? compilation.mainTemplate
|
||||
: compilation.chunkTemplate;
|
||||
template.updateHashForChunk(hash, chunk);
|
||||
for (const m of chunk.modulesIterable) {
|
||||
for (const m of chunkGraph.getOrderedChunkModulesIterable(
|
||||
chunk,
|
||||
compareModulesById
|
||||
)) {
|
||||
if (typeof m.source === "function") {
|
||||
hash.update(m.hash);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
const asyncLib = require("neo-async");
|
||||
const path = require("path");
|
||||
const SingleEntryDependency = require("./dependencies/SingleEntryDependency");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
|
||||
class LibManifestPlugin {
|
||||
constructor(options) {
|
||||
|
@ -25,6 +26,7 @@ class LibManifestPlugin {
|
|||
callback();
|
||||
return;
|
||||
}
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const targetPath = compilation.getPath(this.options.path, {
|
||||
hash: compilation.hash,
|
||||
chunk
|
||||
|
@ -38,28 +40,34 @@ class LibManifestPlugin {
|
|||
const manifest = {
|
||||
name,
|
||||
type: this.options.type,
|
||||
content: Array.from(chunk.modulesIterable, module => {
|
||||
if (
|
||||
this.options.entryOnly &&
|
||||
!compilation.moduleGraph
|
||||
.getIncomingConnections(module)
|
||||
.some(c => c.dependency instanceof SingleEntryDependency)
|
||||
) {
|
||||
return;
|
||||
content: Array.from(
|
||||
chunkGraph.getOrderedChunkModulesIterable(
|
||||
chunk,
|
||||
compareModulesById
|
||||
),
|
||||
module => {
|
||||
if (
|
||||
this.options.entryOnly &&
|
||||
!compilation.moduleGraph
|
||||
.getIncomingConnections(module)
|
||||
.some(c => c.dependency instanceof SingleEntryDependency)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const ident = module.libIdent({
|
||||
context: this.options.context || compiler.options.context
|
||||
});
|
||||
if (ident) {
|
||||
return {
|
||||
ident,
|
||||
data: {
|
||||
id: module.id,
|
||||
buildMeta: module.buildMeta
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
const ident = module.libIdent({
|
||||
context: this.options.context || compiler.options.context
|
||||
});
|
||||
if (ident) {
|
||||
return {
|
||||
ident,
|
||||
data: {
|
||||
id: module.id,
|
||||
buildMeta: module.buildMeta
|
||||
}
|
||||
};
|
||||
}
|
||||
})
|
||||
)
|
||||
.filter(Boolean)
|
||||
.reduce((obj, item) => {
|
||||
obj[item.ident] = item.data;
|
||||
|
|
139
lib/Module.js
139
lib/Module.js
|
@ -7,10 +7,10 @@
|
|||
|
||||
const DependenciesBlock = require("./DependenciesBlock");
|
||||
const Template = require("./Template");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("./ChunkGroup")} ChunkGroup */
|
||||
/** @typedef {import("./Compilation")} Compilation */
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
|
@ -19,6 +19,7 @@ const SortableSet = require("./util/SortableSet");
|
|||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
/** @template T @typedef {import("./util/SortableSet")<T>} SortableSet<T> */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
/**
|
||||
|
@ -26,6 +27,7 @@ const SortableSet = require("./util/SortableSet");
|
|||
* @property {DependencyTemplates} dependencyTemplates the dependency templates
|
||||
* @property {RuntimeTemplate} runtimeTemplate the runtime template
|
||||
* @property {ModuleGraph} moduleGraph the module graph
|
||||
* @property {ChunkGraph} chunkGraph the chunk graph
|
||||
* @property {string=} type the type of source that should be generated
|
||||
*/
|
||||
|
||||
|
@ -49,14 +51,6 @@ const issuerSymbol = Symbol("issuer");
|
|||
|
||||
let debugId = 1000;
|
||||
|
||||
const sortById = (a, b) => {
|
||||
return a.id - b.id;
|
||||
};
|
||||
|
||||
const sortByDebugId = (a, b) => {
|
||||
return a.debugId - b.debugId;
|
||||
};
|
||||
|
||||
const getIndexMap = set => {
|
||||
set.sort();
|
||||
const map = new Map();
|
||||
|
@ -108,10 +102,6 @@ class Module extends DependenciesBlock {
|
|||
/** @type {object} */
|
||||
this.buildInfo = undefined;
|
||||
|
||||
// Graph (per Compilation)
|
||||
/** @type {SortableSet<Chunk>} */
|
||||
this._chunks = new SortableSet(undefined, sortById);
|
||||
|
||||
// Info from Compilation (per Compilation)
|
||||
/** @type {number|string} */
|
||||
this.id = null;
|
||||
|
@ -211,8 +201,6 @@ class Module extends DependenciesBlock {
|
|||
this.hash = undefined;
|
||||
this.renderedHash = undefined;
|
||||
|
||||
this._chunks.clear();
|
||||
|
||||
this.id = null;
|
||||
this.index = null;
|
||||
this.index2 = null;
|
||||
|
@ -232,60 +220,9 @@ class Module extends DependenciesBlock {
|
|||
this.index = null;
|
||||
this.index2 = null;
|
||||
this.depth = null;
|
||||
this._chunks.clear();
|
||||
super.unseal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chunks to a new value
|
||||
* @protected
|
||||
* @param {Iterable<Chunk>} chunks the new chunks
|
||||
* @returns {void}
|
||||
*/
|
||||
setChunks(chunks) {
|
||||
this._chunks = new SortableSet(chunks, sortById);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk added chunk
|
||||
* @returns {boolean} true, if the chunk could be added
|
||||
*/
|
||||
addChunk(chunk) {
|
||||
if (this._chunks.has(chunk)) return false;
|
||||
this._chunks.add(chunk);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk removed chunk
|
||||
* @returns {boolean} true, if the chunk could be removed
|
||||
*/
|
||||
removeChunk(chunk) {
|
||||
if (this._chunks.delete(chunk)) {
|
||||
chunk.removeModule(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk chunk to be tested
|
||||
* @returns {boolean} true, if the module is in a chunk
|
||||
*/
|
||||
isInChunk(chunk) {
|
||||
return this._chunks.has(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean} true, if the module is entry of any chunk
|
||||
*/
|
||||
isEntryModule() {
|
||||
for (const chunk of this._chunks) {
|
||||
if (chunk.entryModule === this) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @returns {boolean} true, if the module is optional
|
||||
|
@ -299,64 +236,26 @@ class Module extends DependenciesBlock {
|
|||
}
|
||||
|
||||
/**
|
||||
* @returns {Chunk[]} all chunks which contain the module
|
||||
*/
|
||||
getChunks() {
|
||||
return Array.from(this._chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number} the number of chunk which contain the module
|
||||
*/
|
||||
getNumberOfChunks() {
|
||||
return this._chunks.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Iterable<Chunk>} chunks that contain the module
|
||||
*/
|
||||
get chunksIterable() {
|
||||
return this._chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} otherModule some other module
|
||||
* @returns {boolean} true, if modules are in the same chunks
|
||||
*/
|
||||
hasEqualChunks(otherModule) {
|
||||
if (this._chunks.size !== otherModule._chunks.size) return false;
|
||||
this._chunks.sortWith(sortByDebugId);
|
||||
otherModule._chunks.sortWith(sortByDebugId);
|
||||
const a = this._chunks[Symbol.iterator]();
|
||||
const b = otherModule._chunks[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const aItem = a.next();
|
||||
const bItem = b.next();
|
||||
if (aItem.done) return true;
|
||||
if (aItem.value !== bItem.value) return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @param {Chunk} chunk a chunk
|
||||
* @param {Chunk=} ignoreChunk chunk to be ignored
|
||||
* @returns {boolean} true, if the module is accessible from "chunk" when ignoring "ignoreChunk"
|
||||
*/
|
||||
isAccessibleInChunk(chunk, ignoreChunk) {
|
||||
isAccessibleInChunk(chunkGraph, chunk, ignoreChunk) {
|
||||
// Check if module is accessible in ALL chunk groups
|
||||
for (const chunkGroup of chunk.groupsIterable) {
|
||||
if (!this.isAccessibleInChunkGroup(chunkGroup)) return false;
|
||||
if (!this.isAccessibleInChunkGroup(chunkGraph, chunkGroup)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @param {ChunkGroup} chunkGroup a chunk group
|
||||
* @param {Chunk=} ignoreChunk chunk to be ignored
|
||||
* @returns {boolean} true, if the module is accessible from "chunkGroup" when ignoring "ignoreChunk"
|
||||
*/
|
||||
isAccessibleInChunkGroup(chunkGroup, ignoreChunk) {
|
||||
isAccessibleInChunkGroup(chunkGraph, chunkGroup, ignoreChunk) {
|
||||
const queue = new Set([chunkGroup]);
|
||||
|
||||
// Check if module is accessible from all items of the queue
|
||||
|
@ -364,7 +263,7 @@ class Module extends DependenciesBlock {
|
|||
// 1. If module is in one of the chunks of the group we can continue checking the next items
|
||||
// because it's accessible.
|
||||
for (const chunk of cg.chunks) {
|
||||
if (chunk !== ignoreChunk && chunk.containsModule(this))
|
||||
if (chunk !== ignoreChunk && chunkGraph.isModuleInChunk(this, chunk))
|
||||
continue queueFor;
|
||||
}
|
||||
// 2. If the chunk group is initial, we can break here because it's not accessible.
|
||||
|
@ -379,15 +278,19 @@ class Module extends DependenciesBlock {
|
|||
/**
|
||||
* @param {Chunk} chunk a chunk
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @returns {boolean} true, if the module has any reason why "chunk" should be included
|
||||
*/
|
||||
hasReasonForChunk(chunk, moduleGraph) {
|
||||
hasReasonForChunk(chunk, moduleGraph, chunkGraph) {
|
||||
// check for each reason if we need the chunk
|
||||
for (const connection of moduleGraph.getIncomingConnections(this)) {
|
||||
const fromModule = connection.originModule;
|
||||
for (const originChunk of fromModule.chunksIterable) {
|
||||
for (const originChunk of chunkGraph.getModuleChunksIterable(
|
||||
fromModule
|
||||
)) {
|
||||
// return true if module this is not reachable from originChunk when ignoring cunk
|
||||
if (!this.isAccessibleInChunk(originChunk, chunk)) return true;
|
||||
if (!this.isAccessibleInChunk(chunkGraph, originChunk, chunk))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -499,16 +402,6 @@ class Module extends DependenciesBlock {
|
|||
super.updateHash(hash, compilation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts items in this module
|
||||
* @param {boolean=} sortChunks sort the chunks too
|
||||
* @returns {void}
|
||||
*/
|
||||
sortItems(sortChunks) {
|
||||
super.sortItems();
|
||||
if (sortChunks) this._chunks.sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,7 @@ const { SyncWaterfallHook, SyncHook } = require("tapable");
|
|||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./ModuleGraph")} ModuleGraph */
|
||||
|
@ -20,6 +21,7 @@ const { SyncWaterfallHook, SyncHook } = require("tapable");
|
|||
* @property {DependencyTemplates} dependencyTemplates the dependency templates
|
||||
* @property {RuntimeTemplate} runtimeTemplate the runtime template
|
||||
* @property {ModuleGraph} moduleGraph the module graph
|
||||
* @property {ChunkGraph} chunkGraph the chunk graph
|
||||
*/
|
||||
|
||||
module.exports = class ModuleTemplate {
|
||||
|
@ -46,11 +48,17 @@ module.exports = class ModuleTemplate {
|
|||
*/
|
||||
render(module, ctx) {
|
||||
try {
|
||||
const { runtimeTemplate, dependencyTemplates, moduleGraph } = ctx;
|
||||
const {
|
||||
runtimeTemplate,
|
||||
dependencyTemplates,
|
||||
moduleGraph,
|
||||
chunkGraph
|
||||
} = ctx;
|
||||
const moduleSource = module.source({
|
||||
dependencyTemplates,
|
||||
runtimeTemplate,
|
||||
moduleGraph,
|
||||
chunkGraph,
|
||||
type: this.type
|
||||
});
|
||||
const moduleSourcePostContent = this.hooks.content.call(
|
||||
|
|
|
@ -19,7 +19,10 @@ class NamedChunksPlugin {
|
|||
compilation.hooks.beforeChunkIds.tap("NamedChunksPlugin", chunks => {
|
||||
for (const chunk of chunks) {
|
||||
if (chunk.id === null) {
|
||||
chunk.id = this.nameResolver(chunk);
|
||||
chunk.id = this.nameResolver(chunk, {
|
||||
moduleGraph: compilation.moduleGraph,
|
||||
chunkGraph: compilation.chunkGraph
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
54
lib/Stats.js
54
lib/Stats.js
|
@ -10,8 +10,12 @@ const { formatSize } = require("./SizeFormatHelpers");
|
|||
const compareLocations = require("./compareLocations");
|
||||
const formatLocation = require("./formatLocation");
|
||||
const AggressiveSplittingPlugin = require("./optimize/AggressiveSplittingPlugin");
|
||||
const SizeLimitsPlugin = require("./performance/SizeLimitsPlugin");
|
||||
const { compareChunksById, compareIds } = require("./util/comparators");
|
||||
const identifierUtils = require("./util/identifier");
|
||||
|
||||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./ChunkGroup")} ChunkGroup */
|
||||
/** @typedef {import("./Compilation")} Compilation */
|
||||
|
||||
const optionsOrFallback = (...args) => {
|
||||
|
@ -20,12 +24,6 @@ const optionsOrFallback = (...args) => {
|
|||
return optionValues.find(optionValue => typeof optionValue !== "undefined");
|
||||
};
|
||||
|
||||
const compareId = (a, b) => {
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
class Stats {
|
||||
/**
|
||||
* @param {Compilation} compilation webpack compilation
|
||||
|
@ -142,6 +140,7 @@ class Stats {
|
|||
|
||||
const compilation = this.compilation;
|
||||
const moduleGraph = compilation.moduleGraph;
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const context = optionsOrFallback(
|
||||
options.context,
|
||||
compilation.compiler.context
|
||||
|
@ -231,7 +230,9 @@ class Stats {
|
|||
|
||||
if (!showOrphanModules) {
|
||||
excludeModules.push((ident, module, type) => {
|
||||
return module.getNumberOfChunks() === 0 && type !== "nested";
|
||||
return (
|
||||
chunkGraph.getNumberOfModuleChunks(module) === 0 && type !== "nested"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -416,7 +417,9 @@ class Stats {
|
|||
};
|
||||
|
||||
if (showPerformance) {
|
||||
obj.isOverSizeLimit = compilation.assets[asset].isOverSizeLimit;
|
||||
obj.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(
|
||||
compilation.assets[asset]
|
||||
);
|
||||
}
|
||||
|
||||
assetsByFile[asset] = obj;
|
||||
|
@ -447,12 +450,16 @@ class Stats {
|
|||
obj.assets.sort(sortByField(sortAssets));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Map<string, ChunkGroup>} groupMap map from name to chunk group
|
||||
* @returns {Object} chunk group stats object
|
||||
*/
|
||||
const fnChunkGroup = groupMap => {
|
||||
const obj = {};
|
||||
for (const keyValuePair of groupMap) {
|
||||
const name = keyValuePair[0];
|
||||
const cg = keyValuePair[1];
|
||||
const children = cg.getChildrenByOrders();
|
||||
const children = cg.getChildrenByOrders(chunkGraph);
|
||||
obj[name] = {
|
||||
chunks: cg.chunks.map(c => c.id),
|
||||
assets: cg.chunks.reduce(
|
||||
|
@ -487,7 +494,7 @@ class Stats {
|
|||
}, Object.create(null))
|
||||
};
|
||||
if (showPerformance) {
|
||||
obj[name].isOverSizeLimit = cg.isOverSizeLimit;
|
||||
obj[name].isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(cg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,7 +529,10 @@ class Stats {
|
|||
built: !!module.built,
|
||||
optional: module.isOptional(moduleGraph),
|
||||
prefetched: module.prefetched,
|
||||
chunks: Array.from(module.chunksIterable, chunk => chunk.id),
|
||||
chunks: Array.from(
|
||||
chunkGraph.getOrderedModuleChunksIterable(module, compareChunksById),
|
||||
chunk => chunk.id
|
||||
),
|
||||
issuer: issuer && issuer.identifier(),
|
||||
issuerId: issuer && issuer.id,
|
||||
issuerName: issuer && issuer.readableIdentifier(requestShortener),
|
||||
|
@ -540,7 +550,7 @@ class Stats {
|
|||
warnings: module.warnings ? module.warnings.length : 0
|
||||
};
|
||||
if (showOrphanModules && !nested) {
|
||||
obj.orphan = module.getNumberOfChunks() === 0;
|
||||
obj.orphan = chunkGraph.getNumberOfModuleChunks(module) === 0;
|
||||
}
|
||||
if (showModuleAssets) {
|
||||
obj.assets = Object.keys(module.buildInfo.assets || {});
|
||||
|
@ -552,7 +562,7 @@ class Stats {
|
|||
if (a.originModule && !b.originModule) return -1;
|
||||
if (!a.originModule && b.originModule) return 1;
|
||||
if (a.originModule && b.originModule) {
|
||||
const cmp = compareId(a.originModule.id, b.originModule.id);
|
||||
const cmp = compareIds(a.originModule.id, b.originModule.id);
|
||||
if (cmp) return cmp;
|
||||
}
|
||||
if (a.dependency && !b.dependency) return -1;
|
||||
|
@ -641,7 +651,7 @@ class Stats {
|
|||
const parents = new Set();
|
||||
const children = new Set();
|
||||
const siblings = new Set();
|
||||
const childIdByOrder = chunk.getChildIdsByOrders();
|
||||
const childIdByOrder = chunk.getChildIdsByOrders(chunkGraph);
|
||||
for (const chunkGroup of chunk.groupsIterable) {
|
||||
for (const parentGroup of chunkGroup.parentsIterable) {
|
||||
for (const chunk of parentGroup.chunks) {
|
||||
|
@ -664,22 +674,24 @@ class Stats {
|
|||
entry: chunk.hasRuntime(),
|
||||
recorded: AggressiveSplittingPlugin.wasChunkRecorded(chunk),
|
||||
reason: chunk.chunkReason,
|
||||
size: chunk.modulesSize(),
|
||||
size: chunkGraph.getChunkModulesSize(chunk),
|
||||
names: chunk.name ? [chunk.name] : [],
|
||||
files: chunk.files.slice(),
|
||||
hash: chunk.renderedHash,
|
||||
siblings: Array.from(siblings).sort(compareId),
|
||||
parents: Array.from(parents).sort(compareId),
|
||||
children: Array.from(children).sort(compareId),
|
||||
siblings: Array.from(siblings).sort(compareIds),
|
||||
parents: Array.from(parents).sort(compareIds),
|
||||
children: Array.from(children).sort(compareIds),
|
||||
childrenByOrder: childIdByOrder
|
||||
};
|
||||
if (showChunkModules) {
|
||||
obj.modules = chunk
|
||||
.getModules()
|
||||
obj.modules = chunkGraph
|
||||
.getChunkModules(chunk)
|
||||
.slice()
|
||||
.sort(sortByField("depth"))
|
||||
.filter(createModuleFilter("chunk"))
|
||||
.map(m => fnModule(m));
|
||||
obj.filteredModules = chunk.getNumberOfModules() - obj.modules.length;
|
||||
obj.filteredModules =
|
||||
chunkGraph.getNumberOfChunkModules(chunk) - obj.modules.length;
|
||||
obj.modules.sort(sortByField(sortModules));
|
||||
}
|
||||
if (showChunkOrigins) {
|
||||
|
|
|
@ -217,9 +217,9 @@ class Template {
|
|||
moduleTemplate,
|
||||
prefix = ""
|
||||
) {
|
||||
const chunk = renderContext.chunk;
|
||||
const { chunk, chunkGraph } = renderContext;
|
||||
var source = new ConcatSource();
|
||||
const modules = chunk.getModules().filter(filterFn);
|
||||
const modules = chunkGraph.getChunkModules(chunk).filter(filterFn);
|
||||
let removedModules;
|
||||
if (chunk instanceof HotUpdateChunk) {
|
||||
removedModules = chunk.removedModules;
|
||||
|
|
|
@ -95,15 +95,18 @@ class UmdMainTemplatePlugin {
|
|||
* @returns {Source} new source
|
||||
*/
|
||||
const onRenderWithEntry = (source, chunk, hash) => {
|
||||
/** @type {ExternalModule[]} */
|
||||
let externals = /** @type {ExternalModule[]} */ (chunk
|
||||
.getModules()
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const modules = chunkGraph
|
||||
.getChunkModules(chunk)
|
||||
.filter(
|
||||
m =>
|
||||
m instanceof ExternalModule &&
|
||||
(m.externalType === "umd" || m.externalType === "umd2")
|
||||
));
|
||||
);
|
||||
let externals = /** @type {ExternalModule[]} */ (modules);
|
||||
/** @type {ExternalModule[]} */
|
||||
const optionalExternals = [];
|
||||
/** @type {ExternalModule[]} */
|
||||
let requiredExternals = [];
|
||||
if (this.optionalAmdExternalAsGlobal) {
|
||||
for (const m of externals) {
|
||||
|
|
|
@ -45,7 +45,7 @@ class ReadFileCompileWasmTemplatePlugin {
|
|||
]);
|
||||
|
||||
const plugin = new WasmMainTemplatePlugin(
|
||||
compilation.moduleGraph,
|
||||
compilation,
|
||||
Object.assign(
|
||||
{
|
||||
generateLoadBinaryCode,
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class AggressiveMergingPlugin {
|
||||
constructor(options) {
|
||||
if (
|
||||
|
@ -18,6 +21,10 @@ class AggressiveMergingPlugin {
|
|||
this.options = options || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Compiler} compiler webpack compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
const minSizeReduce = options.minSizeReduce || 1.5;
|
||||
|
@ -28,43 +35,35 @@ class AggressiveMergingPlugin {
|
|||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"AggressiveMergingPlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
/** @type {{a: Chunk, b: Chunk, improvement: number}[]} */
|
||||
let combinations = [];
|
||||
chunks.forEach((a, idx) => {
|
||||
if (a.canBeInitial()) return;
|
||||
for (let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
if (b.canBeInitial()) continue;
|
||||
if (!chunkGraph.canChunksBeIntegrated(a, b)) {
|
||||
continue;
|
||||
}
|
||||
const aSize = chunkGraph.getChunkSize(b, {
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const bSize = chunkGraph.getChunkSize(a, {
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const abSize = chunkGraph.getIntegratedChunksSize(b, a, {
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const improvement = (aSize + bSize) / abSize;
|
||||
combinations.push({
|
||||
a,
|
||||
b,
|
||||
improvement: undefined
|
||||
improvement
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (const pair of combinations) {
|
||||
const a = pair.b.size({
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const b = pair.a.size({
|
||||
chunkOverhead: 0
|
||||
});
|
||||
const ab = pair.b.integratedSize(pair.a, {
|
||||
chunkOverhead: 0
|
||||
});
|
||||
let newSize;
|
||||
if (ab === false) {
|
||||
pair.improvement = false;
|
||||
return;
|
||||
} else {
|
||||
newSize = ab;
|
||||
}
|
||||
|
||||
pair.improvement = (a + b) / newSize;
|
||||
}
|
||||
combinations = combinations.filter(pair => {
|
||||
return pair.improvement !== false;
|
||||
});
|
||||
combinations.sort((a, b) => {
|
||||
return b.improvement - a.improvement;
|
||||
});
|
||||
|
@ -74,10 +73,9 @@ class AggressiveMergingPlugin {
|
|||
if (!pair) return;
|
||||
if (pair.improvement < minSizeReduce) return;
|
||||
|
||||
if (pair.b.integrate(pair.a, "aggressive-merge")) {
|
||||
chunks.splice(chunks.indexOf(pair.a), 1);
|
||||
return true;
|
||||
}
|
||||
chunkGraph.integrateChunks(pair.b, pair.a);
|
||||
chunks.splice(chunks.indexOf(pair.a), 1);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,13 +8,16 @@
|
|||
const validateOptions = require("schema-utils");
|
||||
const schema = require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json");
|
||||
const { intersect } = require("../util/SetHelpers");
|
||||
const { compareModulesById } = require("../util/comparators");
|
||||
const identifierUtils = require("../util/identifier");
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
const moveModuleBetween = (oldChunk, newChunk) => {
|
||||
const moveModuleBetween = (chunkGraph, oldChunk, newChunk) => {
|
||||
return module => {
|
||||
oldChunk.moveModule(module, newChunk);
|
||||
chunkGraph.disconnectChunkAndModule(oldChunk, module);
|
||||
chunkGraph.connectChunkAndModule(newChunk, module);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -54,6 +57,10 @@ class AggressiveSplittingPlugin {
|
|||
return recordedChunks.has(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Compiler} compiler webpack compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap(
|
||||
"AggressiveSplittingPlugin",
|
||||
|
@ -70,6 +77,7 @@ class AggressiveSplittingPlugin {
|
|||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"AggressiveSplittingPlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
// Precompute stuff
|
||||
const nameToModuleMap = new Map();
|
||||
const moduleToNameMap = new Map();
|
||||
|
@ -122,7 +130,9 @@ class AggressiveSplittingPlugin {
|
|||
|
||||
// get chunks with all modules
|
||||
const selectedChunks = intersect(
|
||||
selectedModules.map(m => new Set(m.chunksIterable))
|
||||
selectedModules.map(
|
||||
m => new Set(chunkGraph.getModuleChunksIterable(m))
|
||||
)
|
||||
);
|
||||
|
||||
// No relevant chunks found
|
||||
|
@ -131,8 +141,9 @@ class AggressiveSplittingPlugin {
|
|||
// The found chunk is already the split or similar
|
||||
if (
|
||||
selectedChunks.size === 1 &&
|
||||
Array.from(selectedChunks)[0].getNumberOfModules() ===
|
||||
selectedModules.length
|
||||
chunkGraph.getNumberOfChunkModules(
|
||||
Array.from(selectedChunks)[0]
|
||||
) === selectedModules.length
|
||||
) {
|
||||
const chunk = Array.from(selectedChunks)[0];
|
||||
if (fromAggressiveSplittingSet.has(chunk)) return false;
|
||||
|
@ -145,7 +156,9 @@ class AggressiveSplittingPlugin {
|
|||
const newChunk = compilation.addChunk();
|
||||
newChunk.chunkReason = "aggressive splitted";
|
||||
for (const chunk of selectedChunks) {
|
||||
selectedModules.forEach(moveModuleBetween(chunk, newChunk));
|
||||
selectedModules.forEach(
|
||||
moveModuleBetween(chunkGraph, chunk, newChunk)
|
||||
);
|
||||
chunk.split(newChunk);
|
||||
chunk.name = null;
|
||||
}
|
||||
|
@ -168,14 +181,20 @@ class AggressiveSplittingPlugin {
|
|||
// for any chunk which isn't splitted yet, split it and create a new entry
|
||||
// start with the biggest chunk
|
||||
const sortedChunks = chunks.slice().sort((a, b) => {
|
||||
const diff1 = b.modulesSize() - a.modulesSize();
|
||||
const diff1 =
|
||||
chunkGraph.getChunkModulesSize(b) -
|
||||
chunkGraph.getChunkModulesSize(a);
|
||||
if (diff1) return diff1;
|
||||
const diff2 = a.getNumberOfModules() - b.getNumberOfModules();
|
||||
const diff2 =
|
||||
chunkGraph.getNumberOfChunkModules(a) -
|
||||
chunkGraph.getNumberOfChunkModules(b);
|
||||
if (diff2) return diff2;
|
||||
const modulesA = Array.from(a.modulesIterable);
|
||||
const modulesB = Array.from(b.modulesIterable);
|
||||
modulesA.sort();
|
||||
modulesB.sort();
|
||||
const modulesA = Array.from(
|
||||
chunkGraph.getOrderedChunkModulesIterable(a, compareModulesById)
|
||||
);
|
||||
const modulesB = Array.from(
|
||||
chunkGraph.getOrderedChunkModulesIterable(b, compareModulesById)
|
||||
);
|
||||
const aI = modulesA[Symbol.iterator]();
|
||||
const bI = modulesB[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
|
@ -191,16 +210,19 @@ class AggressiveSplittingPlugin {
|
|||
});
|
||||
for (const chunk of sortedChunks) {
|
||||
if (fromAggressiveSplittingSet.has(chunk)) continue;
|
||||
const size = chunk.modulesSize();
|
||||
if (size > maxSize && chunk.getNumberOfModules() > 1) {
|
||||
const modules = chunk
|
||||
.getModules()
|
||||
const size = chunkGraph.getChunkModulesSize(chunk);
|
||||
if (
|
||||
size > maxSize &&
|
||||
chunkGraph.getNumberOfChunkModules(chunk) > 1
|
||||
) {
|
||||
const modules = chunkGraph
|
||||
.getChunkModules(chunk)
|
||||
.filter(isNotAEntryModule(chunk.entryModule))
|
||||
.sort((a, b) => {
|
||||
a = a.identifier();
|
||||
b = b.identifier();
|
||||
if (a > b) return 1;
|
||||
if (a < b) return -1;
|
||||
const aIdentifer = a.identifier();
|
||||
const bIdentifer = b.identifier();
|
||||
if (aIdentifer > bIdentifer) return 1;
|
||||
if (aIdentifer < bIdentifer) return -1;
|
||||
return 0;
|
||||
});
|
||||
const selectedModules = [];
|
||||
|
|
|
@ -5,23 +5,27 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const sortByIndex = (a, b) => {
|
||||
return a.index - b.index;
|
||||
};
|
||||
const {
|
||||
compareModulesByIndex,
|
||||
compareModulesByIndex2
|
||||
} = require("../util/comparators");
|
||||
|
||||
const sortByIndex2 = (a, b) => {
|
||||
return a.index2 - b.index2;
|
||||
};
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class ChunkModuleIdRangePlugin {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Compiler} compiler webpack compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
compiler.hooks.compilation.tap("ChunkModuleIdRangePlugin", compilation => {
|
||||
compilation.hooks.moduleIds.tap("ChunkModuleIdRangePlugin", modules => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const chunk = compilation.chunks.find(
|
||||
chunk => chunk.name === options.name
|
||||
);
|
||||
|
@ -35,22 +39,23 @@ class ChunkModuleIdRangePlugin {
|
|||
|
||||
let chunkModules;
|
||||
if (options.order) {
|
||||
chunkModules = Array.from(chunk.modulesIterable);
|
||||
let cmpFn;
|
||||
switch (options.order) {
|
||||
case "index":
|
||||
chunkModules.sort(sortByIndex);
|
||||
cmpFn = compareModulesByIndex;
|
||||
break;
|
||||
case "index2":
|
||||
chunkModules.sort(sortByIndex2);
|
||||
cmpFn = compareModulesByIndex2;
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
"ChunkModuleIdRangePlugin: unexpected value of order"
|
||||
);
|
||||
}
|
||||
chunkModules = chunkGraph.getOrderedChunkModules(chunk, cmpFn);
|
||||
} else {
|
||||
chunkModules = modules.filter(m => {
|
||||
return m.chunksIterable.has(chunk);
|
||||
return chunkGraph.isModuleInChunk(m, chunk);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -310,7 +310,6 @@ class ConcatenatedModule extends Module {
|
|||
*/
|
||||
constructor(rootModule, modules, compilation) {
|
||||
super("javascript/esm", null);
|
||||
super.setChunks(rootModule._chunks);
|
||||
|
||||
const moduleGraph = compilation.moduleGraph;
|
||||
|
||||
|
@ -542,7 +541,7 @@ class ConcatenatedModule extends Module {
|
|||
* @param {SourceContext} sourceContext source context
|
||||
* @returns {Source} generated source
|
||||
*/
|
||||
source({ dependencyTemplates, runtimeTemplate, moduleGraph }) {
|
||||
source({ dependencyTemplates, runtimeTemplate, moduleGraph, chunkGraph }) {
|
||||
const requestShortener = runtimeTemplate.requestShortener;
|
||||
// Metainfo for each module
|
||||
const modulesWithInfo = this._orderedConcatenationList.map((info, idx) => {
|
||||
|
@ -699,7 +698,8 @@ class ConcatenatedModule extends Module {
|
|||
const source = m.source({
|
||||
dependencyTemplates: innerDependencyTemplates,
|
||||
runtimeTemplate,
|
||||
moduleGraph
|
||||
moduleGraph,
|
||||
chunkGraph
|
||||
});
|
||||
const code = source.source();
|
||||
let ast;
|
||||
|
|
|
@ -5,24 +5,20 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
connectChunkAndModule,
|
||||
disconnectChunkAndModule
|
||||
} = require("../GraphHelpers");
|
||||
|
||||
class EnsureChunkConditionsPlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
"EnsureChunkConditionsPlugin",
|
||||
compilation => {
|
||||
const handler = chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
let changed = false;
|
||||
// These sets are hoisted here to save memory
|
||||
// They are cleared at the end of every loop
|
||||
const sourceChunks = new Set();
|
||||
const chunkGroups = new Set();
|
||||
for (const module of compilation.modules) {
|
||||
for (const chunk of module.chunksIterable) {
|
||||
for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
|
||||
if (!module.chunkCondition(chunk)) {
|
||||
sourceChunks.add(chunk);
|
||||
for (const group of chunk.groupsIterable) {
|
||||
|
@ -52,10 +48,10 @@ class EnsureChunkConditionsPlugin {
|
|||
}
|
||||
}
|
||||
for (const sourceChunk of sourceChunks) {
|
||||
disconnectChunkAndModule(sourceChunk, module);
|
||||
chunkGraph.disconnectChunkAndModule(sourceChunk, module);
|
||||
}
|
||||
for (const targetChunk of targetChunks) {
|
||||
connectChunkAndModule(targetChunk, module);
|
||||
chunkGraph.connectChunkAndModule(targetChunk, module);
|
||||
}
|
||||
sourceChunks.clear();
|
||||
chunkGroups.clear();
|
||||
|
|
|
@ -11,6 +11,8 @@ class FlagIncludedChunksPlugin {
|
|||
compilation.hooks.optimizeChunkIds.tap(
|
||||
"FlagIncludedChunksPlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
|
||||
// prepare two bit integers for each module
|
||||
// 2^31 is the max number represented as SMI in v8
|
||||
// we want the bits distributed this way:
|
||||
|
@ -47,7 +49,7 @@ class FlagIncludedChunksPlugin {
|
|||
const chunkModulesHash = new WeakMap();
|
||||
for (const chunk of chunks) {
|
||||
let hash = 0;
|
||||
for (const module of chunk.modulesIterable) {
|
||||
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
hash |= moduleBits.get(module);
|
||||
}
|
||||
chunkModulesHash.set(chunk, hash);
|
||||
|
@ -55,22 +57,29 @@ class FlagIncludedChunksPlugin {
|
|||
|
||||
for (const chunkA of chunks) {
|
||||
const chunkAHash = chunkModulesHash.get(chunkA);
|
||||
const chunkAModulesCount = chunkA.getNumberOfModules();
|
||||
const chunkAModulesCount = chunkGraph.getNumberOfChunkModules(
|
||||
chunkA
|
||||
);
|
||||
if (chunkAModulesCount === 0) continue;
|
||||
let bestModule = undefined;
|
||||
for (const module of chunkA.modulesIterable) {
|
||||
for (const module of chunkGraph.getChunkModulesIterable(chunkA)) {
|
||||
if (
|
||||
bestModule === undefined ||
|
||||
bestModule.getNumberOfChunks() > module.getNumberOfChunks()
|
||||
chunkGraph.getNumberOfModuleChunks(bestModule) >
|
||||
chunkGraph.getNumberOfModuleChunks(module)
|
||||
)
|
||||
bestModule = module;
|
||||
}
|
||||
loopB: for (const chunkB of bestModule.chunksIterable) {
|
||||
loopB: for (const chunkB of chunkGraph.getModuleChunksIterable(
|
||||
bestModule
|
||||
)) {
|
||||
// as we iterate the same iterables twice
|
||||
// skip if we find ourselves
|
||||
if (chunkA === chunkB) continue;
|
||||
|
||||
const chunkBModulesCount = chunkB.getNumberOfModules();
|
||||
const chunkBModulesCount = chunkGraph.getNumberOfChunkModules(
|
||||
chunkB
|
||||
);
|
||||
|
||||
// ids for empty chunks are not included
|
||||
if (chunkBModulesCount === 0) continue;
|
||||
|
@ -86,8 +95,8 @@ class FlagIncludedChunksPlugin {
|
|||
if ((chunkBHash & chunkAHash) !== chunkAHash) continue;
|
||||
|
||||
// compare all modules
|
||||
for (const m of chunkA.modulesIterable) {
|
||||
if (!chunkB.containsModule(m)) continue loopB;
|
||||
for (const m of chunkGraph.getChunkModulesIterable(chunkA)) {
|
||||
if (!chunkGraph.isModuleInChunk(m, chunkB)) continue loopB;
|
||||
}
|
||||
chunkB.ids.push(chunkA.id);
|
||||
}
|
||||
|
|
|
@ -8,42 +8,55 @@
|
|||
const validateOptions = require("schema-utils");
|
||||
const schema = require("../../schemas/plugins/optimize/LimitChunkCountPlugin.json");
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class LimitChunkCountPlugin {
|
||||
constructor(options) {
|
||||
validateOptions(schema, options || {}, "Limit Chunk Count Plugin");
|
||||
this.options = options || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Compiler} compiler webpack compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"LimitChunkCountPlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const maxChunks = options.maxChunks;
|
||||
if (!maxChunks) return;
|
||||
if (maxChunks < 1) return;
|
||||
if (chunks.length <= maxChunks) return;
|
||||
|
||||
const sortedExtendedPairCombinations = chunks
|
||||
.reduce((combinations, a, idx) => {
|
||||
.reduce((/** @type {[Chunk, Chunk][]} */ combinations, a, idx) => {
|
||||
// create combination pairs
|
||||
for (let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
combinations.push([b, a]);
|
||||
// filter pairs that can NOT be integrated!
|
||||
if (chunkGraph.canChunksBeIntegrated(b, a)) {
|
||||
combinations.push([b, a]);
|
||||
}
|
||||
}
|
||||
return combinations;
|
||||
}, [])
|
||||
.map(pair => {
|
||||
// extend combination pairs with size and integrated size
|
||||
const a = pair[0].size(options);
|
||||
const b = pair[1].size(options);
|
||||
const ab = pair[0].integratedSize(pair[1], options);
|
||||
return [a + b - ab, ab, pair[0], pair[1], a, b];
|
||||
})
|
||||
.filter(extendedPair => {
|
||||
// filter pairs that do not have an integratedSize
|
||||
// meaning they can NOT be integrated!
|
||||
return extendedPair[1] !== false;
|
||||
const a = chunkGraph.getChunkSize(pair[0], options);
|
||||
const b = chunkGraph.getChunkSize(pair[1], options);
|
||||
const ab = chunkGraph.getIntegratedChunksSize(
|
||||
pair[0],
|
||||
pair[1],
|
||||
options
|
||||
);
|
||||
/** @type {[number, number, Chunk, Chunk, number, number]} */
|
||||
const extendedPair = [a + b - ab, ab, pair[0], pair[1], a, b];
|
||||
return extendedPair;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// sadly javascript does an inplace sort here
|
||||
|
@ -55,7 +68,8 @@ class LimitChunkCountPlugin {
|
|||
|
||||
const pair = sortedExtendedPairCombinations[0];
|
||||
|
||||
if (pair && pair[2].integrate(pair[3], "limit")) {
|
||||
if (pair) {
|
||||
chunkGraph.integrateChunks(pair[2], pair[3]);
|
||||
chunks.splice(chunks.indexOf(pair[3]), 1);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class MergeDuplicateChunksPlugin {
|
||||
/**
|
||||
* @param {Compiler} compiler the compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
"MergeDuplicateChunksPlugin",
|
||||
|
@ -13,6 +19,8 @@ class MergeDuplicateChunksPlugin {
|
|||
compilation.hooks.optimizeChunksBasic.tap(
|
||||
"MergeDuplicateChunksPlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
|
||||
// remember already tested chunks for performance
|
||||
const notDuplicates = new Set();
|
||||
|
||||
|
@ -20,15 +28,18 @@ class MergeDuplicateChunksPlugin {
|
|||
for (const chunk of chunks) {
|
||||
// track a Set of all chunk that could be duplicates
|
||||
let possibleDuplicates;
|
||||
for (const module of chunk.modulesIterable) {
|
||||
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
if (possibleDuplicates === undefined) {
|
||||
// when possibleDuplicates is not yet set,
|
||||
// create a new Set from chunks of the current module
|
||||
// including only chunks with the same number of modules
|
||||
for (const dup of module.chunksIterable) {
|
||||
for (const dup of chunkGraph.getModuleChunksIterable(
|
||||
module
|
||||
)) {
|
||||
if (
|
||||
dup !== chunk &&
|
||||
chunk.getNumberOfModules() === dup.getNumberOfModules() &&
|
||||
chunkGraph.getNumberOfChunkModules(chunk) ===
|
||||
chunkGraph.getNumberOfChunkModules(dup) &&
|
||||
!notDuplicates.has(dup)
|
||||
) {
|
||||
// delay allocating the new Set until here, reduce memory pressure
|
||||
|
@ -44,7 +55,7 @@ class MergeDuplicateChunksPlugin {
|
|||
// validate existing possible duplicates
|
||||
for (const dup of possibleDuplicates) {
|
||||
// remove possible duplicate when module is not contained
|
||||
if (!dup.containsModule(module)) {
|
||||
if (!chunkGraph.isModuleInChunk(module, dup)) {
|
||||
possibleDuplicates.delete(dup);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +72,8 @@ class MergeDuplicateChunksPlugin {
|
|||
for (const otherChunk of possibleDuplicates) {
|
||||
if (otherChunk.hasRuntime() !== chunk.hasRuntime()) continue;
|
||||
// merge them
|
||||
if (chunk.integrate(otherChunk, "duplicate")) {
|
||||
if (chunkGraph.canChunksBeIntegrated(chunk, otherChunk)) {
|
||||
chunkGraph.integrateChunks(chunk, otherChunk);
|
||||
chunks.splice(chunks.indexOf(otherChunk), 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,19 @@
|
|||
const validateOptions = require("schema-utils");
|
||||
const schema = require("../../schemas/plugins/optimize/MinChunkSizePlugin.json");
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class MinChunkSizePlugin {
|
||||
constructor(options) {
|
||||
validateOptions(schema, options, "Min Chunk Size Plugin");
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Compiler} compiler webpack compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
const options = this.options;
|
||||
const minChunkSize = options.minChunkSize;
|
||||
|
@ -21,13 +28,14 @@ class MinChunkSizePlugin {
|
|||
compilation.hooks.optimizeChunksAdvanced.tap(
|
||||
"MinChunkSizePlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const equalOptions = {
|
||||
chunkOverhead: 1,
|
||||
entryChunkMultiplicator: 1
|
||||
};
|
||||
|
||||
const sortedSizeFilteredExtendedPairCombinations = chunks
|
||||
.reduce((combinations, a, idx) => {
|
||||
.reduce((/** @type {[Chunk, Chunk][]} */ combinations, a, idx) => {
|
||||
// create combination pairs
|
||||
for (let i = 0; i < idx; i++) {
|
||||
const b = chunks[i];
|
||||
|
@ -38,22 +46,26 @@ class MinChunkSizePlugin {
|
|||
.filter(pair => {
|
||||
// check if one of the chunks sizes is smaller than the minChunkSize
|
||||
const p0SmallerThanMinChunkSize =
|
||||
pair[0].size(equalOptions) < minChunkSize;
|
||||
chunkGraph.getChunkSize(pair[0], equalOptions) < minChunkSize;
|
||||
const p1SmallerThanMinChunkSize =
|
||||
pair[1].size(equalOptions) < minChunkSize;
|
||||
return p0SmallerThanMinChunkSize || p1SmallerThanMinChunkSize;
|
||||
chunkGraph.getChunkSize(pair[1], equalOptions) < minChunkSize;
|
||||
if (!p0SmallerThanMinChunkSize && !p1SmallerThanMinChunkSize)
|
||||
return false;
|
||||
// filter pairs that can NOT be integrated!
|
||||
return chunkGraph.canChunksBeIntegrated(pair[0], pair[1]);
|
||||
})
|
||||
.map(pair => {
|
||||
// extend combination pairs with size and integrated size
|
||||
const a = pair[0].size(options);
|
||||
const b = pair[1].size(options);
|
||||
const ab = pair[0].integratedSize(pair[1], options);
|
||||
return [a + b - ab, ab, pair[0], pair[1]];
|
||||
})
|
||||
.filter(pair => {
|
||||
// filter pairs that do not have an integratedSize
|
||||
// meaning they can NOT be integrated!
|
||||
return pair[1] !== false;
|
||||
const a = chunkGraph.getChunkSize(pair[0], options);
|
||||
const b = chunkGraph.getChunkSize(pair[1], options);
|
||||
const ab = chunkGraph.getIntegratedChunksSize(
|
||||
pair[0],
|
||||
pair[1],
|
||||
options
|
||||
);
|
||||
/** @type {[number, number, Chunk, Chunk]} */
|
||||
const extendedPair = [a + b - ab, ab, pair[0], pair[1]];
|
||||
return extendedPair;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// sadly javascript does an inplace sort here
|
||||
|
@ -67,7 +79,7 @@ class MinChunkSizePlugin {
|
|||
|
||||
const pair = sortedSizeFilteredExtendedPairCombinations[0];
|
||||
|
||||
pair[2].integrate(pair[3], "min-size");
|
||||
chunkGraph.integrateChunks(pair[2], pair[3]);
|
||||
chunks.splice(chunks.indexOf(pair[3]), 1);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ class ModuleConcatenationPlugin {
|
|||
compilation.hooks.optimizeChunkModules.tap(
|
||||
"ModuleConcatenationPlugin",
|
||||
(chunks, modules) => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const relevantModules = [];
|
||||
const possibleInners = new Set();
|
||||
for (const module of modules) {
|
||||
|
@ -147,7 +148,7 @@ class ModuleConcatenationPlugin {
|
|||
}
|
||||
|
||||
// Module must be in any chunk (we don't want to do useless work)
|
||||
if (module.getNumberOfChunks() === 0) {
|
||||
if (chunkGraph.getNumberOfModuleChunks(module) === 0) {
|
||||
setBailoutReason(module, "Module is not in any chunk");
|
||||
continue;
|
||||
}
|
||||
|
@ -155,7 +156,7 @@ class ModuleConcatenationPlugin {
|
|||
relevantModules.push(module);
|
||||
|
||||
// Module must not be the entry points
|
||||
if (module.isEntryModule()) {
|
||||
if (chunkGraph.isEntryModule(module)) {
|
||||
setInnerBailoutReason(module, "Module is an entry point");
|
||||
continue;
|
||||
}
|
||||
|
@ -235,7 +236,10 @@ class ModuleConcatenationPlugin {
|
|||
connection => {
|
||||
return (
|
||||
connection.originModule &&
|
||||
!connection.originModule.hasEqualChunks(module)
|
||||
!chunkGraph.haveModulesEqualChunks(
|
||||
connection.originModule,
|
||||
module
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -328,13 +332,13 @@ class ModuleConcatenationPlugin {
|
|||
.getOptimizationBailout(moduleGraph)
|
||||
.push(formatBailoutWarning(warning[0], warning[1]));
|
||||
}
|
||||
const chunks = concatConfiguration.rootModule.getChunks();
|
||||
const chunks = chunkGraph.getModuleChunks(
|
||||
concatConfiguration.rootModule
|
||||
);
|
||||
for (const m of modules) {
|
||||
usedModules.add(m);
|
||||
// remove module from chunk
|
||||
for (const chunk of chunks) {
|
||||
chunk.removeModule(m);
|
||||
}
|
||||
chunkGraph.replaceModule(m, newModule);
|
||||
// replace module references with the concatenated module
|
||||
moduleGraph.replaceModule(m, newModule, c => {
|
||||
return !(
|
||||
|
@ -346,8 +350,6 @@ class ModuleConcatenationPlugin {
|
|||
}
|
||||
// add concatenated module to the chunks
|
||||
for (const chunk of chunks) {
|
||||
chunk.addModule(newModule);
|
||||
newModule.addChunk(chunk);
|
||||
if (chunk.entryModule === concatConfiguration.rootModule) {
|
||||
chunk.entryModule = newModule;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { compareModulesById } = require("../util/comparators");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class NaturalChunkOrderPlugin {
|
||||
|
@ -17,9 +19,14 @@ class NaturalChunkOrderPlugin {
|
|||
compilation.hooks.optimizeChunkOrder.tap(
|
||||
"NaturalChunkOrderPlugin",
|
||||
chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
chunks.sort((chunkA, chunkB) => {
|
||||
const a = chunkA.modulesIterable[Symbol.iterator]();
|
||||
const b = chunkB.modulesIterable[Symbol.iterator]();
|
||||
const a = chunkGraph
|
||||
.getOrderedChunkModulesIterable(chunkA, compareModulesById)
|
||||
[Symbol.iterator]();
|
||||
const b = chunkGraph
|
||||
.getOrderedChunkModulesIterable(chunkB, compareModulesById)
|
||||
[Symbol.iterator]();
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const aItem = a.next();
|
||||
|
|
|
@ -30,6 +30,8 @@ class OccurrenceOrderModuleIdsPlugin {
|
|||
compilation.hooks.optimizeModuleOrder.tap(
|
||||
"OccurrenceOrderModuleIdsPlugin",
|
||||
modules => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
|
||||
const occursInInitialChunksMap = new Map();
|
||||
const occursInAllChunksMap = new Map();
|
||||
|
||||
|
@ -38,7 +40,7 @@ class OccurrenceOrderModuleIdsPlugin {
|
|||
for (const m of modules) {
|
||||
let initial = 0;
|
||||
let entry = 0;
|
||||
for (const c of m.chunksIterable) {
|
||||
for (const c of chunkGraph.getModuleChunksIterable(m)) {
|
||||
if (c.canBeInitial()) initial++;
|
||||
if (c.entryModule === m) entry++;
|
||||
}
|
||||
|
@ -71,7 +73,10 @@ class OccurrenceOrderModuleIdsPlugin {
|
|||
if (factor === 0) {
|
||||
return sum;
|
||||
}
|
||||
return sum + factor * c.originModule.getNumberOfChunks();
|
||||
return (
|
||||
sum +
|
||||
factor * chunkGraph.getNumberOfModuleChunks(c.originModule)
|
||||
);
|
||||
};
|
||||
|
||||
if (prioritiseInitial) {
|
||||
|
@ -91,7 +96,7 @@ class OccurrenceOrderModuleIdsPlugin {
|
|||
for (const m of modules) {
|
||||
const result =
|
||||
moduleGraph.getIncomingConnections(m).reduce(countOccurs, 0) +
|
||||
m.getNumberOfChunks() +
|
||||
chunkGraph.getNumberOfModuleChunks(m) +
|
||||
entryCountMap.get(m);
|
||||
occursInAllChunksMap.set(m, result);
|
||||
originalOrder.set(m, i++);
|
||||
|
|
|
@ -5,18 +5,30 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class RemoveEmptyChunksPlugin {
|
||||
/**
|
||||
* @param {Compiler} compiler webpack compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("RemoveEmptyChunksPlugin", compilation => {
|
||||
/**
|
||||
* @param {Chunk[]} chunks the chunks array
|
||||
* @returns {void}
|
||||
*/
|
||||
const handler = chunks => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
for (let i = chunks.length - 1; i >= 0; i--) {
|
||||
const chunk = chunks[i];
|
||||
if (
|
||||
chunk.isEmpty() &&
|
||||
chunkGraph.getNumberOfChunkModules(chunk) === 0 &&
|
||||
!chunk.hasRuntime() &&
|
||||
!chunk.hasEntryModule()
|
||||
) {
|
||||
chunk.remove("empty");
|
||||
compilation.chunkGraph.disconnectChunk(chunk);
|
||||
chunks.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,17 @@
|
|||
const Queue = require("../util/Queue");
|
||||
const { intersect } = require("../util/SetHelpers");
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
||||
class RemoveParentModulesPlugin {
|
||||
/**
|
||||
* @param {Compiler} compiler the compiler
|
||||
* @returns {void}
|
||||
*/
|
||||
apply(compiler) {
|
||||
compiler.hooks.compilation.tap("RemoveParentModulesPlugin", compilation => {
|
||||
const handler = (chunks, chunkGroups) => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const queue = new Queue();
|
||||
const availableModulesMap = new WeakMap();
|
||||
|
||||
|
@ -35,7 +42,7 @@ class RemoveParentModulesPlugin {
|
|||
// if we have not own info yet: create new entry
|
||||
availableModules = new Set(availableModulesInParent);
|
||||
for (const chunk of parent.chunks) {
|
||||
for (const m of chunk.modulesIterable) {
|
||||
for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
availableModules.add(m);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +51,7 @@ class RemoveParentModulesPlugin {
|
|||
} else {
|
||||
for (const m of availableModules) {
|
||||
if (
|
||||
!parent.containsModule(m) &&
|
||||
!chunkGraph.isModuleInChunkGroup(m, parent) &&
|
||||
!availableModulesInParent.has(m)
|
||||
) {
|
||||
availableModules.delete(m);
|
||||
|
@ -73,23 +80,23 @@ class RemoveParentModulesPlugin {
|
|||
availableModulesSets.length === 1
|
||||
? availableModulesSets[0]
|
||||
: intersect(availableModulesSets);
|
||||
const numberOfModules = chunk.getNumberOfModules();
|
||||
const numberOfModules = chunkGraph.getNumberOfChunkModules(chunk);
|
||||
const toRemove = new Set();
|
||||
if (numberOfModules < availableModules.size) {
|
||||
for (const m of chunk.modulesIterable) {
|
||||
for (const m of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
if (availableModules.has(m)) {
|
||||
toRemove.add(m);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const m of availableModules) {
|
||||
if (chunk.containsModule(m)) {
|
||||
if (chunkGraph.isModuleInChunk(m, chunk)) {
|
||||
toRemove.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const module of toRemove) {
|
||||
chunk.removeModule(module);
|
||||
chunkGraph.disconnectChunkAndModule(chunk, module);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -18,6 +18,7 @@ module.exports = class RuntimeChunkPlugin {
|
|||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap("RuntimeChunkPlugin", compilation => {
|
||||
compilation.hooks.optimizeChunksAdvanced.tap("RuntimeChunkPlugin", () => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
for (const entrypoint of compilation.entrypoints.values()) {
|
||||
const chunk = entrypoint.getRuntimeChunk();
|
||||
let name = this.options.name;
|
||||
|
@ -25,7 +26,7 @@ module.exports = class RuntimeChunkPlugin {
|
|||
name = name(entrypoint);
|
||||
}
|
||||
if (
|
||||
chunk.getNumberOfModules() > 0 ||
|
||||
chunkGraph.getNumberOfChunkModules(chunk) > 0 ||
|
||||
!chunk.preventIntegration ||
|
||||
chunk.name !== name
|
||||
) {
|
||||
|
|
|
@ -6,17 +6,18 @@
|
|||
"use strict";
|
||||
|
||||
const crypto = require("crypto");
|
||||
const { connectChunkAndModule } = require("../GraphHelpers");
|
||||
const { isSubset } = require("../util/SetHelpers");
|
||||
const SortableSet = require("../util/SortableSet");
|
||||
const deterministicGrouping = require("../util/deterministicGrouping");
|
||||
const contextify = require("../util/identifier").contextify;
|
||||
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("../util/deterministicGrouping").Options<Module>} DeterministicGroupingOptionsForModule */
|
||||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("../util/deterministicGrouping").GroupedItems<Module>} DeterministicGroupingGroupedItemsForModule */
|
||||
/** @typedef {import("../util/deterministicGrouping").Options<Module>} DeterministicGroupingOptionsForModule */
|
||||
|
||||
const deterministicGroupingForModules = /** @type {function(DeterministicGroupingOptionsForModule): DeterministicGroupingGroupedItemsForModule[]} */ (deterministicGrouping);
|
||||
|
||||
|
@ -216,7 +217,7 @@ module.exports = class SplitChunksPlugin {
|
|||
return cacheGroups;
|
||||
}
|
||||
if (cacheGroups && typeof cacheGroups === "object") {
|
||||
const fn = module => {
|
||||
const fn = (module, context) => {
|
||||
let results;
|
||||
for (const key of Object.keys(cacheGroups)) {
|
||||
let option = cacheGroups[key];
|
||||
|
@ -241,7 +242,9 @@ module.exports = class SplitChunksPlugin {
|
|||
results.push(result);
|
||||
}
|
||||
}
|
||||
} else if (SplitChunksPlugin.checkTest(option.test, module)) {
|
||||
} else if (
|
||||
SplitChunksPlugin.checkTest(option.test, module, context)
|
||||
) {
|
||||
if (results === undefined) results = [];
|
||||
results.push({
|
||||
key: key,
|
||||
|
@ -277,13 +280,22 @@ module.exports = class SplitChunksPlugin {
|
|||
return fn;
|
||||
}
|
||||
|
||||
static checkTest(test, module) {
|
||||
/**
|
||||
* @typedef {Object} TestContext
|
||||
* @property {ModuleGraph} moduleGraph the module graph
|
||||
* @property {ChunkGraph} chunkGraph the chunk graph
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {undefined|boolean|string|RegExp|function(Module, TestContext): boolean} test test option
|
||||
* @param {Module} module the module
|
||||
* @param {TestContext} context context object
|
||||
* @returns {boolean} true, if the module should be selected
|
||||
*/
|
||||
static checkTest(test, module, context) {
|
||||
if (test === undefined) return true;
|
||||
if (typeof test === "function") {
|
||||
if (test.length !== 1) {
|
||||
return test(module, module.getChunks());
|
||||
}
|
||||
return test(module);
|
||||
return test(module, context);
|
||||
}
|
||||
if (typeof test === "boolean") return test;
|
||||
if (typeof test === "string") {
|
||||
|
@ -291,7 +303,7 @@ module.exports = class SplitChunksPlugin {
|
|||
if (name && name.startsWith(test)) {
|
||||
return true;
|
||||
}
|
||||
for (const chunk of module.chunksIterable) {
|
||||
for (const chunk of context.chunkGraph.getModuleChunksIterable(module)) {
|
||||
if (chunk.name && chunk.name.startsWith(test)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -303,7 +315,7 @@ module.exports = class SplitChunksPlugin {
|
|||
if (name && test.test(name)) {
|
||||
return true;
|
||||
}
|
||||
for (const chunk of module.chunksIterable) {
|
||||
for (const chunk of context.chunkGraph.getModuleChunksIterable(module)) {
|
||||
if (chunk.name && test.test(chunk.name)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -328,6 +340,8 @@ module.exports = class SplitChunksPlugin {
|
|||
chunks => {
|
||||
if (alreadyOptimized) return;
|
||||
alreadyOptimized = true;
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const moduleGraph = compilation.moduleGraph;
|
||||
// Give each selected chunk an index (to create strings from chunks)
|
||||
const indexMap = new Map();
|
||||
let index = 1;
|
||||
|
@ -342,9 +356,14 @@ module.exports = class SplitChunksPlugin {
|
|||
/** @type {Map<string, Set<Chunk>>} */
|
||||
const chunkSetsInGraph = new Map();
|
||||
for (const module of compilation.modules) {
|
||||
const chunksKey = getKey(module.chunksIterable);
|
||||
const chunksKey = getKey(
|
||||
chunkGraph.getModuleChunksIterable(module)
|
||||
);
|
||||
if (!chunkSetsInGraph.has(chunksKey)) {
|
||||
chunkSetsInGraph.set(chunksKey, new Set(module.chunksIterable));
|
||||
chunkSetsInGraph.set(
|
||||
chunksKey,
|
||||
new Set(chunkGraph.getModuleChunksIterable(module))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -503,16 +522,23 @@ module.exports = class SplitChunksPlugin {
|
|||
}
|
||||
};
|
||||
|
||||
const context = {
|
||||
moduleGraph,
|
||||
chunkGraph
|
||||
};
|
||||
|
||||
// Walk through all modules
|
||||
for (const module of compilation.modules) {
|
||||
// Get cache group
|
||||
let cacheGroups = this.options.getCacheGroups(module);
|
||||
let cacheGroups = this.options.getCacheGroups(module, context);
|
||||
if (!Array.isArray(cacheGroups) || cacheGroups.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prepare some values
|
||||
const chunksKey = getKey(module.chunksIterable);
|
||||
const chunksKey = getKey(
|
||||
chunkGraph.getModuleChunksIterable(module)
|
||||
);
|
||||
let combs = combinationsCache.get(chunksKey);
|
||||
if (combs === undefined) {
|
||||
combs = getCombinations(chunksKey);
|
||||
|
@ -627,10 +653,15 @@ module.exports = class SplitChunksPlugin {
|
|||
let isReused = false;
|
||||
if (item.cacheGroup.reuseExistingChunk) {
|
||||
outer: for (const chunk of item.chunks) {
|
||||
if (chunk.getNumberOfModules() !== item.modules.size) continue;
|
||||
if (
|
||||
chunkGraph.getNumberOfChunkModules(chunk) !==
|
||||
item.modules.size
|
||||
)
|
||||
continue;
|
||||
if (chunk.hasEntryModule()) continue;
|
||||
for (const module of item.modules) {
|
||||
if (!chunk.containsModule(module)) continue outer;
|
||||
if (!chunkGraph.isModuleInChunk(module, chunk))
|
||||
continue outer;
|
||||
}
|
||||
if (!newChunk || !newChunk.name) {
|
||||
newChunk = chunk;
|
||||
|
@ -730,17 +761,17 @@ module.exports = class SplitChunksPlugin {
|
|||
for (const module of item.modules) {
|
||||
if (!module.chunkCondition(newChunk)) continue;
|
||||
// Add module to new chunk
|
||||
connectChunkAndModule(newChunk, module);
|
||||
chunkGraph.connectChunkAndModule(newChunk, module);
|
||||
// Remove module from used chunks
|
||||
for (const chunk of usedChunks) {
|
||||
chunk.removeModule(module);
|
||||
chunkGraph.disconnectChunkAndModule(chunk, module);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remove all modules from used chunks
|
||||
for (const module of item.modules) {
|
||||
for (const chunk of usedChunks) {
|
||||
chunk.removeModule(module);
|
||||
chunkGraph.disconnectChunkAndModule(chunk, module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -789,7 +820,7 @@ module.exports = class SplitChunksPlugin {
|
|||
const results = deterministicGroupingForModules({
|
||||
maxSize,
|
||||
minSize,
|
||||
items: chunk.modulesIterable,
|
||||
items: chunkGraph.getChunkModulesIterable(chunk),
|
||||
getKey(module) {
|
||||
const ident = contextify(
|
||||
compilation.options.context,
|
||||
|
@ -837,9 +868,9 @@ module.exports = class SplitChunksPlugin {
|
|||
for (const module of group.items) {
|
||||
if (!module.chunkCondition(newPart)) continue;
|
||||
// Add module to new chunk
|
||||
connectChunkAndModule(newPart, module);
|
||||
chunkGraph.connectChunkAndModule(newPart, module);
|
||||
// Remove module from used chunks
|
||||
chunk.removeModule(module);
|
||||
chunkGraph.disconnectChunkAndModule(chunk, module);
|
||||
}
|
||||
} else {
|
||||
// change the chunk to be a part
|
||||
|
|
|
@ -9,6 +9,8 @@ const AssetsOverSizeLimitWarning = require("./AssetsOverSizeLimitWarning");
|
|||
const EntrypointsOverSizeLimitWarning = require("./EntrypointsOverSizeLimitWarning");
|
||||
const NoAsyncChunksWarning = require("./NoAsyncChunksWarning");
|
||||
|
||||
const isOverSizeLimitSet = new WeakSet();
|
||||
|
||||
module.exports = class SizeLimitsPlugin {
|
||||
constructor(options) {
|
||||
this.hints = options.hints;
|
||||
|
@ -16,6 +18,11 @@ module.exports = class SizeLimitsPlugin {
|
|||
this.maxEntrypointSize = options.maxEntrypointSize;
|
||||
this.assetFilter = options.assetFilter;
|
||||
}
|
||||
|
||||
static isOverSizeLimit(thing) {
|
||||
return isOverSizeLimitSet.has(thing);
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
const entrypointSizeLimit = this.maxEntrypointSize;
|
||||
const assetSizeLimit = this.maxAssetSize;
|
||||
|
@ -47,7 +54,7 @@ module.exports = class SizeLimitsPlugin {
|
|||
name: assetName,
|
||||
size: size
|
||||
});
|
||||
asset.isOverSizeLimit = true;
|
||||
isOverSizeLimitSet.add(asset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +70,7 @@ module.exports = class SizeLimitsPlugin {
|
|||
size: size,
|
||||
files: entry.getFiles().filter(assetFilter)
|
||||
});
|
||||
entry.isOverSizeLimit = true;
|
||||
isOverSizeLimitSet.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
|
||||
/**
|
||||
* @param {Chunk} a chunk
|
||||
* @param {Chunk} b chunk
|
||||
* @returns {-1|0|1} compare result
|
||||
*/
|
||||
exports.compareChunksById = (a, b) => {
|
||||
return compareIds(a.id, b.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Module} a module
|
||||
* @param {Module} b module
|
||||
* @returns {-1|0|1} compare result
|
||||
*/
|
||||
exports.compareModulesById = (a, b) => {
|
||||
return compareIds(a.id, b.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} a number
|
||||
* @param {number} b number
|
||||
* @returns {-1|0|1} compare result
|
||||
*/
|
||||
const compareNumbers = (a, b) => {
|
||||
if (typeof a !== typeof b) {
|
||||
return typeof a < typeof b ? -1 : 1;
|
||||
}
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Module} a module
|
||||
* @param {Module} b module
|
||||
* @returns {-1|0|1} compare result
|
||||
*/
|
||||
exports.compareModulesByIndex = (a, b) => {
|
||||
return compareNumbers(a.index, b.index);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Module} a module
|
||||
* @param {Module} b module
|
||||
* @returns {-1|0|1} compare result
|
||||
*/
|
||||
exports.compareModulesByIndex2 = (a, b) => {
|
||||
return compareNumbers(a.index2, b.index2);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string|number} a first id
|
||||
* @param {string|number} b second id
|
||||
* @returns {-1|0|1} compare result
|
||||
*/
|
||||
const compareIds = (a, b) => {
|
||||
if (typeof a !== typeof b) {
|
||||
return typeof a < typeof b ? -1 : 1;
|
||||
}
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
exports.compareIds = compareIds;
|
|
@ -6,18 +6,24 @@
|
|||
"use strict";
|
||||
|
||||
const Template = require("../Template");
|
||||
const { compareModulesById } = require("../util/comparators");
|
||||
const WebAssemblyUtils = require("./WebAssemblyUtils");
|
||||
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
/** @typedef {import("../MainTemplate")} MainTemplate */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
|
||||
// Get all wasm modules
|
||||
const getAllWasmModules = chunk => {
|
||||
const getAllWasmModules = (chunkGraph, chunk) => {
|
||||
const wasmModules = chunk.getAllAsyncChunks();
|
||||
const array = [];
|
||||
for (const chunk of wasmModules) {
|
||||
for (const m of chunk.modulesIterable) {
|
||||
for (const m of chunkGraph.getOrderedChunkModulesIterable(
|
||||
chunk,
|
||||
compareModulesById
|
||||
)) {
|
||||
if (m.type.startsWith("webassembly")) {
|
||||
array.push(m);
|
||||
}
|
||||
|
@ -161,17 +167,17 @@ const generateImportObject = (moduleGraph, module, mangle) => {
|
|||
|
||||
class WasmMainTemplatePlugin {
|
||||
/**
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @param {Compilation} compilation the compilation
|
||||
* @param {Object} options options
|
||||
* @param {function(string): string} options.generateLoadBinaryCode function to generate the load code
|
||||
* @param {boolean=} options.supportsStreaming whether the generateLoadBinaryCode function supports streaming compilation
|
||||
* @param {boolean=} options.mangleImports whether imports should be mangled
|
||||
*/
|
||||
constructor(
|
||||
moduleGraph,
|
||||
compilation,
|
||||
{ generateLoadBinaryCode, supportsStreaming, mangleImports }
|
||||
) {
|
||||
this.moduleGraph = moduleGraph;
|
||||
this.compilation = compilation;
|
||||
this.generateLoadBinaryCode = generateLoadBinaryCode;
|
||||
this.supportsStreaming = supportsStreaming;
|
||||
this.mangleImports = mangleImports;
|
||||
|
@ -185,11 +191,14 @@ class WasmMainTemplatePlugin {
|
|||
mainTemplate.hooks.localVars.tap(
|
||||
"WasmMainTemplatePlugin",
|
||||
(source, chunk) => {
|
||||
const wasmModules = getAllWasmModules(chunk);
|
||||
const wasmModules = getAllWasmModules(
|
||||
this.compilation.chunkGraph,
|
||||
chunk
|
||||
);
|
||||
if (wasmModules.length === 0) return source;
|
||||
const importObjects = wasmModules.map(module => {
|
||||
return generateImportObject(
|
||||
this.moduleGraph,
|
||||
this.compilation.moduleGraph,
|
||||
module,
|
||||
this.mangleImports
|
||||
);
|
||||
|
@ -218,8 +227,9 @@ class WasmMainTemplatePlugin {
|
|||
const webassemblyModuleFilename =
|
||||
mainTemplate.outputOptions.webassemblyModuleFilename;
|
||||
|
||||
const chunkModuleMaps = chunk.getChunkModuleMaps(m =>
|
||||
m.type.startsWith("webassembly")
|
||||
const chunkModuleMaps = this.compilation.chunkGraph.getChunkModuleMaps(
|
||||
chunk,
|
||||
m => m.type.startsWith("webassembly")
|
||||
);
|
||||
if (Object.keys(chunkModuleMaps.id).length === 0) return source;
|
||||
const wasmModuleSrcPath = mainTemplate.getAssetPath(
|
||||
|
@ -342,7 +352,12 @@ class WasmMainTemplatePlugin {
|
|||
mainTemplate.hooks.requireExtensions.tap(
|
||||
"WasmMainTemplatePlugin",
|
||||
(source, chunk) => {
|
||||
if (!chunk.hasModuleInGraph(m => m.type.startsWith("webassembly"))) {
|
||||
const chunkGraph = this.compilation.chunkGraph;
|
||||
if (
|
||||
!chunkGraph.hasModuleInGraph(chunk, m =>
|
||||
m.type.startsWith("webassembly")
|
||||
)
|
||||
) {
|
||||
return source;
|
||||
}
|
||||
return Template.asString([
|
||||
|
@ -362,11 +377,15 @@ class WasmMainTemplatePlugin {
|
|||
mainTemplate.hooks.hashForChunk.tap(
|
||||
"WasmMainTemplatePlugin",
|
||||
(hash, chunk) => {
|
||||
const chunkModuleMaps = chunk.getChunkModuleMaps(m =>
|
||||
m.type.startsWith("webassembly")
|
||||
const chunkModuleMaps = this.compilation.chunkGraph.getChunkModuleMaps(
|
||||
chunk,
|
||||
m => m.type.startsWith("webassembly")
|
||||
);
|
||||
hash.update(JSON.stringify(chunkModuleMaps.id));
|
||||
const wasmModules = getAllWasmModules(chunk);
|
||||
const wasmModules = getAllWasmModules(
|
||||
this.compilation.chunkGraph,
|
||||
chunk
|
||||
);
|
||||
for (const module of wasmModules) {
|
||||
hash.update(module.hash);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
const WebpackError = require("../WebpackError");
|
||||
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("../RequestShortener")} RequestShortener */
|
||||
|
@ -13,10 +14,16 @@ const WebpackError = require("../WebpackError");
|
|||
/**
|
||||
* @param {Module} module module to get chains from
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @param {RequestShortener} requestShortener to make readable identifiers
|
||||
* @returns {string[]} all chains to the module
|
||||
*/
|
||||
const getInitialModuleChains = (module, moduleGraph, requestShortener) => {
|
||||
const getInitialModuleChains = (
|
||||
module,
|
||||
moduleGraph,
|
||||
chunkGraph,
|
||||
requestShortener
|
||||
) => {
|
||||
const queue = [
|
||||
{ head: module, message: module.readableIdentifier(requestShortener) }
|
||||
];
|
||||
|
@ -35,7 +42,8 @@ const getInitialModuleChains = (module, moduleGraph, requestShortener) => {
|
|||
for (const connection of moduleGraph.getIncomingConnections(head)) {
|
||||
const newHead = connection.originModule;
|
||||
if (newHead) {
|
||||
if (!newHead.getChunks().some(c => c.canBeInitial())) continue;
|
||||
if (!chunkGraph.getModuleChunks(newHead).some(c => c.canBeInitial()))
|
||||
continue;
|
||||
final = false;
|
||||
if (alreadyReferencedModules.has(newHead)) continue;
|
||||
alreadyReferencedModules.add(newHead);
|
||||
|
@ -75,12 +83,14 @@ module.exports = class WebAssemblyInInitialChunkError extends WebpackError {
|
|||
/**
|
||||
* @param {Module} module WASM module
|
||||
* @param {ModuleGraph} moduleGraph the module graph
|
||||
* @param {ChunkGraph} chunkGraph the chunk graph
|
||||
* @param {RequestShortener} requestShortener request shortener
|
||||
*/
|
||||
constructor(module, moduleGraph, requestShortener) {
|
||||
constructor(module, moduleGraph, chunkGraph, requestShortener) {
|
||||
const moduleChains = getInitialModuleChains(
|
||||
module,
|
||||
moduleGraph,
|
||||
chunkGraph,
|
||||
requestShortener
|
||||
);
|
||||
const message = `WebAssembly module is included in initial chunk.
|
||||
|
|
|
@ -9,6 +9,7 @@ const Generator = require("../Generator");
|
|||
const JavascriptModulesPlugin = require("../JavascriptModulesPlugin");
|
||||
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
|
||||
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
|
||||
const { compareModulesById } = require("../util/comparators");
|
||||
const WebAssemblyGenerator = require("./WebAssemblyGenerator");
|
||||
const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError");
|
||||
const WebAssemblyJavascriptGenerator = require("./WebAssemblyJavascriptGenerator");
|
||||
|
@ -66,12 +67,16 @@ class WebAssemblyModulesPlugin {
|
|||
compilation.chunkTemplate.hooks.renderManifest.tap(
|
||||
"WebAssemblyModulesPlugin",
|
||||
(result, options) => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const chunk = options.chunk;
|
||||
const outputOptions = options.outputOptions;
|
||||
const moduleTemplates = options.moduleTemplates;
|
||||
const dependencyTemplates = options.dependencyTemplates;
|
||||
|
||||
for (const module of chunk.modulesIterable) {
|
||||
for (const module of chunkGraph.getOrderedChunkModulesIterable(
|
||||
chunk,
|
||||
compareModulesById
|
||||
)) {
|
||||
if (module.type && module.type.startsWith("webassembly")) {
|
||||
const filenameTemplate =
|
||||
outputOptions.webassemblyModuleFilename;
|
||||
|
@ -85,7 +90,8 @@ class WebAssemblyModulesPlugin {
|
|||
chunk,
|
||||
dependencyTemplates,
|
||||
runtimeTemplate: compilation.runtimeTemplate,
|
||||
moduleGraph: compilation.moduleGraph
|
||||
moduleGraph: compilation.moduleGraph,
|
||||
chunkGraph: compilation.chunkGraph
|
||||
}
|
||||
),
|
||||
filenameTemplate,
|
||||
|
@ -103,10 +109,11 @@ class WebAssemblyModulesPlugin {
|
|||
);
|
||||
|
||||
compilation.hooks.afterChunks.tap("WebAssemblyModulesPlugin", () => {
|
||||
const chunkGraph = compilation.chunkGraph;
|
||||
const initialWasmModules = new Set();
|
||||
for (const chunk of compilation.chunks) {
|
||||
if (chunk.canBeInitial()) {
|
||||
for (const module of chunk.modulesIterable) {
|
||||
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
||||
if (module.type.startsWith("webassembly")) {
|
||||
initialWasmModules.add(module);
|
||||
}
|
||||
|
@ -118,6 +125,7 @@ class WebAssemblyModulesPlugin {
|
|||
new WebAssemblyInInitialChunkError(
|
||||
module,
|
||||
compilation.moduleGraph,
|
||||
compilation.chunkGraph,
|
||||
compilation.requestShortener
|
||||
)
|
||||
);
|
||||
|
|
|
@ -21,7 +21,7 @@ class FetchCompileWasmTemplatePlugin {
|
|||
`fetch(${mainTemplate.requireFn}.p + ${path})`;
|
||||
|
||||
const plugin = new WasmMainTemplatePlugin(
|
||||
compilation.moduleGraph,
|
||||
compilation,
|
||||
Object.assign(
|
||||
{
|
||||
generateLoadBinaryCode,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
const { ConcatSource } = require("webpack-sources");
|
||||
|
||||
/** @typedef {import("../ChunkTemplate")} ChunkTemplate */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
|
||||
const getEntryInfo = chunk => {
|
||||
return [chunk.entryModule].filter(Boolean).map(m =>
|
||||
|
@ -20,6 +21,13 @@ const getEntryInfo = chunk => {
|
|||
};
|
||||
|
||||
class JsonpChunkTemplatePlugin {
|
||||
/**
|
||||
* @param {Compilation} compilation the compilation
|
||||
*/
|
||||
constructor(compilation) {
|
||||
this.compilation = compilation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ChunkTemplate} chunkTemplate the chunk template
|
||||
* @returns {void}
|
||||
|
@ -27,11 +35,11 @@ class JsonpChunkTemplatePlugin {
|
|||
apply(chunkTemplate) {
|
||||
chunkTemplate.hooks.render.tap(
|
||||
"JsonpChunkTemplatePlugin",
|
||||
(modules, moduleTemplate, { chunk }) => {
|
||||
(modules, moduleTemplate, { chunk, chunkGraph }) => {
|
||||
const jsonpFunction = chunkTemplate.outputOptions.jsonpFunction;
|
||||
const globalObject = chunkTemplate.outputOptions.globalObject;
|
||||
const source = new ConcatSource();
|
||||
const prefetchChunks = chunk.getChildIdsByOrders().prefetch;
|
||||
const prefetchChunks = chunk.getChildIdsByOrders(chunkGraph).prefetch;
|
||||
source.add(
|
||||
`(${globalObject}[${JSON.stringify(
|
||||
jsonpFunction
|
||||
|
@ -63,8 +71,11 @@ class JsonpChunkTemplatePlugin {
|
|||
chunkTemplate.hooks.hashForChunk.tap(
|
||||
"JsonpChunkTemplatePlugin",
|
||||
(hash, chunk) => {
|
||||
const chunkGraph = this.compilation.chunkGraph;
|
||||
hash.update(JSON.stringify(getEntryInfo(chunk)));
|
||||
hash.update(JSON.stringify(chunk.getChildIdsByOrders().prefetch) || "");
|
||||
hash.update(
|
||||
JSON.stringify(chunk.getChildIdsByOrders(chunkGraph).prefetch) || ""
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,18 @@ const { SyncWaterfallHook } = require("tapable");
|
|||
const MainTemplate = require("../MainTemplate");
|
||||
const Template = require("../Template");
|
||||
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
|
||||
const mainTemplateHooksMap = new WeakMap();
|
||||
|
||||
class JsonpMainTemplatePlugin {
|
||||
/**
|
||||
* @param {Compilation} compilation the compilation
|
||||
*/
|
||||
constructor(compilation) {
|
||||
this.compilation = compilation;
|
||||
}
|
||||
|
||||
static getHooks(mainTemplate) {
|
||||
if (!(mainTemplate instanceof MainTemplate)) {
|
||||
throw new TypeError(
|
||||
|
@ -51,7 +60,10 @@ class JsonpMainTemplatePlugin {
|
|||
return false;
|
||||
};
|
||||
const needPrefetchingCode = chunk => {
|
||||
const allPrefetchChunks = chunk.getChildIdsByOrdersMap(true).prefetch;
|
||||
const allPrefetchChunks = chunk.getChildIdsByOrdersMap(
|
||||
this.compilation.chunkGraph,
|
||||
true
|
||||
).prefetch;
|
||||
return allPrefetchChunks && Object.keys(allPrefetchChunks).length;
|
||||
};
|
||||
|
||||
|
@ -311,7 +323,9 @@ class JsonpMainTemplatePlugin {
|
|||
stage: 10
|
||||
},
|
||||
(source, chunk, hash) => {
|
||||
const chunkMap = chunk.getChildIdsByOrdersMap().preload;
|
||||
const chunkMap = chunk.getChildIdsByOrdersMap(
|
||||
this.compilation.chunkGraph
|
||||
).preload;
|
||||
if (!chunkMap || Object.keys(chunkMap).length === 0) return source;
|
||||
return Template.asString([
|
||||
source,
|
||||
|
@ -492,7 +506,8 @@ class JsonpMainTemplatePlugin {
|
|||
mainTemplate.hooks.beforeStartup.tap(
|
||||
"JsonpMainTemplatePlugin",
|
||||
(source, chunk, hash) => {
|
||||
const prefetchChunks = chunk.getChildIdsByOrders().prefetch;
|
||||
const chunkGraph = this.compilation.chunkGraph;
|
||||
const prefetchChunks = chunk.getChildIdsByOrders(chunkGraph).prefetch;
|
||||
if (
|
||||
needChunkLoadingCode(chunk) &&
|
||||
prefetchChunks &&
|
||||
|
|
|
@ -12,8 +12,10 @@ const JsonpMainTemplatePlugin = require("./JsonpMainTemplatePlugin");
|
|||
class JsonpTemplatePlugin {
|
||||
apply(compiler) {
|
||||
compiler.hooks.thisCompilation.tap("JsonpTemplatePlugin", compilation => {
|
||||
new JsonpMainTemplatePlugin().apply(compilation.mainTemplate);
|
||||
new JsonpChunkTemplatePlugin().apply(compilation.chunkTemplate);
|
||||
new JsonpMainTemplatePlugin(compilation).apply(compilation.mainTemplate);
|
||||
new JsonpChunkTemplatePlugin(compilation).apply(
|
||||
compilation.chunkTemplate
|
||||
);
|
||||
new JsonpHotUpdateChunkTemplatePlugin().apply(
|
||||
compilation.hotUpdateChunkTemplate
|
||||
);
|
||||
|
|
|
@ -162,5 +162,6 @@ exportPlugins((exports.debug = {}), {
|
|||
ProfilingPlugin: () => require("./debug/ProfilingPlugin")
|
||||
});
|
||||
exportPlugins((exports.util = {}), {
|
||||
createHash: () => require("./util/createHash")
|
||||
createHash: () => require("./util/createHash"),
|
||||
comparators: () => require("./util/comparators")
|
||||
});
|
||||
|
|
|
@ -14,10 +14,6 @@ describe("Chunk", () => {
|
|||
expect(ChunkInstance.debugId).toBeGreaterThan(999);
|
||||
});
|
||||
|
||||
it("returns a string with modules information", () => {
|
||||
expect(ChunkInstance.toString()).toBe("Chunk[]");
|
||||
});
|
||||
|
||||
it("should not be the initial instance", () => {
|
||||
expect(ChunkInstance.canBeInitial()).toBe(false);
|
||||
});
|
||||
|
@ -27,62 +23,4 @@ describe("Chunk", () => {
|
|||
expect(ChunkInstance.hasRuntime()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isEmpty", () => {
|
||||
it("should NOT have any module by default", () => {
|
||||
expect(ChunkInstance.isEmpty()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("size", () => {
|
||||
it("should NOT have any module by default", () => {
|
||||
expect(
|
||||
ChunkInstance.size({
|
||||
chunkOverhead: 10,
|
||||
entryChunkMultiplicator: 2
|
||||
})
|
||||
).toBe(10);
|
||||
});
|
||||
});
|
||||
|
||||
describe("removeModule", () => {
|
||||
let module;
|
||||
let removeChunkSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
removeChunkSpy = jest.fn();
|
||||
module = {
|
||||
removeChunk: removeChunkSpy
|
||||
};
|
||||
});
|
||||
|
||||
describe("and the chunk does not contain this module", () => {
|
||||
it("returns false", () => {
|
||||
expect(ChunkInstance.removeModule(module)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and the chunk does contain this module", () => {
|
||||
beforeEach(() => {
|
||||
ChunkInstance._modules = new Set([module]);
|
||||
});
|
||||
|
||||
it("calls module.removeChunk with itself and returns true", () => {
|
||||
expect(ChunkInstance.removeModule(module)).toBe(true);
|
||||
|
||||
expect(removeChunkSpy.mock.calls.length).toBe(1);
|
||||
expect(removeChunkSpy.mock.calls[0][0]).toBe(ChunkInstance);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getNumberOfGroups", () => {
|
||||
beforeEach(() => {
|
||||
ChunkInstance._groups = new Set();
|
||||
});
|
||||
|
||||
it("should return the number of chunk groups contained by the chunk", () => {
|
||||
expect(ChunkInstance.getNumberOfGroups()).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,63 +1,63 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`StatsTestCases should print correct stats for aggressive-splitting-entry 1`] = `
|
||||
"Hash: 13158616d9265e218cf913158616d9265e218cf9
|
||||
"Hash: 44a278e3b0741b9b5da644a278e3b0741b9b5da6
|
||||
Child fitting:
|
||||
Hash: 13158616d9265e218cf9
|
||||
Hash: 44a278e3b0741b9b5da6
|
||||
Time: Xms
|
||||
Built at: Thu Jan 01 1970 00:00:00 GMT
|
||||
Asset Size Chunks Chunk Names
|
||||
d4b551c6319035df2898.js 1.05 KiB 0 [emitted]
|
||||
138d0972019f89a65bcf.js 1.94 KiB 1 [emitted]
|
||||
0f93dbc57653279c9b6c.js 1.94 KiB 2 [emitted]
|
||||
5c03d474bf8ab9d8029d.js 11.1 KiB 3 [emitted]
|
||||
Entrypoint main = 138d0972019f89a65bcf.js 0f93dbc57653279c9b6c.js 5c03d474bf8ab9d8029d.js
|
||||
7029d2a129d88406bdea.js 1.94 KiB 1 [emitted]
|
||||
9d3d08d313ade4d2c47a.js 11.1 KiB 2 [emitted]
|
||||
5d5aae6ca1af5d6e6ea4.js 1.94 KiB 3 [emitted]
|
||||
Entrypoint main = 5d5aae6ca1af5d6e6ea4.js 7029d2a129d88406bdea.js 9d3d08d313ade4d2c47a.js
|
||||
chunk {0} d4b551c6319035df2898.js 916 bytes <{1}> <{2}> <{3}>
|
||||
> ./g [4] ./index.js 7:0-13
|
||||
[7] ./g.js 916 bytes {0} [built]
|
||||
chunk {1} 138d0972019f89a65bcf.js 1.76 KiB ={2}= ={3}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
chunk {1} 7029d2a129d88406bdea.js 1.76 KiB ={2}= ={3}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
> ./index main
|
||||
[0] ./b.js 899 bytes {1} [built]
|
||||
[5] ./a.js 899 bytes {1} [built]
|
||||
chunk {2} 0f93dbc57653279c9b6c.js 1.76 KiB ={1}= ={3}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
[1] ./c.js 899 bytes {1} [built]
|
||||
[2] ./d.js 899 bytes {1} [built]
|
||||
chunk {2} 9d3d08d313ade4d2c47a.js 1.87 KiB ={1}= ={3}= >{0}< [entry] [rendered]
|
||||
> ./index main
|
||||
[1] ./c.js 899 bytes {2} [built]
|
||||
[2] ./d.js 899 bytes {2} [built]
|
||||
chunk {3} 5c03d474bf8ab9d8029d.js 1.87 KiB ={1}= ={2}= >{0}< [entry] [rendered]
|
||||
[3] ./e.js 899 bytes {2} [built]
|
||||
[4] ./index.js 111 bytes {2} [built]
|
||||
[6] ./f.js 900 bytes {2} [built]
|
||||
chunk {3} 5d5aae6ca1af5d6e6ea4.js 1.76 KiB ={1}= ={2}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
> ./index main
|
||||
[3] ./e.js 899 bytes {3} [built]
|
||||
[4] ./index.js 111 bytes {3} [built]
|
||||
[6] ./f.js 900 bytes {3} [built]
|
||||
[0] ./b.js 899 bytes {3} [built]
|
||||
[5] ./a.js 899 bytes {3} [built]
|
||||
Child content-change:
|
||||
Hash: 13158616d9265e218cf9
|
||||
Hash: 44a278e3b0741b9b5da6
|
||||
Time: Xms
|
||||
Built at: Thu Jan 01 1970 00:00:00 GMT
|
||||
Asset Size Chunks Chunk Names
|
||||
d4b551c6319035df2898.js 1.05 KiB 0 [emitted]
|
||||
138d0972019f89a65bcf.js 1.94 KiB 1 [emitted]
|
||||
0f93dbc57653279c9b6c.js 1.94 KiB 2 [emitted]
|
||||
5c03d474bf8ab9d8029d.js 11.1 KiB 3 [emitted]
|
||||
Entrypoint main = 138d0972019f89a65bcf.js 0f93dbc57653279c9b6c.js 5c03d474bf8ab9d8029d.js
|
||||
7029d2a129d88406bdea.js 1.94 KiB 1 [emitted]
|
||||
9d3d08d313ade4d2c47a.js 11.1 KiB 2 [emitted]
|
||||
5d5aae6ca1af5d6e6ea4.js 1.94 KiB 3 [emitted]
|
||||
Entrypoint main = 5d5aae6ca1af5d6e6ea4.js 7029d2a129d88406bdea.js 9d3d08d313ade4d2c47a.js
|
||||
chunk {0} d4b551c6319035df2898.js 916 bytes <{1}> <{2}> <{3}>
|
||||
> ./g [4] ./index.js 7:0-13
|
||||
[7] ./g.js 916 bytes {0} [built]
|
||||
chunk {1} 138d0972019f89a65bcf.js 1.76 KiB ={2}= ={3}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
chunk {1} 7029d2a129d88406bdea.js 1.76 KiB ={2}= ={3}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
> ./index main
|
||||
[0] ./b.js 899 bytes {1} [built]
|
||||
[5] ./a.js 899 bytes {1} [built]
|
||||
chunk {2} 0f93dbc57653279c9b6c.js 1.76 KiB ={1}= ={3}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
[1] ./c.js 899 bytes {1} [built]
|
||||
[2] ./d.js 899 bytes {1} [built]
|
||||
chunk {2} 9d3d08d313ade4d2c47a.js 1.87 KiB ={1}= ={3}= >{0}< [entry] [rendered]
|
||||
> ./index main
|
||||
[1] ./c.js 899 bytes {2} [built]
|
||||
[2] ./d.js 899 bytes {2} [built]
|
||||
chunk {3} 5c03d474bf8ab9d8029d.js 1.87 KiB ={1}= ={2}= >{0}< [entry] [rendered]
|
||||
[3] ./e.js 899 bytes {2} [built]
|
||||
[4] ./index.js 111 bytes {2} [built]
|
||||
[6] ./f.js 900 bytes {2} [built]
|
||||
chunk {3} 5d5aae6ca1af5d6e6ea4.js 1.76 KiB ={1}= ={2}= >{0}< [initial] [rendered] [recorded] aggressive splitted
|
||||
> ./index main
|
||||
[3] ./e.js 899 bytes {3} [built]
|
||||
[4] ./index.js 111 bytes {3} [built]
|
||||
[6] ./f.js 900 bytes {3} [built]"
|
||||
[0] ./b.js 899 bytes {3} [built]
|
||||
[5] ./a.js 899 bytes {3} [built]"
|
||||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for aggressive-splitting-on-demand 1`] = `
|
||||
"Hash: 974518ddadca5f73bda5
|
||||
"Hash: 02a058acce1bfbcd9896
|
||||
Time: Xms
|
||||
Built at: Thu Jan 01 1970 00:00:00 GMT
|
||||
Asset Size Chunks Chunk Names
|
||||
|
@ -69,11 +69,11 @@ f0ef1f91cb22147f3f2c.js 1 KiB 4 [emitted]
|
|||
c99c160aba2d9a94e5d1.js 1.94 KiB 5 [emitted]
|
||||
138d0972019f89a65bcf.js 1.94 KiB 1 [emitted]
|
||||
6a8e74d82c35e3f013d2.js 1 KiB 7 [emitted]
|
||||
5bc7f208cd99a83b4e33.js 1.94 KiB 8 [emitted]
|
||||
ee043b525cd899e33ec0.js 1.94 KiB 8 [emitted]
|
||||
01a8254701931adbf278.js 1.01 KiB 9 [emitted]
|
||||
c083e218f1f3ce7f1e48.js 9.7 KiB 10 [emitted] main
|
||||
57253719544987787b40.js 9.7 KiB 10 [emitted] main
|
||||
ba9fedb7aa0c69201639.js 1.94 KiB 11 [emitted]
|
||||
Entrypoint main = c083e218f1f3ce7f1e48.js
|
||||
Entrypoint main = 57253719544987787b40.js
|
||||
chunk {0} 2736cf9d79233cd0a9b6.js 1.76 KiB <{10}> ={2}= ={3}= ={4}= ={5}= ={7}= [recorded] aggressive splitted
|
||||
> ./b ./d ./e ./f ./g [11] ./index.js 5:0-44
|
||||
> ./b ./d ./e ./f ./g ./h ./i ./j ./k [11] ./index.js 6:0-72
|
||||
|
@ -108,14 +108,14 @@ chunk {6} 58f368c01f66002b0eb3.js 1.76 KiB <{10}> ={2}= ={11}=
|
|||
chunk {7} 6a8e74d82c35e3f013d2.js 899 bytes <{10}> ={0}= ={2}= ={3}= ={5}=
|
||||
> ./b ./d ./e ./f ./g ./h ./i ./j ./k [11] ./index.js 6:0-72
|
||||
[9] ./k.js 899 bytes {6} {7} [built]
|
||||
chunk {8} 5bc7f208cd99a83b4e33.js 1.76 KiB <{10}> ={4}= [recorded] aggressive splitted
|
||||
chunk {8} ee043b525cd899e33ec0.js 1.76 KiB <{10}> ={4}= [recorded] aggressive splitted
|
||||
> ./c ./d ./e [11] ./index.js 3:0-30
|
||||
[1] ./d.js 899 bytes {0} {8} [built]
|
||||
[5] ./c.js 899 bytes {1} {8} [built]
|
||||
chunk {9} 01a8254701931adbf278.js 899 bytes <{10}>
|
||||
> ./a [11] ./index.js 1:0-16
|
||||
[10] ./a.js 899 bytes {9} [built]
|
||||
chunk {10} c083e218f1f3ce7f1e48.js (main) 248 bytes >{0}< >{1}< >{2}< >{3}< >{4}< >{5}< >{6}< >{7}< >{8}< >{9}< >{11}< [entry] [rendered]
|
||||
chunk {10} 57253719544987787b40.js (main) 248 bytes >{0}< >{1}< >{2}< >{3}< >{4}< >{5}< >{6}< >{7}< >{8}< >{9}< >{11}< [entry] [rendered]
|
||||
> ./index main
|
||||
[11] ./index.js 248 bytes {10} [built]
|
||||
chunk {11} ba9fedb7aa0c69201639.js 1.76 KiB <{10}> ={2}= ={6}= [rendered] [recorded] aggressive splitted
|
||||
|
@ -2228,10 +2228,10 @@ main.js 9.32 KiB 0 [emitted] main
|
|||
Entrypoint main = main.js
|
||||
[0] ./components/src/CompAB/CompA.js 89 bytes {0} [built]
|
||||
[only some exports used: default]
|
||||
harmony side effect evaluation ./CompA ./components/src/CompAB/index.js 1:0-43
|
||||
harmony export imported specifier ./CompA ./components/src/CompAB/index.js 1:0-43
|
||||
harmony import specifier ./components [2] ./foo.js 3:20-25 (skipped side-effect-free modules)
|
||||
harmony import specifier ./components [3] ./main.js + 1 modules 3:15-20 (skipped side-effect-free modules)
|
||||
harmony side effect evaluation ./CompA ./components/src/CompAB/index.js 1:0-43
|
||||
harmony export imported specifier ./CompA ./components/src/CompAB/index.js 1:0-43
|
||||
[1] ./components/src/CompAB/utils.js 97 bytes {0} [built]
|
||||
harmony side effect evaluation ./utils [0] ./components/src/CompAB/CompA.js 1:0-35
|
||||
harmony import specifier ./utils [0] ./components/src/CompAB/CompA.js 5:5-12
|
||||
|
|
|
@ -23,7 +23,9 @@ module.exports = {
|
|||
const modules = new Map();
|
||||
const modules2 = new Map();
|
||||
for (const chunk of group.chunks) {
|
||||
for (const module of chunk.modulesIterable) {
|
||||
for (const module of compilation.chunkGraph.getChunkModulesIterable(
|
||||
chunk
|
||||
)) {
|
||||
modules.set(module, group.getModuleIndex(module));
|
||||
modules2.set(module, group.getModuleIndex2(module));
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const NamedChunksPlugin = require("../../../lib/NamedChunksPlugin");
|
||||
const RequestShortener = require("../../../lib/RequestShortener");
|
||||
const { compareModulesById } = require("../../../lib/util/comparators");
|
||||
|
||||
module.exports = {
|
||||
mode: "production",
|
||||
|
@ -10,17 +11,20 @@ module.exports = {
|
|||
entry: "./entry"
|
||||
},
|
||||
plugins: [
|
||||
new NamedChunksPlugin(function(chunk) {
|
||||
new NamedChunksPlugin(function(chunk, { chunkGraph }) {
|
||||
if (chunk.name) {
|
||||
return chunk.name;
|
||||
}
|
||||
const chunkModulesToName = chunk =>
|
||||
Array.from(chunk.modulesIterable, mod => {
|
||||
const rs = new RequestShortener(mod.context);
|
||||
return rs.shorten(mod.request).replace(/[./\\]/g, "_");
|
||||
}).join("-");
|
||||
Array.from(
|
||||
chunkGraph.getOrderedChunkModulesIterable(chunk, compareModulesById),
|
||||
mod => {
|
||||
const rs = new RequestShortener(mod.context);
|
||||
return rs.shorten(mod.request).replace(/[./\\]/g, "_");
|
||||
}
|
||||
).join("-");
|
||||
|
||||
if (chunk.getNumberOfModules() > 0) {
|
||||
if (chunkGraph.getNumberOfChunkModules(chunk) > 0) {
|
||||
return `chunk-containing-${chunkModulesToName(chunk)}`;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,12 +97,12 @@ const schema = [
|
|||
},
|
||||
{
|
||||
title: "type imports",
|
||||
regexp: /(\/\*\* @typedef \{import\("[^"]+"\)(\.\w+)*\} \w+ \*\/\n)+\n/g,
|
||||
regexp: /(\/\*\* (?:@template \w+ )*@typedef \{import\("[^"]+"\)(\.\w+)*(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)?\} \w+(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)? \*\/\n)+\n/g,
|
||||
updateMessage: "sort type imports alphabetically",
|
||||
update(content) {
|
||||
const items = execToArray(
|
||||
content,
|
||||
/\/\*\* @typedef \{import\("([^"]+)"\)((?:\.\w+)*)\} \w+ \*\/\n/g
|
||||
/\/\*\* (?:@template \w+ )*@typedef \{import\("([^"]+)"\)((?:\.\w+)*(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)?)\} \w+(?:<(?:(?:\w\.)*\w+, )*(?:\w\.)*\w+>)? \*\/\n/g
|
||||
);
|
||||
items.sort(sortImport);
|
||||
return items.map(item => item.content).join("") + "\n";
|
||||
|
|
Loading…
Reference in New Issue