first commit

This commit is contained in:
monjack
2025-06-20 18:01:48 +08:00
commit 6daa6d65c1
24611 changed files with 2512443 additions and 0 deletions

View File

@ -0,0 +1,89 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { find } = require("../util/SetHelpers");
const {
compareModulesByPreOrderIndexOrIdentifier,
compareModulesByPostOrderIndexOrIdentifier
} = require("../util/comparators");
/** @typedef {import("../Compiler")} Compiler */
/**
* @typedef {object} ChunkModuleIdRangePluginOptions
* @property {string} name the chunk name
* @property {("index" | "index2" | "preOrderIndex" | "postOrderIndex")=} order order
* @property {number=} start start id
* @property {number=} end end id
*/
const PLUGIN_NAME = "ChunkModuleIdRangePlugin";
class ChunkModuleIdRangePlugin {
/**
* @param {ChunkModuleIdRangePluginOptions} options options object
*/
constructor(options) {
this.options = options;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
const options = this.options;
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
const moduleGraph = compilation.moduleGraph;
compilation.hooks.moduleIds.tap(PLUGIN_NAME, modules => {
const chunkGraph = compilation.chunkGraph;
const chunk = find(
compilation.chunks,
chunk => chunk.name === options.name
);
if (!chunk) {
throw new Error(
`${PLUGIN_NAME}: Chunk with name '${options.name}"' was not found`
);
}
let chunkModules;
if (options.order) {
let cmpFn;
switch (options.order) {
case "index":
case "preOrderIndex":
cmpFn = compareModulesByPreOrderIndexOrIdentifier(moduleGraph);
break;
case "index2":
case "postOrderIndex":
cmpFn = compareModulesByPostOrderIndexOrIdentifier(moduleGraph);
break;
default:
throw new Error(`${PLUGIN_NAME}: unexpected value of order`);
}
chunkModules = chunkGraph.getOrderedChunkModules(chunk, cmpFn);
} else {
chunkModules = Array.from(modules)
.filter(m => chunkGraph.isModuleInChunk(m, chunk))
.sort(compareModulesByPreOrderIndexOrIdentifier(moduleGraph));
}
let currentId = options.start || 0;
for (let i = 0; i < chunkModules.length; i++) {
const m = chunkModules[i];
if (m.needId && chunkGraph.getModuleId(m) === null) {
chunkGraph.setModuleId(m, currentId++);
}
if (options.end && currentId > options.end) break;
}
});
});
}
}
module.exports = ChunkModuleIdRangePlugin;

View File

@ -0,0 +1,77 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Florent Cailhol @ooflorent
*/
"use strict";
const { compareChunksNatural } = require("../util/comparators");
const {
getFullChunkName,
getUsedChunkIds,
assignDeterministicIds
} = require("./IdHelpers");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/**
* @typedef {object} DeterministicChunkIdsPluginOptions
* @property {string=} context context for ids
* @property {number=} maxLength maximum length of ids
*/
class DeterministicChunkIdsPlugin {
/**
* @param {DeterministicChunkIdsPluginOptions=} options options
*/
constructor(options = {}) {
this.options = options;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(
"DeterministicChunkIdsPlugin",
compilation => {
compilation.hooks.chunkIds.tap(
"DeterministicChunkIdsPlugin",
chunks => {
const chunkGraph = compilation.chunkGraph;
const context = this.options.context
? this.options.context
: compiler.context;
const maxLength = this.options.maxLength || 3;
const compareNatural = compareChunksNatural(chunkGraph);
const usedIds = getUsedChunkIds(compilation);
assignDeterministicIds(
Array.from(chunks).filter(chunk => chunk.id === null),
chunk =>
getFullChunkName(chunk, chunkGraph, context, compiler.root),
compareNatural,
(chunk, id) => {
const size = usedIds.size;
usedIds.add(`${id}`);
if (size === usedIds.size) return false;
chunk.id = id;
chunk.ids = [id];
return true;
},
[10 ** maxLength],
10,
usedIds.size
);
}
);
}
);
}
}
module.exports = DeterministicChunkIdsPlugin;

View File

