| | |
| | | } = require("../util/serialization"); |
| | | |
| | | /** @typedef {import("../../declarations/WebpackOptions").SnapshotOptions} SnapshotOptions */ |
| | | /** @typedef {import("../Compilation").FileSystemDependencies} FileSystemDependencies */ |
| | | /** @typedef {import("../Cache").Data} Data */ |
| | | /** @typedef {import("../Cache").Etag} Etag */ |
| | | /** @typedef {import("../Compiler")} Compiler */ |
| | |
| | | /** @typedef {import("../logging/Logger").Logger} Logger */ |
| | | /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */ |
| | | /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */ |
| | | /** @typedef {typeof import("../util/Hash")} Hash */ |
| | | /** @typedef {import("../util/Hash").HashFunction} HashFunction */ |
| | | /** @typedef {import("../util/fs").IntermediateFileSystem} IntermediateFileSystem */ |
| | | |
| | | /** @typedef {Set<string>} Items */ |
| | |
| | | |
| | | class PackContainer { |
| | | /** |
| | | * Creates an instance of PackContainer. |
| | | * @param {Pack} data stored data |
| | | * @param {string} version version identifier |
| | | * @param {Snapshot} buildSnapshot snapshot of all build dependencies |
| | |
| | | resolveResults, |
| | | resolveBuildDependenciesSnapshot |
| | | ) { |
| | | /** @type {Pack | (() => Pack) } */ |
| | | /** @type {Pack | (() => Pack)} */ |
| | | this.data = data; |
| | | /** @type {string} */ |
| | | this.version = version; |
| | |
| | | } |
| | | |
| | | /** |
| | | * Serializes this instance into the provided serializer context. |
| | | * @param {ObjectSerializerContext} context context |
| | | */ |
| | | serialize({ write, writeLazy }) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Restores this instance from the provided deserializer context. |
| | | * @param {ObjectDeserializerContext} context context |
| | | */ |
| | | deserialize({ read }) { |
| | |
| | | |
| | | class PackItemInfo { |
| | | /** |
| | | * Creates an instance of PackItemInfo. |
| | | * @param {string} identifier identifier of item |
| | | * @param {string | null | undefined} etag etag of item |
| | | * @param {Data} value fresh value of item |
| | |
| | | |
| | | class Pack { |
| | | /** |
| | | * Creates an instance of Pack. |
| | | * @param {Logger} logger a logger |
| | | * @param {number} maxAge max age of cache items |
| | | */ |
| | |
| | | this.itemInfo = new Map(); |
| | | /** @type {(string | undefined)[]} */ |
| | | this.requests = []; |
| | | /** @type {undefined | NodeJS.Timeout} */ |
| | | this.requestsTimeout = undefined; |
| | | /** @type {ItemInfo} */ |
| | | this.freshContent = new Map(); |
| | | /** @type {(undefined | PackContent)[]} */ |
| | | this.content = []; |
| | | /** @type {boolean} */ |
| | | this.invalid = false; |
| | | /** @type {Logger} */ |
| | | this.logger = logger; |
| | | /** @type {number} */ |
| | | this.maxAge = maxAge; |
| | | } |
| | | |
| | | /** |
| | | * Adds the provided identifier to the pack. |
| | | * @param {string} identifier identifier |
| | | */ |
| | | _addRequest(identifier) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns cached content. |
| | | * @param {string} identifier unique name for the resource |
| | | * @param {string | null} etag etag of the resource |
| | | * @returns {Data} cached content |
| | |
| | | } |
| | | |
| | | /** |
| | | * Updates value using the provided identifier. |
| | | * @param {string} identifier unique name for the resource |
| | | * @param {string | null} etag etag of the resource |
| | | * @param {Data} data cached content |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns new location of data entries. |
| | | * @returns {number} new location of data entries |
| | | */ |
| | | _findLocation() { |
| | | /** @type {number} */ |
| | | let i; |
| | | for (i = 0; i < this.content.length && this.content[i] !== undefined; i++); |
| | | return i; |
| | | } |
| | | |
| | | /** |
| | | * Gc and update location. |
| | | * @private |
| | | * @param {Items} items items |
| | | * @param {Items} usedItems used items |
| | |
| | | */ |
| | | _gcAndUpdateLocation(items, usedItems, newLoc) { |
| | | let count = 0; |
| | | /** @type {undefined | string} */ |
| | | let lastGC; |
| | | const now = Date.now(); |
| | | for (const identifier of items) { |
| | |
| | | } |
| | | |
| | | // 2. Check if minimum number is reached |
| | | /** @type {number[]} */ |
| | | let mergedIndices; |
| | | if ( |
| | | smallUsedContents.length >= CONTENT_COUNT_TO_MERGE || |
| | |
| | | return; |
| | | } |
| | | |
| | | /** @type {PackContent[] } */ |
| | | /** @type {PackContent[]} */ |
| | | const mergedContent = []; |
| | | |
| | | // 3. Remove old content entries |
| | |
| | | |
| | | // 5. Determine items for the unused content file |
| | | const unusedItems = new Set(content.items); |
| | | /** @type {Items} */ |
| | | const usedOfUnusedItems = new Set(); |
| | | for (const identifier of usedItems) { |
| | | unusedItems.delete(identifier); |
| | |
| | | await content.unpack( |
| | | "it should be splitted into used and unused items" |
| | | ); |
| | | /** @type {Content} */ |
| | | const map = new Map(); |
| | | for (const identifier of unusedItems) { |
| | | map.set( |
| | |
| | | await content.unpack( |
| | | "it contains old items that should be garbage collected" |
| | | ); |
| | | /** @type {Content} */ |
| | | const map = new Map(); |
| | | for (const identifier of items) { |
| | | map.set( |
| | |
| | | } |
| | | |
| | | /** |
| | | * Serializes this instance into the provided serializer context. |
| | | * @param {ObjectSerializerContext} context context |
| | | */ |
| | | serialize({ write, writeSeparate }) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Restores this instance from the provided deserializer context. |
| | | * @param {ObjectDeserializerContext & { logger: Logger }} context context |
| | | */ |
| | | deserialize({ read, logger }) { |
| | |
| | | |
| | | class PackContentItems { |
| | | /** |
| | | * Creates an instance of PackContentItems. |
| | | * @param {Content} map items |
| | | */ |
| | | constructor(map) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * @param {ObjectSerializerContext & { logger: Logger, profile: boolean | undefined }} context context |
| | | * Serializes this instance into the provided serializer context. |
| | | * @param {ObjectSerializerContext & { logger: Logger, profile: boolean | undefined }} context context |
| | | */ |
| | | serialize({ write, snapshot, rollback, logger, profile }) { |
| | | if (profile) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Restores this instance from the provided deserializer context. |
| | | * @param {ObjectDeserializerContext & { logger: Logger, profile: boolean | undefined }} context context |
| | | */ |
| | | deserialize({ read, logger, profile }) { |
| | | if (read()) { |
| | | this.map = read(); |
| | | } else if (profile) { |
| | | /** @type {Map<EXPECTED_ANY, EXPECTED_ANY>} */ |
| | | const map = new Map(); |
| | | let key = read(); |
| | | while (key !== null) { |
| | |
| | | } |
| | | this.map = map; |
| | | } else { |
| | | /** @type {Map<EXPECTED_ANY, EXPECTED_ANY>} */ |
| | | const map = new Map(); |
| | | let key = read(); |
| | | while (key !== null) { |
| | |
| | | "PackContentItems" |
| | | ); |
| | | |
| | | /** @typedef {(() => Promise<PackContentItems> | PackContentItems) & Partial<{ options: { size?: number }}>} LazyFunction */ |
| | | /** @typedef {(() => Promise<PackContentItems> | PackContentItems) & Partial<{ options: { size?: number } }>} LazyFunction */ |
| | | |
| | | class PackContent { |
| | | /* |
| | |
| | | */ |
| | | |
| | | /** |
| | | * Creates an instance of PackContent. |
| | | * @param {Items} items keys |
| | | * @param {Items} usedItems used keys |
| | | * @param {PackContentItems | (() => Promise<PackContentItems>)} dataOrFn sync or async content |
| | |
| | | * @param {string=} lazyName name of dataOrFn for logging |
| | | */ |
| | | constructor(items, usedItems, dataOrFn, logger, lazyName) { |
| | | /** @type {Items} */ |
| | | this.items = items; |
| | | /** @type {LazyFunction | undefined} */ |
| | | this.lazy = typeof dataOrFn === "function" ? dataOrFn : undefined; |
| | | /** @type {Content | undefined} */ |
| | | this.content = typeof dataOrFn === "function" ? undefined : dataOrFn.map; |
| | | /** @type {boolean} */ |
| | | this.outdated = false; |
| | | /** @type {Items} */ |
| | | this.used = usedItems; |
| | | /** @type {Logger | undefined} */ |
| | | this.logger = logger; |
| | | /** @type {string | undefined} */ |
| | | this.lazyName = lazyName; |
| | | } |
| | | |
| | | /** |
| | | * Returns result. |
| | | * @param {string} identifier identifier |
| | | * @returns {string | Promise<string>} result |
| | | */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns maybe a promise if lazy. |
| | | * @param {string} reason explanation why unpack is necessary |
| | | * @returns {void | Promise<void>} maybe a promise if lazy |
| | | */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the estimated size for the requested source type. |
| | | * @returns {number} size of the content or -1 if not known |
| | | */ |
| | | getSize() { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Processes the provided identifier. |
| | | * @param {string} identifier identifier |
| | | */ |
| | | delete(identifier) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Processes the provided write. |
| | | * @param {(lazy: LazyFunction) => (() => PackContentItems | Promise<PackContentItems>)} write write function |
| | | * @returns {void} |
| | | */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * Allow collecting memory. |
| | | * @param {Buffer} buf buffer |
| | | * @returns {Buffer} buffer that can be collected |
| | | */ |
| | |
| | | |
| | | class PackFileCacheStrategy { |
| | | /** |
| | | * Creates an instance of PackFileCacheStrategy. |
| | | * @param {object} options options |
| | | * @param {Compiler} options.compiler the compiler |
| | | * @param {IntermediateFileSystem} options.fs the filesystem |
| | |
| | | * @param {Logger} options.logger a logger |
| | | * @param {SnapshotOptions} options.snapshot options regarding snapshotting |
| | | * @param {number} options.maxAge max age of cache items |
| | | * @param {boolean | undefined} options.profile track and log detailed timing information for individual cache items |
| | | * @param {boolean | undefined} options.allowCollectingMemory allow to collect unused memory created during deserialization |
| | | * @param {false | "gzip" | "brotli" | undefined} options.compression compression used |
| | | * @param {boolean | undefined} options.readonly disable storing cache into filesystem |
| | | * @param {boolean=} options.profile track and log detailed timing information for individual cache items |
| | | * @param {boolean=} options.allowCollectingMemory allow to collect unused memory created during deserialization |
| | | * @param {false | "gzip" | "brotli"=} options.compression compression used |
| | | * @param {boolean=} options.readonly disable storing cache into filesystem |
| | | */ |
| | | constructor({ |
| | | compiler, |
| | |
| | | compression, |
| | | readonly |
| | | }) { |
| | | /** @type {import("../serialization/Serializer")<PackContainer, null, {}>} */ |
| | | /** @type {import("../serialization/Serializer")<PackContainer, null, EXPECTED_OBJECT>} */ |
| | | this.fileSerializer = createFileSerializer( |
| | | fs, |
| | | /** @type {string | Hash} */ |
| | | /** @type {HashFunction} */ |
| | | (compiler.options.output.hashFunction) |
| | | ); |
| | | /** @type {FileSystemInfo} */ |
| | | this.fileSystemInfo = new FileSystemInfo(fs, { |
| | | managedPaths: snapshot.managedPaths, |
| | | immutablePaths: snapshot.immutablePaths, |
| | | logger: logger.getChildLogger("webpack.FileSystemInfo"), |
| | | hashFunction: compiler.options.output.hashFunction |
| | | }); |
| | | /** @type {Compiler} */ |
| | | this.compiler = compiler; |
| | | /** @type {string} */ |
| | | this.context = context; |
| | | /** @type {string} */ |
| | | this.cacheLocation = cacheLocation; |
| | | /** @type {string} */ |
| | | this.version = version; |
| | | /** @type {Logger} */ |
| | | this.logger = logger; |
| | | /** @type {number} */ |
| | | this.maxAge = maxAge; |
| | | /** @type {boolean | undefined} */ |
| | | this.profile = profile; |
| | | /** @type {boolean | undefined} */ |
| | | this.readonly = readonly; |
| | | /** @type {boolean | undefined} */ |
| | | this.allowCollectingMemory = allowCollectingMemory; |
| | | /** @type {false | "gzip" | "brotli" | undefined} */ |
| | | this.compression = compression; |
| | | /** @type {string} */ |
| | | this._extension = |
| | | compression === "brotli" |
| | | ? ".pack.br" |
| | | : compression === "gzip" |
| | | ? ".pack.gz" |
| | | : ".pack"; |
| | | /** @type {SnapshotOptions} */ |
| | | this.snapshot = snapshot; |
| | | /** @type {BuildDependencies} */ |
| | | this.buildDependencies = new Set(); |
| | | /** @type {LazySet<string>} */ |
| | | /** @type {FileSystemDependencies} */ |
| | | this.newBuildDependencies = new LazySet(); |
| | | /** @type {Snapshot | undefined} */ |
| | | this.resolveBuildDependenciesSnapshot = undefined; |
| | |
| | | this.buildSnapshot = undefined; |
| | | /** @type {Promise<Pack> | undefined} */ |
| | | this.packPromise = this._openPack(); |
| | | /** @type {Promise<void>} */ |
| | | this.storePromise = Promise.resolve(); |
| | | } |
| | | |
| | | /** |
| | | * Returns pack. |
| | | * @returns {Promise<Pack>} pack |
| | | */ |
| | | _getPack() { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the pack. |
| | | * @returns {Promise<Pack>} the pack |
| | | */ |
| | | _openPack() { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns promise. |
| | | * @param {string} identifier unique name for the resource |
| | | * @param {Etag | null} etag etag of the resource |
| | | * @param {Data} data cached content |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns promise to the cached content. |
| | | * @param {string} identifier unique name for the resource |
| | | * @param {Etag | null} etag etag of the resource |
| | | * @returns {Promise<Data>} promise to the cached content |
| | |
| | | } |
| | | |
| | | /** |
| | | * @param {LazySet<string> | Iterable<string>} dependencies dependencies to store |
| | | * Stores build dependencies. |
| | | * @param {FileSystemDependencies | Iterable<string>} dependencies dependencies to store |
| | | */ |
| | | storeBuildDependencies(dependencies) { |
| | | if (this.readonly) return; |
| | |
| | | if (!pack.invalid) return; |
| | | this.packPromise = undefined; |
| | | this.logger.log("Storing pack..."); |
| | | /** @type {undefined | Promise<void>} */ |
| | | let promise; |
| | | /** @type {Set<string>} */ |
| | | const newBuildDependencies = new Set(); |
| | | for (const dep of this.newBuildDependencies) { |
| | | if (!this.buildDependencies.has(dep)) { |
| | |
| | | ); |
| | | promise = new Promise( |
| | | /** |
| | | * Handles the callback logic for this hook. |
| | | * @param {(value?: undefined) => void} resolve resolve |
| | | * @param {(reason?: Error) => void} reject reject |
| | | */ |