@ -0,0 +1,96 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Florent Cailhol @ooflorent
*/
"use strict";
const {
compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const {
getUsedModuleIdsAndModules,
getFullModuleName,
assignDeterministicIds
} = require("./IdHelpers");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/**
* @typedef {object} DeterministicModuleIdsPluginOptions
* @property {string=} context context relative to which module identifiers are computed
* @property {((module: Module) => boolean)=} test selector function for modules
* @property {number=} maxLength maximum id length in digits (used as starting point)
* @property {number=} salt hash salt for ids
* @property {boolean=} fixedLength do not increase the maxLength to find an optimal id space size
* @property {boolean=} failOnConflict throw an error when id conflicts occur (instead of rehashing)
*/
const PLUGIN_NAME = "DeterministicModuleIdsPlugin";
class DeterministicModuleIdsPlugin {
/**
* @param {DeterministicModuleIdsPluginOptions=} options options
*/
constructor(options = {}) {
this.options = options;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.moduleIds.tap(PLUGIN_NAME, () => {
const chunkGraph = compilation.chunkGraph;
const context = this.options.context
? this.options.context
: compiler.context;
const maxLength = this.options.maxLength || 3;
const failOnConflict = this.options.failOnConflict || false;
const fixedLength = this.options.fixedLength || false;
const salt = this.options.salt || 0;
let conflicts = 0;
const [usedIds, modules] = getUsedModuleIdsAndModules(
compilation,
this.options.test
);
assignDeterministicIds(
modules,
module => getFullModuleName(module, context, compiler.root),
failOnConflict
? () => 0
: compareModulesByPreOrderIndexOrIdentifier(
compilation.moduleGraph
),
(module, id) => {
const size = usedIds.size;
usedIds.add(`${id}`);
if (size === usedIds.size) {
conflicts++;
return false;
}
chunkGraph.setModuleId(module, id);
return true;
},
[10 ** maxLength],
fixedLength ? 0 : 10,
usedIds.size,
salt
);
if (failOnConflict && conflicts)
throw new Error(
`Assigning deterministic module ids has lead to ${conflicts} conflict${
conflicts > 1 ? "s" : ""
}.\nIncrease the 'maxLength' to increase the id space and make conflicts less likely (recommended when there are many conflicts or application is expected to grow), or add an 'salt' number to try another hash starting value in the same id space (recommended when there is only a single conflict).`
);
});
});
}
}
module.exports = DeterministicModuleIdsPlugin;

View File

@ -0,0 +1,91 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { DEFAULTS } = require("../config/defaults");
const {
compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const createSchemaValidation = require("../util/create-schema-validation");
const createHash = require("../util/createHash");
const {
getUsedModuleIdsAndModules,
getFullModuleName
} = require("./IdHelpers");
/** @typedef {import("../../declarations/plugins/HashedModuleIdsPlugin").HashedModuleIdsPluginOptions} HashedModuleIdsPluginOptions */
/** @typedef {import("../Compiler")} Compiler */
const validate = createSchemaValidation(
require("../../schemas/plugins/HashedModuleIdsPlugin.check.js"),
() => require("../../schemas/plugins/HashedModuleIdsPlugin.json"),
{
name: "Hashed Module Ids Plugin",
baseDataPath: "options"
}
);
const PLUGIN_NAME = "HashedModuleIdsPlugin";
class HashedModuleIdsPlugin {
/**
* @param {HashedModuleIdsPluginOptions=} options options object
*/
constructor(options = {}) {
validate(options);
/** @type {HashedModuleIdsPluginOptions} */
this.options = {
context: undefined,
hashFunction: DEFAULTS.HASH_FUNCTION,
hashDigest: "base64",
hashDigestLength: 4,
...options
};
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
const options = this.options;
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.moduleIds.tap(PLUGIN_NAME, () => {
const chunkGraph = compilation.chunkGraph;
const context = this.options.context
? this.options.context
: compiler.context;
const [usedIds, modules] = getUsedModuleIdsAndModules(compilation);
const modulesInNaturalOrder = modules.sort(
compareModulesByPreOrderIndexOrIdentifier(compilation.moduleGraph)
);
for (const module of modulesInNaturalOrder) {
const ident = getFullModuleName(module, context, compiler.root);
const hash = createHash(
/** @type {NonNullable<HashedModuleIdsPluginOptions["hashFunction"]>} */ (
options.hashFunction
)
);
hash.update(ident || "");
const hashId = /** @type {string} */ (
hash.digest(options.hashDigest)
);
let len = options.hashDigestLength;
while (usedIds.has(hashId.slice(0, len)))
/** @type {number} */ (len)++;
const moduleId = hashId.slice(0, len);
chunkGraph.setModuleId(module, moduleId);
usedIds.add(moduleId);
}
});
});
}
}
module.exports = HashedModuleIdsPlugin;

474
app_vue/node_modules/webpack/lib/ids/IdHelpers.js generated vendored Normal file
View File

@ -0,0 +1,474 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const createHash = require("../util/createHash");
const { makePathsRelative } = require("../util/identifier");
const numberHash = require("../util/numberHash");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Module")} Module */
/** @typedef {typeof import("../util/Hash")} Hash */
/** @typedef {import("../util/identifier").AssociatedObjectForCache} AssociatedObjectForCache */
/**
* @param {string} str string to hash
* @param {number} len max length of the hash
* @param {string | Hash} hashFunction hash function to use
* @returns {string} hash
*/
const getHash = (str, len, hashFunction) => {
const hash = createHash(hashFunction);
hash.update(str);
const digest = /** @type {string} */ (hash.digest("hex"));
return digest.slice(0, len);
};
/**
* @param {string} str the string
* @returns {string} string prefixed by an underscore if it is a number
*/
const avoidNumber = str => {
// max length of a number is 21 chars, bigger numbers a written as "...e+xx"
if (str.length > 21) return str;
const firstChar = str.charCodeAt(0);
// skip everything that doesn't look like a number
// charCodes: "-": 45, "1": 49, "9": 57
if (firstChar < 49) {
if (firstChar !== 45) return str;
} else if (firstChar > 57) {
return str;
}
if (str === String(Number(str))) {
return `_${str}`;
}
return str;
};
/**
* @param {string} request the request
* @returns {string} id representation
*/
const requestToId = request =>
request.replace(/^(\.\.?\/)+/, "").replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_");
module.exports.requestToId = requestToId;
/**
* @param {string} string the string
* @param {string} delimiter separator for string and hash
* @param {string | Hash} hashFunction hash function to use
* @returns {string} string with limited max length to 100 chars
*/
const shortenLongString = (string, delimiter, hashFunction) => {
if (string.length < 100) return string;
return (
string.slice(0, 100 - 6 - delimiter.length) +
delimiter +
getHash(string, 6, hashFunction)
);
};
/**
* @param {Module} module the module
* @param {string} context context directory
* @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
* @returns {string} short module name
*/
const getShortModuleName = (module, context, associatedObjectForCache) => {
const libIdent = module.libIdent({ context, associatedObjectForCache });
if (libIdent) return avoidNumber(libIdent);
const nameForCondition = module.nameForCondition();
if (nameForCondition)
return avoidNumber(
makePathsRelative(context, nameForCondition, associatedObjectForCache)
);
return "";
};
module.exports.getShortModuleName = getShortModuleName;
/**
* @param {string} shortName the short name
* @param {Module} module the module
* @param {string} context context directory
* @param {string | Hash} hashFunction hash function to use
* @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
* @returns {string} long module name
*/
const getLongModuleName = (
shortName,
module,
context,
hashFunction,
associatedObjectForCache
) => {
const fullName = getFullModuleName(module, context, associatedObjectForCache);
return `${shortName}?${getHash(fullName, 4, hashFunction)}`;
};
module.exports.getLongModuleName = getLongModuleName;
/**
* @param {Module} module the module
* @param {string} context context directory
* @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
* @returns {string} full module name
*/
const getFullModuleName = (module, context, associatedObjectForCache) =>
makePathsRelative(context, module.identifier(), associatedObjectForCache);
module.exports.getFullModuleName = getFullModuleName;
/**
* @param {Chunk} chunk the chunk
* @param {ChunkGraph} chunkGraph the chunk graph
* @param {string} context context directory
* @param {string} delimiter delimiter for names
* @param {string | Hash} hashFunction hash function to use
* @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
* @returns {string} short chunk name
*/
const getShortChunkName = (
chunk,
chunkGraph,
context,
delimiter,
hashFunction,
associatedObjectForCache
) => {
const modules = chunkGraph.getChunkRootModules(chunk);
const shortModuleNames = modules.map(m =>
requestToId(getShortModuleName(m, context, associatedObjectForCache))
);
chunk.idNameHints.sort();
const chunkName = Array.from(chunk.idNameHints)
.concat(shortModuleNames)
.filter(Boolean)
.join(delimiter);
return shortenLongString(chunkName, delimiter, hashFunction);
};
module.exports.getShortChunkName = getShortChunkName;
/**
* @param {Chunk} chunk the chunk
* @param {ChunkGraph} chunkGraph the chunk graph
* @param {string} context context directory
* @param {string} delimiter delimiter for names
* @param {string | Hash} hashFunction hash function to use
* @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
* @returns {string} short chunk name
*/
const getLongChunkName = (
chunk,
chunkGraph,
context,
delimiter,
hashFunction,
associatedObjectForCache
) => {
const modules = chunkGraph.getChunkRootModules(chunk);
const shortModuleNames = modules.map(m =>
requestToId(getShortModuleName(m, context, associatedObjectForCache))
);
const longModuleNames = modules.map(m =>
requestToId(
getLongModuleName("", m, context, hashFunction, associatedObjectForCache)
)
);
chunk.idNameHints.sort();
const chunkName = Array.from(chunk.idNameHints)
.concat(shortModuleNames, longModuleNames)
.filter(Boolean)
.join(delimiter);
return shortenLongString(chunkName, delimiter, hashFunction);
};
module.exports.getLongChunkName = getLongChunkName;
/**
* @param {Chunk} chunk the chunk
* @param {ChunkGraph} chunkGraph the chunk graph
* @param {string} context context directory
* @param {AssociatedObjectForCache=} associatedObjectForCache an object to which the cache will be attached
* @returns {string} full chunk name
*/
const getFullChunkName = (
chunk,
chunkGraph,
context,
associatedObjectForCache
) => {
if (chunk.name) return chunk.name;
const modules = chunkGraph.getChunkRootModules(chunk);
const fullModuleNames = modules.map(m =>
makePathsRelative(context, m.identifier(), associatedObjectForCache)
);
return fullModuleNames.join();
};
module.exports.getFullChunkName = getFullChunkName;
/**
* @template K
* @template V
* @param {Map<K, V[]>} map a map from key to values
* @param {K} key key
* @param {V} value value
* @returns {void}
*/
const addToMapOfItems = (map, key, value) => {
let array = map.get(key);
if (array === undefined) {
array = [];
map.set(key, array);
}
array.push(value);
};
/**
* @param {Compilation} compilation the compilation
* @param {((module: Module) => boolean)=} filter filter modules
* @returns {[Set<string>, Module[]]} used module ids as strings and modules without id matching the filter
*/
const getUsedModuleIdsAndModules = (compilation, filter) => {
const chunkGraph = compilation.chunkGraph;
const modules = [];
/** @type {Set<string>} */
const usedIds = new Set();
if (compilation.usedModuleIds) {
for (const id of compilation.usedModuleIds) {
usedIds.add(String(id));
}
}
for (const module of compilation.modules) {
if (!module.needId) continue;
const moduleId = chunkGraph.getModuleId(module);
if (moduleId !== null) {
usedIds.add(String(moduleId));
} else if (
(!filter || filter(module)) &&
chunkGraph.getNumberOfModuleChunks(module) !== 0
) {
modules.push(module);
}
}
return [usedIds, modules];
};
module.exports.getUsedModuleIdsAndModules = getUsedModuleIdsAndModules;
/**
* @param {Compilation} compilation the compilation
* @returns {Set<string>} used chunk ids as strings
*/
const getUsedChunkIds = compilation => {
/** @type {Set<string>} */
const usedIds = new Set();
if (compilation.usedChunkIds) {
for (const id of compilation.usedChunkIds) {
usedIds.add(String(id));
}
}
for (const chunk of compilation.chunks) {
const chunkId = chunk.id;
if (chunkId !== null) {
usedIds.add(String(chunkId));
}
}
return usedIds;
};
module.exports.getUsedChunkIds = getUsedChunkIds;
/**
* @template T
* @param {Iterable<T>} items list of items to be named
* @param {(item: T) => string} getShortName get a short name for an item
* @param {(item: T, name: string) => string} getLongName get a long name for an item
* @param {(a: T, b: T) => -1 | 0 | 1} comparator order of items
* @param {Set<string>} usedIds already used ids, will not be assigned
* @param {(item: T, name: string) => void} assignName assign a name to an item
* @returns {T[]} list of items without a name
*/
const assignNames = (
items,
getShortName,
getLongName,
comparator,
usedIds,
assignName
) => {
/** @type {Map<string, T[]>} */
const nameToItems = new Map();
for (const item of items) {
const name = getShortName(item);
addToMapOfItems(nameToItems, name, item);
}
/** @type {Map<string, T[]>} */
const nameToItems2 = new Map();
for (const [name, items] of nameToItems) {
if (items.length > 1 || !name) {
for (const item of items) {
const longName = getLongName(item, name);
addToMapOfItems(nameToItems2, longName, item);
}
} else {
addToMapOfItems(nameToItems2, name, items[0]);
}
}
/** @type {T[]} */
const unnamedItems = [];
for (const [name, items] of nameToItems2) {
if (!name) {
for (const item of items) {
unnamedItems.push(item);
}
} else if (items.length === 1 && !usedIds.has(name)) {
assignName(items[0], name);
usedIds.add(name);
} else {
items.sort(comparator);
let i = 0;
for (const item of items) {
while (nameToItems2.has(name + i) && usedIds.has(name + i)) i++;
assignName(item, name + i);
usedIds.add(name + i);
i++;
}
}
}
unnamedItems.sort(comparator);
return unnamedItems;
};
module.exports.assignNames = assignNames;
/**
* @template T
* @param {T[]} items list of items to be named
* @param {(item: T) => string} getName get a name for an item
* @param {(a: T, n: T) => -1 | 0 | 1} comparator order of items
* @param {(item: T, id: number) => boolean} assignId assign an id to an item
* @param {number[]} ranges usable ranges for ids
* @param {number} expandFactor factor to create more ranges
* @param {number} extraSpace extra space to allocate, i. e. when some ids are already used
* @param {number} salt salting number to initialize hashing
* @returns {void}
*/
const assignDeterministicIds = (
items,
getName,
comparator,
assignId,
ranges = [10],
expandFactor = 10,
extraSpace = 0,
salt = 0
) => {
items.sort(comparator);
// max 5% fill rate
const optimalRange = Math.min(
items.length * 20 + extraSpace,
Number.MAX_SAFE_INTEGER
);
let i = 0;
let range = ranges[i];
while (range < optimalRange) {
i++;
if (i < ranges.length) {
range = Math.min(ranges[i], Number.MAX_SAFE_INTEGER);
} else if (expandFactor) {
range = Math.min(range * expandFactor, Number.MAX_SAFE_INTEGER);
} else {
break;
}
}
for (const item of items) {
const ident = getName(item);
let id;
let i = salt;
do {
id = numberHash(ident + i++, range);
} while (!assignId(item, id));
}
};
module.exports.assignDeterministicIds = assignDeterministicIds;
/**
* @param {Set<string>} usedIds used ids
* @param {Iterable<Module>} modules the modules
* @param {Compilation} compilation the compilation
* @returns {void}
*/
const assignAscendingModuleIds = (usedIds, modules, compilation) => {
const chunkGraph = compilation.chunkGraph;
let nextId = 0;
let assignId;
if (usedIds.size > 0) {
/**
* @param {Module} module the module
*/
assignId = module => {
if (chunkGraph.getModuleId(module) === null) {
while (usedIds.has(String(nextId))) nextId++;
chunkGraph.setModuleId(module, nextId++);
}
};
} else {
/**
* @param {Module} module the module
*/
assignId = module => {
if (chunkGraph.getModuleId(module) === null) {
chunkGraph.setModuleId(module, nextId++);
}
};
}
for (const module of modules) {
assignId(module);
}
};
module.exports.assignAscendingModuleIds = assignAscendingModuleIds;
/**
* @param {Iterable<Chunk>} chunks the chunks
* @param {Compilation} compilation the compilation
* @returns {void}
*/
const assignAscendingChunkIds = (chunks, compilation) => {
const usedIds = getUsedChunkIds(compilation);
let nextId = 0;
if (usedIds.size > 0) {
for (const chunk of chunks) {
if (chunk.id === null) {
while (usedIds.has(String(nextId))) nextId++;
chunk.id = nextId;
chunk.ids = [nextId];
nextId++;
}
}
} else {
for (const chunk of chunks) {
if (chunk.id === null) {
chunk.id = nextId;
chunk.ids = [nextId];
nextId++;
}
}
}
};
module.exports.assignAscendingChunkIds = assignAscendingChunkIds;

View File

@ -0,0 +1,95 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { compareChunksNatural } = require("../util/comparators");
const {
getShortChunkName,
getLongChunkName,
assignNames,
getUsedChunkIds,
assignAscendingChunkIds
} = require("./IdHelpers");
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/**
* @typedef {object} NamedChunkIdsPluginOptions
* @property {string=} context context
* @property {string=} delimiter delimiter
*/
const PLUGIN_NAME = "NamedChunkIdsPlugin";
class NamedChunkIdsPlugin {
/**
* @param {NamedChunkIdsPluginOptions=} options options
*/
constructor(options) {
this.delimiter = (options && options.delimiter) || "-";
this.context = options && options.context;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
const hashFunction =
/** @type {NonNullable<Output["hashFunction"]>} */
(compilation.outputOptions.hashFunction);
compilation.hooks.chunkIds.tap(PLUGIN_NAME, chunks => {
const chunkGraph = compilation.chunkGraph;
const context = this.context ? this.context : compiler.context;
const delimiter = this.delimiter;
const unnamedChunks = assignNames(
Array.from(chunks).filter(chunk => {
if (chunk.name) {
chunk.id = chunk.name;
chunk.ids = [chunk.name];
}
return chunk.id === null;
}),
chunk =>
getShortChunkName(
chunk,
chunkGraph,
context,
delimiter,
hashFunction,
compiler.root
),
chunk =>
getLongChunkName(
chunk,
chunkGraph,
context,
delimiter,
hashFunction,
compiler.root
),
compareChunksNatural(chunkGraph),
getUsedChunkIds(compilation),
(chunk, name) => {
chunk.id = name;
chunk.ids = [name];
}
);
if (unnamedChunks.length > 0) {
assignAscendingChunkIds(unnamedChunks, compilation);
}
});
});
}
}
module.exports = NamedChunkIdsPlugin;

View File

@ -0,0 +1,71 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { compareModulesByIdentifier } = require("../util/comparators");
const {
getShortModuleName,
getLongModuleName,
assignNames,
getUsedModuleIdsAndModules,
assignAscendingModuleIds
} = require("./IdHelpers");
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/**
* @typedef {object} NamedModuleIdsPluginOptions
* @property {string=} context context
*/
const PLUGIN_NAME = "NamedModuleIdsPlugin";
class NamedModuleIdsPlugin {
/**
* @param {NamedModuleIdsPluginOptions=} options options
*/
constructor(options = {}) {
this.options = options;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
const { root } = compiler;
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
const hashFunction =
/** @type {NonNullable<Output["hashFunction"]>} */
(compilation.outputOptions.hashFunction);
compilation.hooks.moduleIds.tap(PLUGIN_NAME, () => {
const chunkGraph = compilation.chunkGraph;
const context = this.options.context
? this.options.context
: compiler.context;
const [usedIds, modules] = getUsedModuleIdsAndModules(compilation);
const unnamedModules = assignNames(
modules,
m => getShortModuleName(m, context, root),
(m, shortName) =>
getLongModuleName(shortName, m, context, hashFunction, root),
compareModulesByIdentifier,
usedIds,
(m, name) => chunkGraph.setModuleId(m, name)
);
if (unnamedModules.length > 0) {
assignAscendingModuleIds(usedIds, unnamedModules, compilation);
}
});
});
}
}
module.exports = NamedModuleIdsPlugin;

View File

@ -0,0 +1,35 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { compareChunksNatural } = require("../util/comparators");
const { assignAscendingChunkIds } = require("./IdHelpers");
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
const PLUGIN_NAME = "NaturalChunkIdsPlugin";
class NaturalChunkIdsPlugin {
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.chunkIds.tap(PLUGIN_NAME, chunks => {
const chunkGraph = compilation.chunkGraph;
const compareNatural = compareChunksNatural(chunkGraph);
const chunksInNaturalOrder = Array.from(chunks).sort(compareNatural);
assignAscendingChunkIds(chunksInNaturalOrder, compilation);
});
});
}
}
module.exports = NaturalChunkIdsPlugin;

View File

@ -0,0 +1,41 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Florent Cailhol @ooflorent
*/
"use strict";
const {
compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const {
assignAscendingModuleIds,
getUsedModuleIdsAndModules
} = require("./IdHelpers");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
const PLUGIN_NAME = "NaturalModuleIdsPlugin";
class NaturalModuleIdsPlugin {
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.moduleIds.tap(PLUGIN_NAME, modules => {
const [usedIds, modulesInNaturalOrder] =
getUsedModuleIdsAndModules(compilation);
modulesInNaturalOrder.sort(
compareModulesByPreOrderIndexOrIdentifier(compilation.moduleGraph)
);
assignAscendingModuleIds(usedIds, modulesInNaturalOrder, compilation);
});
});
}
}
module.exports = NaturalModuleIdsPlugin;

View File

@ -0,0 +1,86 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { compareChunksNatural } = require("../util/comparators");
const createSchemaValidation = require("../util/create-schema-validation");
const { assignAscendingChunkIds } = require("./IdHelpers");
/** @typedef {import("../../declarations/plugins/ids/OccurrenceChunkIdsPlugin").OccurrenceChunkIdsPluginOptions} OccurrenceChunkIdsPluginOptions */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
const validate = createSchemaValidation(
require("../../schemas/plugins/ids/OccurrenceChunkIdsPlugin.check.js"),
() => require("../../schemas/plugins/ids/OccurrenceChunkIdsPlugin.json"),
{
name: "Occurrence Order Chunk Ids Plugin",
baseDataPath: "options"
}
);
const PLUGIN_NAME = "OccurrenceChunkIdsPlugin";
class OccurrenceChunkIdsPlugin {
/**
* @param {OccurrenceChunkIdsPluginOptions=} options options object
*/
constructor(options = {}) {
validate(options);
this.options = options;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
const prioritiseInitial = this.options.prioritiseInitial;
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.chunkIds.tap(PLUGIN_NAME, chunks => {
const chunkGraph = compilation.chunkGraph;
/** @type {Map<Chunk, number>} */
const occursInInitialChunksMap = new Map();
const compareNatural = compareChunksNatural(chunkGraph);
for (const c of chunks) {
let occurs = 0;
for (const chunkGroup of c.groupsIterable) {
for (const parent of chunkGroup.parentsIterable) {
if (parent.isInitial()) occurs++;
}
}
occursInInitialChunksMap.set(c, occurs);
}
const chunksInOccurrenceOrder = Array.from(chunks).sort((a, b) => {
if (prioritiseInitial) {
const aEntryOccurs =
/** @type {number} */
(occursInInitialChunksMap.get(a));
const bEntryOccurs =
/** @type {number} */
(occursInInitialChunksMap.get(b));
if (aEntryOccurs > bEntryOccurs) return -1;
if (aEntryOccurs < bEntryOccurs) return 1;
}
const aOccurs = a.getNumberOfGroups();
const bOccurs = b.getNumberOfGroups();
if (aOccurs > bOccurs) return -1;
if (aOccurs < bOccurs) return 1;
return compareNatural(a, b);
});
assignAscendingChunkIds(chunksInOccurrenceOrder, compilation);
});
});
}
}
module.exports = OccurrenceChunkIdsPlugin;

View File

@ -0,0 +1,161 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const {
compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const createSchemaValidation = require("../util/create-schema-validation");
const {
assignAscendingModuleIds,
getUsedModuleIdsAndModules
} = require("./IdHelpers");
/** @typedef {import("../../declarations/plugins/ids/OccurrenceModuleIdsPlugin").OccurrenceModuleIdsPluginOptions} OccurrenceModuleIdsPluginOptions */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
const validate = createSchemaValidation(
require("../../schemas/plugins/ids/OccurrenceModuleIdsPlugin.check.js"),
() => require("../../schemas/plugins/ids/OccurrenceModuleIdsPlugin.json"),
{
name: "Occurrence Order Module Ids Plugin",
baseDataPath: "options"
}
);
const PLUGIN_NAME = "OccurrenceModuleIdsPlugin";
class OccurrenceModuleIdsPlugin {
/**
* @param {OccurrenceModuleIdsPluginOptions=} options options object
*/
constructor(options = {}) {
validate(options);
this.options = options;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
const prioritiseInitial = this.options.prioritiseInitial;
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
const moduleGraph = compilation.moduleGraph;
compilation.hooks.moduleIds.tap(PLUGIN_NAME, () => {
const chunkGraph = compilation.chunkGraph;
const [usedIds, modulesInOccurrenceOrder] =
getUsedModuleIdsAndModules(compilation);
const occursInInitialChunksMap = new Map();
const occursInAllChunksMap = new Map();
const initialChunkChunkMap = new Map();
const entryCountMap = new Map();
for (const m of modulesInOccurrenceOrder) {
let initial = 0;
let entry = 0;
for (const c of chunkGraph.getModuleChunksIterable(m)) {
if (c.canBeInitial()) initial++;
if (chunkGraph.isEntryModuleInChunk(m, c)) entry++;
}
initialChunkChunkMap.set(m, initial);
entryCountMap.set(m, entry);
}
/**
* @param {Module} module module
* @returns {number} count of occurs
*/
const countOccursInEntry = module => {
let sum = 0;
for (const [
originModule,
connections
] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
if (!originModule) continue;
if (!connections.some(c => c.isTargetActive(undefined))) continue;
sum += initialChunkChunkMap.get(originModule) || 0;
}
return sum;
};
/**
* @param {Module} module module
* @returns {number} count of occurs
*/
const countOccurs = module => {
let sum = 0;
for (const [
originModule,
connections
] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
if (!originModule) continue;
const chunkModules =
chunkGraph.getNumberOfModuleChunks(originModule);
for (const c of connections) {
if (!c.isTargetActive(undefined)) continue;
if (!c.dependency) continue;
const factor = c.dependency.getNumberOfIdOccurrences();
if (factor === 0) continue;
sum += factor * chunkModules;
}
}
return sum;
};
if (prioritiseInitial) {
for (const m of modulesInOccurrenceOrder) {
const result =
countOccursInEntry(m) +
initialChunkChunkMap.get(m) +
entryCountMap.get(m);
occursInInitialChunksMap.set(m, result);
}
}
for (const m of modulesInOccurrenceOrder) {
const result =
countOccurs(m) +
chunkGraph.getNumberOfModuleChunks(m) +
entryCountMap.get(m);
occursInAllChunksMap.set(m, result);
}
const naturalCompare = compareModulesByPreOrderIndexOrIdentifier(
compilation.moduleGraph
);
modulesInOccurrenceOrder.sort((a, b) => {
if (prioritiseInitial) {
const aEntryOccurs = occursInInitialChunksMap.get(a);
const bEntryOccurs = occursInInitialChunksMap.get(b);
if (aEntryOccurs > bEntryOccurs) return -1;
if (aEntryOccurs < bEntryOccurs) return 1;
}
const aOccurs = occursInAllChunksMap.get(a);
const bOccurs = occursInAllChunksMap.get(b);
if (aOccurs > bOccurs) return -1;
if (aOccurs < bOccurs) return 1;
return naturalCompare(a, b);
});
assignAscendingModuleIds(
usedIds,
modulesInOccurrenceOrder,
compilation
);
});
});
}
}
module.exports = OccurrenceModuleIdsPlugin;

View File

@ -0,0 +1,150 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { WebpackError } = require("..");
const { getUsedModuleIdsAndModules } = require("./IdHelpers");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../util/fs").IntermediateFileSystem} IntermediateFileSystem */
const plugin = "SyncModuleIdsPlugin";
/**
* @typedef {object} SyncModuleIdsPluginOptions
* @property {string} path path to file
* @property {string=} context context for module names
* @property {((module: Module) => boolean)=} test selector for modules
* @property {"read" | "create" | "merge" | "update"=} mode operation mode (defaults to merge)
*/
class SyncModuleIdsPlugin {
/**
* @param {SyncModuleIdsPluginOptions} options options
*/
constructor({ path, context, test, mode }) {
this._path = path;
this._context = context;
this._test = test || (() => true);
const readAndWrite = !mode || mode === "merge" || mode === "update";
this._read = readAndWrite || mode === "read";
this._write = readAndWrite || mode === "create";
this._prune = mode === "update";
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
/** @type {Map<string, string | number>} */
let data;
let dataChanged = false;
if (this._read) {
compiler.hooks.readRecords.tapAsync(plugin, callback => {
const fs =
/** @type {IntermediateFileSystem} */
(compiler.intermediateFileSystem);
fs.readFile(this._path, (err, buffer) => {
if (err) {
if (err.code !== "ENOENT") {
return callback(err);
}
return callback();
}
const json = JSON.parse(/** @type {Buffer} */ (buffer).toString());
data = new Map();
for (const key of Object.keys(json)) {
data.set(key, json[key]);
}
dataChanged = false;
return callback();
});
});
}
if (this._write) {
compiler.hooks.emitRecords.tapAsync(plugin, callback => {
if (!data || !dataChanged) return callback();
/** @type {{[key: string]: string | number}} */
const json = {};
const sorted = Array.from(data).sort(([a], [b]) => (a < b ? -1 : 1));
for (const [key, value] of sorted) {
json[key] = value;
}
const fs =
/** @type {IntermediateFileSystem} */
(compiler.intermediateFileSystem);
fs.writeFile(this._path, JSON.stringify(json), callback);
});
}
compiler.hooks.thisCompilation.tap(plugin, compilation => {
const associatedObjectForCache = compiler.root;
const context = this._context || compiler.context;
if (this._read) {
compilation.hooks.reviveModules.tap(plugin, (_1, _2) => {
if (!data) return;
const { chunkGraph } = compilation;
const [usedIds, modules] = getUsedModuleIdsAndModules(
compilation,
this._test
);
for (const module of modules) {
const name = module.libIdent({
context,
associatedObjectForCache
});
if (!name) continue;
const id = data.get(name);
const idAsString = `${id}`;
if (usedIds.has(idAsString)) {
const err = new WebpackError(
`SyncModuleIdsPlugin: Unable to restore id '${id}' from '${this._path}' as it's already used.`
);
err.module = module;
compilation.errors.push(err);
}
chunkGraph.setModuleId(module, /** @type {string | number} */ (id));
usedIds.add(idAsString);
}
});
}
if (this._write) {
compilation.hooks.recordModules.tap(plugin, modules => {
const { chunkGraph } = compilation;
let oldData = data;
if (!oldData) {
oldData = data = new Map();
} else if (this._prune) {
data = new Map();
}
for (const module of modules) {
if (this._test(module)) {
const name = module.libIdent({
context,
associatedObjectForCache
});
if (!name) continue;
const id = chunkGraph.getModuleId(module);
if (id === null) continue;
const oldId = oldData.get(name);
if (oldId !== id) {
dataChanged = true;
} else if (data === oldData) {
continue;
}
data.set(name, id);
}
}
if (data.size !== oldData.size) dataChanged = true;
});
}
});
}
}
module.exports = SyncModuleIdsPlugin;