feat: refactoring project

This commit is contained in:
Carlos
2024-11-23 14:56:07 -05:00
parent f0c2a50c18
commit 1c6db5818d
2351 changed files with 39323 additions and 60326 deletions

View File

@@ -11,7 +11,7 @@ const ProgressPlugin = require("../ProgressPlugin");
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("./PackFileCacheStrategy")} PackFileCacheStrategy */
const BUILD_DEPENDENCIES_KEY = Symbol();
const BUILD_DEPENDENCIES_KEY = Symbol("build dependencies key");
class IdleFileCachePlugin {
/**
@@ -38,7 +38,7 @@ class IdleFileCachePlugin {
* @returns {void}
*/
apply(compiler) {
let strategy = this.strategy;
const strategy = this.strategy;
const idleTimeout = this.idleTimeout;
const idleTimeoutForInitialStore = Math.min(
idleTimeout,
@@ -119,7 +119,7 @@ class IdleFileCachePlugin {
currentIdlePromise = promise.then(() => strategy.afterAllStored());
if (reportProgress) {
currentIdlePromise = currentIdlePromise.then(() => {
reportProgress(1, `stored`);
reportProgress(1, "stored");
});
}
return currentIdlePromise.then(() => {
@@ -175,7 +175,7 @@ class IdleFileCachePlugin {
}
};
/** @type {ReturnType<typeof setTimeout> | undefined} */
let idleTimer = undefined;
let idleTimer;
compiler.cache.hooks.beginIdle.tap(
{ name: "IdleFileCachePlugin", stage: Cache.STAGE_DISK },
() => {

View File

@@ -20,6 +20,7 @@ class MemoryWithGcCachePlugin {
constructor({ maxGenerations }) {
this._maxGenerations = maxGenerations;
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
@@ -106,12 +107,11 @@ class MemoryWithGcCachePlugin {
oldCache.delete(identifier);
cache.set(identifier, cacheEntry);
return null;
} else {
if (cacheEntry.etag !== etag) return null;
oldCache.delete(identifier);
cache.set(identifier, cacheEntry);
return cacheEntry.data;
}
if (cacheEntry.etag !== etag) return null;
oldCache.delete(identifier);
cache.set(identifier, cacheEntry);
return cacheEntry.data;
}
gotHandlers.push((result, callback) => {
if (result === undefined) {

View File

@@ -98,7 +98,7 @@ const MAX_TIME_IN_FRESH_PACK = 1 * 60 * 1000; // 1 min
class PackItemInfo {
/**
* @param {string} identifier identifier of item
* @param {string | null} etag etag of item
* @param {string | null | undefined} etag etag of item
* @param {any} value fresh value of item
*/
constructor(identifier, etag, value) {
@@ -160,19 +160,18 @@ class Pack {
const info = this.itemInfo.get(identifier);
this._addRequest(identifier);
if (info === undefined) {
return undefined;
return;
}
if (info.etag !== etag) return null;
info.lastAccess = Date.now();
const loc = info.location;
if (loc === -1) {
return info.freshValue;
} else {
if (!this.content[loc]) {
return undefined;
}
return /** @type {PackContent} */ (this.content[loc]).get(identifier);
}
if (!this.content[loc]) {
return;
}
return /** @type {PackContent} */ (this.content[loc]).get(identifier);
}
/**
@@ -269,20 +268,21 @@ class Pack {
}
_persistFreshContent() {
/** @typedef {{ items: Items, map: Map<string, any>, loc: number }} PackItem */
const itemsCount = this.freshContent.size;
if (itemsCount > 0) {
const packCount = Math.ceil(itemsCount / MAX_ITEMS_IN_FRESH_PACK);
const itemsPerPack = Math.ceil(itemsCount / packCount);
/** @type {PackItem[]} */
const packs = [];
let i = 0;
let ignoreNextTimeTick = false;
const createNextPack = () => {
const loc = this._findLocation();
this.content[loc] = null; // reserve
this.content[loc] = /** @type {EXPECTED_ANY} */ (null); // reserve
/** @type {PackItem} */
const pack = {
/** @type {Items} */
items: new Set(),
/** @type {Map<string, any>} */
map: new Map(),
loc
};
@@ -408,7 +408,9 @@ class Pack {
await content.unpack(
"it should be merged with other small pack contents"
);
for (const [identifier, value] of content.content) {
for (const [identifier, value] of /** @type {Content} */ (
content.content
)) {
map.set(identifier, value);
}
});
@@ -424,7 +426,7 @@ class Pack {
mergedItems,
mergedUsedItems,
memoize(async () => {
/** @type {Map<string, any>} */
/** @type {Content} */
const map = new Map();
await Promise.all(addToMergedMap.map(fn => fn(map)));
return new PackContentItems(map);
@@ -472,7 +474,11 @@ class Pack {
);
const map = new Map();
for (const identifier of usedItems) {
map.set(identifier, content.content.get(identifier));
map.set(
identifier,
/** @type {Content} */
(content.content).get(identifier)
);
}
return new PackContentItems(map);
}
@@ -499,7 +505,11 @@ class Pack {
);
const map = new Map();
for (const identifier of unusedItems) {
map.set(identifier, content.content.get(identifier));
map.set(
identifier,
/** @type {Content} */
(content.content).get(identifier)
);
}
return new PackContentItems(map);
}
@@ -528,7 +538,7 @@ class Pack {
*/
_gcOldestContent() {
/** @type {PackItemInfo | undefined} */
let oldest = undefined;
let oldest;
for (const info of this.itemInfo.values()) {
if (oldest === undefined || info.lastAccess < oldest.lastAccess) {
oldest = info;
@@ -553,7 +563,11 @@ class Pack {
);
const map = new Map();
for (const identifier of items) {
map.set(identifier, content.content.get(identifier));
map.set(
identifier,
/** @type {Content} */
(content.content).get(identifier)
);
}
return new PackContentItems(map);
})
@@ -634,7 +648,8 @@ class Pack {
)
);
for (const identifier of items) {
this.itemInfo.get(identifier).location = idx;
/** @type {PackItemInfo} */
(this.itemInfo.get(identifier)).location = idx;
}
}
items = read();
@@ -644,9 +659,11 @@ class Pack {
makeSerializable(Pack, "webpack/lib/cache/PackFileCacheStrategy", "Pack");
/** @typedef {Map<string, any>} Content */
class PackContentItems {
/**
* @param {Map<string, any>} map items
* @param {Content} map items
*/
constructor(map) {
this.map = map;
@@ -677,16 +694,21 @@ class PackContentItems {
logger.log(`Serialization of '${key}': ${duration} ms`);
else logger.debug(`Serialization of '${key}': ${duration} ms`);
}
} catch (e) {
} catch (err) {
rollback(s);
if (e === NOT_SERIALIZABLE) continue;
if (err === NOT_SERIALIZABLE) continue;
const msg = "Skipped not serializable cache item";
if (e.message.includes("ModuleBuildError")) {
logger.log(`${msg} (in build error): ${e.message}`);
logger.debug(`${msg} '${key}' (in build error): ${e.stack}`);
const notSerializableErr = /** @type {Error} */ (err);
if (notSerializableErr.message.includes("ModuleBuildError")) {
logger.log(
`${msg} (in build error): ${notSerializableErr.message}`
);
logger.debug(
`${msg} '${key}' (in build error): ${notSerializableErr.stack}`
);
} else {
logger.warn(`${msg}: ${e.message}`);
logger.debug(`${msg} '${key}': ${e.stack}`);
logger.warn(`${msg}: ${notSerializableErr.message}`);
logger.debug(`${msg} '${key}': ${notSerializableErr.stack}`);
}
}
}
@@ -698,7 +720,7 @@ class PackContentItems {
try {
write(true);
write(this.map);
} catch (e) {
} catch (_err) {
rollback(s);
// Try to serialize each item on it's own
@@ -708,13 +730,14 @@ class PackContentItems {
try {
write(key);
write(value);
} catch (e) {
} catch (err) {
rollback(s);
if (e === NOT_SERIALIZABLE) continue;
if (err === NOT_SERIALIZABLE) continue;
const notSerializableErr = /** @type {Error} */ (err);
logger.warn(
`Skipped not serializable cache item '${key}': ${e.message}`
`Skipped not serializable cache item '${key}': ${notSerializableErr.message}`
);
logger.debug(e.stack);
logger.debug(notSerializableErr.stack);
}
}
write(null);
@@ -768,6 +791,8 @@ makeSerializable(
"PackContentItems"
);
/** @typedef {(function(): Promise<PackContentItems> | PackContentItems)} LazyFn */
class PackContent {
/*
This class can be in these states:
@@ -797,9 +822,9 @@ class PackContent {
*/
constructor(items, usedItems, dataOrFn, logger, lazyName) {
this.items = items;
/** @type {(function(): Promise<PackContentItems> | PackContentItems) | undefined} */
/** @type {LazyFn | undefined} */
this.lazy = typeof dataOrFn === "function" ? dataOrFn : undefined;
/** @type {Map<string, any> | undefined} */
/** @type {Content | undefined} */
this.content = typeof dataOrFn === "function" ? undefined : dataOrFn.map;
this.outdated = false;
this.used = usedItems;
@@ -817,6 +842,7 @@ class PackContent {
return this.content.get(identifier);
}
const logger = /** @type {Logger} */ (this.logger);
// We are in state B
const { lazyName } = this;
/** @type {string | undefined} */
@@ -827,35 +853,41 @@ class PackContent {
timeMessage = `restore cache content ${lazyName} (${formatSize(
this.getSize()
)})`;
this.logger.log(
logger.log(
`starting to restore cache content ${lazyName} (${formatSize(
this.getSize()
)}) because of request to: ${identifier}`
);
this.logger.time(timeMessage);
logger.time(timeMessage);
}
const value = this.lazy();
const value = /** @type {LazyFn} */ (this.lazy)();
if ("then" in value) {
return value.then(data => {
const map = data.map;
if (timeMessage) {
this.logger.timeEnd(timeMessage);
logger.timeEnd(timeMessage);
}
// Move to state C
this.content = map;
this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
this.lazy = SerializerMiddleware.unMemoizeLazy(
/** @type {LazyFn} */
(this.lazy)
);
return map.get(identifier);
});
} else {
const map = value.map;
if (timeMessage) {
this.logger.timeEnd(timeMessage);
}
// Move to state C
this.content = map;
this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
return map.get(identifier);
}
const map = value.map;
if (timeMessage) {
logger.timeEnd(timeMessage);
}
// Move to state C
this.content = map;
this.lazy = SerializerMiddleware.unMemoizeLazy(
/** @type {LazyFn} */
(this.lazy)
);
return map.get(identifier);
}
/**
@@ -865,6 +897,7 @@ class PackContent {
unpack(reason) {
if (this.content) return;
const logger = /** @type {Logger} */ (this.logger);
// Move from state B to C
if (this.lazy) {
const { lazyName } = this;
@@ -876,27 +909,26 @@ class PackContent {
timeMessage = `unpack cache content ${lazyName} (${formatSize(
this.getSize()
)})`;
this.logger.log(
logger.log(
`starting to unpack cache content ${lazyName} (${formatSize(
this.getSize()
)}) because ${reason}`
);
this.logger.time(timeMessage);
logger.time(timeMessage);
}
const value = this.lazy();
if ("then" in value) {
return value.then(data => {
if (timeMessage) {
this.logger.timeEnd(timeMessage);
logger.timeEnd(timeMessage);
}
this.content = data.map;
});
} else {
if (timeMessage) {
this.logger.timeEnd(timeMessage);
}
this.content = value.map;
}
if (timeMessage) {
logger.timeEnd(timeMessage);
}
this.content = value.map;
}
}
@@ -944,7 +976,7 @@ class PackContent {
}
if (this.content) {
// State A2 or C2
/** @type {Map<string, any>} */
/** @type {Content} */
const map = new Map();
for (const item of this.items) {
map.set(item, this.content.get(item));
@@ -957,6 +989,7 @@ class PackContent {
);
return;
}
const logger = /** @type {Logger} */ (this.logger);
// State B2
const { lazyName } = this;
/** @type {string | undefined} */
@@ -967,31 +1000,34 @@ class PackContent {
timeMessage = `unpack cache content ${lazyName} (${formatSize(
this.getSize()
)})`;
this.logger.log(
logger.log(
`starting to unpack cache content ${lazyName} (${formatSize(
this.getSize()
)}) because it's outdated and need to be serialized`
);
this.logger.time(timeMessage);
logger.time(timeMessage);
}
const value = this.lazy();
const value = /** @type {LazyFn} */ (this.lazy)();
this.outdated = false;
if ("then" in value) {
// Move to state B1
this.lazy = write(() =>
value.then(data => {
if (timeMessage) {
this.logger.timeEnd(timeMessage);
logger.timeEnd(timeMessage);
}
const oldMap = data.map;
/** @type {Map<string, any>} */
/** @type {Content} */
const map = new Map();
for (const item of this.items) {
map.set(item, oldMap.get(item));
}
// Move to state C1 (or maybe C2)
this.content = map;
this.lazy = SerializerMiddleware.unMemoizeLazy(this.lazy);
this.lazy = SerializerMiddleware.unMemoizeLazy(
/** @type {LazyFn} */
(this.lazy)
);
return new PackContentItems(map);
})
@@ -999,10 +1035,10 @@ class PackContent {
} else {
// Move to state C1
if (timeMessage) {
this.logger.timeEnd(timeMessage);
logger.timeEnd(timeMessage);
}
const oldMap = value.map;
/** @type {Map<string, any>} */
/** @type {Content} */
const map = new Map();
for (const item of this.items) {
map.set(item, oldMap.get(item));
@@ -1148,19 +1184,19 @@ class PackFileCacheStrategy {
})
.then(packContainer => {
logger.timeEnd("restore cache container");
if (!packContainer) return undefined;
if (!packContainer) return;
if (!(packContainer instanceof PackContainer)) {
logger.warn(
`Restored pack from ${cacheLocation}${this._extension}, but contained content is unexpected.`,
packContainer
);
return undefined;
return;
}
if (packContainer.version !== version) {
logger.log(
`Restored pack from ${cacheLocation}${this._extension}, but version doesn't match.`
);
return undefined;
return;
}
logger.time("check build dependencies");
return Promise.all([
@@ -1321,7 +1357,7 @@ class PackFileCacheStrategy {
pack.stopCapturingRequests();
if (!pack.invalid) return;
this.packPromise = undefined;
this.logger.log(`Storing pack...`);
this.logger.log("Storing pack...");
let promise;
const newBuildDependencies = new Set();
for (const dep of this.newBuildDependencies) {
@@ -1439,7 +1475,7 @@ class PackFileCacheStrategy {
}
return promise.then(() => {
if (reportProgress) reportProgress(0.8, "serialize pack");
this.logger.time(`store pack`);
this.logger.time("store pack");
const updatedBuildDependencies = new Set(this.buildDependencies);
for (const dep of newBuildDependencies) {
updatedBuildDependencies.add(dep);
@@ -1447,10 +1483,13 @@ class PackFileCacheStrategy {
const content = new PackContainer(
pack,
this.version,
/** @type {Snapshot} */ (this.buildSnapshot),
/** @type {Snapshot} */
(this.buildSnapshot),
updatedBuildDependencies,
this.resolveResults,
this.resolveBuildDependenciesSnapshot
/** @type {ResolveResults} */
(this.resolveResults),
/** @type {Snapshot} */
(this.resolveBuildDependenciesSnapshot)
);
return this.fileSerializer
.serialize(content, {
@@ -1464,7 +1503,7 @@ class PackFileCacheStrategy {
this.buildDependencies.add(dep);
}
this.newBuildDependencies.clear();
this.logger.timeEnd(`store pack`);
this.logger.timeEnd("store pack");
const stats = pack.getContentStats();
this.logger.log(
"Stored pack (%d items, %d files, %d MiB)",
@@ -1474,7 +1513,7 @@ class PackFileCacheStrategy {
);
})
.catch(err => {
this.logger.timeEnd(`store pack`);
this.logger.timeEnd("store pack");
this.logger.warn(`Caching failed for pack: ${err}`);
this.logger.debug(err.stack);
});

View File

@@ -8,23 +8,45 @@
const LazySet = require("../util/LazySet");
const makeSerializable = require("../util/makeSerializable");
/** @typedef {import("enhanced-resolve").ResolveContext} ResolveContext */
/** @typedef {import("enhanced-resolve").ResolveOptions} ResolveOptions */
/** @typedef {import("enhanced-resolve").ResolveRequest} ResolveRequest */
/** @typedef {import("enhanced-resolve").Resolver} Resolver */
/** @typedef {import("../CacheFacade").ItemCacheFacade} ItemCacheFacade */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../FileSystemInfo")} FileSystemInfo */
/** @typedef {import("../FileSystemInfo").Snapshot} Snapshot */
/** @typedef {import("../FileSystemInfo").SnapshotOptions} SnapshotOptions */
/** @typedef {import("../ResolverFactory").ResolveOptionsWithDependencyType} ResolveOptionsWithDependencyType */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/**
* @template T
* @typedef {import("tapable").SyncHook<T>} SyncHook
*/
class CacheEntry {
/**
* @param {ResolveRequest} result result
* @param {Snapshot} snapshot snapshot
*/
constructor(result, snapshot) {
this.result = result;
this.snapshot = snapshot;
}
/**
* @param {ObjectSerializerContext} context context
*/
serialize({ write }) {
write(this.result);
write(this.snapshot);
}
/**
* @param {ObjectDeserializerContext} context context
*/
deserialize({ read }) {
this.result = read();
this.snapshot = read();
@@ -36,7 +58,7 @@ makeSerializable(CacheEntry, "webpack/lib/cache/ResolverCachePlugin");
/**
* @template T
* @param {Set<T> | LazySet<T>} set set to add items to
* @param {Set<T> | LazySet<T>} otherSet set to add items from
* @param {Set<T> | LazySet<T> | Iterable<T>} otherSet set to add items from
* @returns {void}
*/
const addAllToSet = (set, otherSet) => {
@@ -50,7 +72,8 @@ const addAllToSet = (set, otherSet) => {
};
/**
* @param {object} object an object
* @template {object} T
* @param {T} object an object
* @param {boolean} excludeContext if true, context is not included in string
* @returns {string} stringified version
*/
@@ -59,11 +82,10 @@ const objectToString = (object, excludeContext) => {
for (const key in object) {
if (excludeContext && key === "context") continue;
const value = object[key];
if (typeof value === "object" && value !== null) {
str += `|${key}=[${objectToString(value, false)}|]`;
} else {
str += `|${key}=|${value}`;
}
str +=
typeof value === "object" && value !== null
? `|${key}=[${objectToString(value, false)}|]`
: `|${key}=|${value}`;
}
return str;
};
@@ -78,6 +100,7 @@ class ResolverCachePlugin {
const cache = compiler.getCache("ResolverCachePlugin");
/** @type {FileSystemInfo} */
let fileSystemInfo;
/** @type {SnapshotOptions | undefined} */
let snapshotOptions;
let realResolves = 0;
let cachedResolves = 0;
@@ -101,12 +124,16 @@ class ResolverCachePlugin {
}
});
});
/** @typedef {function((Error | null)=, ResolveRequest=): void} Callback */
/** @typedef {ResolveRequest & { _ResolverCachePluginCacheMiss: true }} ResolveRequestWithCacheMiss */
/**
* @param {ItemCacheFacade} itemCache cache
* @param {Resolver} resolver the resolver
* @param {object} resolveContext context for resolving meta info
* @param {object} request the request info object
* @param {function((Error | null)=, object=): void} callback callback function
* @param {ResolveContext} resolveContext context for resolving meta info
* @param {ResolveRequest} request the request info object
* @param {Callback} callback callback function
* @returns {void}
*/
const doRealResolve = (
@@ -117,10 +144,13 @@ class ResolverCachePlugin {
callback
) => {
realResolves++;
const newRequest = {
_ResolverCachePluginCacheMiss: true,
...request
};
const newRequest =
/** @type {ResolveRequestWithCacheMiss} */
({
_ResolverCachePluginCacheMiss: true,
...request
});
/** @type {ResolveContext} */
const newResolveContext = {
...resolveContext,
stack: new Set(),
@@ -131,16 +161,25 @@ class ResolverCachePlugin {
/** @type {LazySet<string>} */
contextDependencies: new LazySet()
};
/** @type {ResolveRequest[] | undefined} */
let yieldResult;
let withYield = false;
if (typeof newResolveContext.yield === "function") {
yieldResult = [];
withYield = true;
newResolveContext.yield = obj => yieldResult.push(obj);
newResolveContext.yield = obj =>
/** @type {ResolveRequest[]} */
(yieldResult).push(obj);
}
/**
* @param {"fileDependencies" | "contextDependencies" | "missingDependencies"} key key
*/
const propagate = key => {
if (resolveContext[key]) {
addAllToSet(resolveContext[key], newResolveContext[key]);
addAllToSet(
/** @type {Set<string>} */ (resolveContext[key]),
/** @type {Set<string>} */ (newResolveContext[key])
);
}
};
const resolveTime = Date.now();
@@ -159,25 +198,43 @@ class ResolverCachePlugin {
const missingDependencies = newResolveContext.missingDependencies;
fileSystemInfo.createSnapshot(
resolveTime,
fileDependencies,
contextDependencies,
missingDependencies,
/** @type {Set<string>} */
(fileDependencies),
/** @type {Set<string>} */
(contextDependencies),
/** @type {Set<string>} */
(missingDependencies),
snapshotOptions,
(err, snapshot) => {
if (err) return callback(err);
const resolveResult = withYield ? yieldResult : result;
// since we intercept resolve hook
// we still can get result in callback
if (withYield && result) yieldResult.push(result);
if (withYield && result)
/** @type {ResolveRequest[]} */ (yieldResult).push(result);
if (!snapshot) {
if (resolveResult) return callback(null, resolveResult);
if (resolveResult)
return callback(
null,
/** @type {ResolveRequest} */
(resolveResult)
);
return callback();
}
itemCache.store(
new CacheEntry(resolveResult, snapshot),
new CacheEntry(
/** @type {ResolveRequest} */
(resolveResult),
snapshot
),
storeErr => {
if (storeErr) return callback(storeErr);
if (resolveResult) return callback(null, resolveResult);
if (resolveResult)
return callback(
null,
/** @type {ResolveRequest} */
(resolveResult)
);
callback();
}
);
@@ -188,174 +245,192 @@ class ResolverCachePlugin {
};
compiler.resolverFactory.hooks.resolver.intercept({
factory(type, hook) {
/** @type {Map<string, (function(Error=, object=): void)[]>} */
/** @type {Map<string, (function(Error=, ResolveRequest=): void)[]>} */
const activeRequests = new Map();
/** @type {Map<string, [function(Error=, object=): void, function(Error=, object=): void][]>} */
/** @type {Map<string, [function(Error=, ResolveRequest=): void, NonNullable<ResolveContext["yield"]>][]>} */
const activeRequestsWithYield = new Map();
hook.tap(
"ResolverCachePlugin",
/**
* @param {Resolver} resolver the resolver
* @param {object} options resolve options
* @param {object} userOptions resolve options passed by the user
* @returns {void}
*/
(resolver, options, userOptions) => {
if (options.cache !== true) return;
const optionsIdent = objectToString(userOptions, false);
const cacheWithContext =
options.cacheWithContext !== undefined
? options.cacheWithContext
: false;
resolver.hooks.resolve.tapAsync(
{
name: "ResolverCachePlugin",
stage: -100
},
(request, resolveContext, callback) => {
if (
/** @type {TODO} */ (request)._ResolverCachePluginCacheMiss ||
!fileSystemInfo
) {
return callback();
}
const withYield = typeof resolveContext.yield === "function";
const identifier = `${type}${
withYield ? "|yield" : "|default"
}${optionsIdent}${objectToString(request, !cacheWithContext)}`;
/** @type {SyncHook<[Resolver, ResolveOptions, ResolveOptionsWithDependencyType]>} */
(hook).tap("ResolverCachePlugin", (resolver, options, userOptions) => {
if (/** @type {TODO} */ (options).cache !== true) return;
const optionsIdent = objectToString(userOptions, false);
const cacheWithContext =
options.cacheWithContext !== undefined
? options.cacheWithContext
: false;
resolver.hooks.resolve.tapAsync(
{
name: "ResolverCachePlugin",
stage: -100
},
(request, resolveContext, callback) => {
if (
/** @type {ResolveRequestWithCacheMiss} */
(request)._ResolverCachePluginCacheMiss ||
!fileSystemInfo
) {
return callback();
}
const withYield = typeof resolveContext.yield === "function";
const identifier = `${type}${
withYield ? "|yield" : "|default"
}${optionsIdent}${objectToString(request, !cacheWithContext)}`;
if (withYield) {
const activeRequest = activeRequestsWithYield.get(identifier);
if (activeRequest) {
activeRequest[0].push(callback);
activeRequest[1].push(
/** @type {TODO} */ (resolveContext.yield)
);
return;
}
} else {
const activeRequest = activeRequests.get(identifier);
if (activeRequest) {
activeRequest.push(callback);
return;
}
}
const itemCache = cache.getItemCache(identifier, null);
let callbacks, yields;
const done = withYield
? (err, result) => {
if (callbacks === undefined) {
if (err) {
callback(err);
} else {
if (result)
for (const r of result) resolveContext.yield(r);
callback(null, null);
}
yields = undefined;
callbacks = false;
} else {
if (err) {
for (const cb of callbacks) cb(err);
} else {
for (let i = 0; i < callbacks.length; i++) {
const cb = callbacks[i];
const yield_ = yields[i];
if (result) for (const r of result) yield_(r);
cb(null, null);
}
}
activeRequestsWithYield.delete(identifier);
yields = undefined;
callbacks = false;
}
}
: (err, result) => {
if (callbacks === undefined) {
callback(err, result);
callbacks = false;
} else {
for (const callback of callbacks) {
callback(err, result);
}
activeRequests.delete(identifier);
callbacks = false;
}
};
/**
* @param {Error=} err error if any
* @param {CacheEntry=} cacheEntry cache entry
* @returns {void}
*/
const processCacheResult = (err, cacheEntry) => {
if (err) return done(err);
if (cacheEntry) {
const { snapshot, result } = cacheEntry;
fileSystemInfo.checkSnapshotValid(
snapshot,
(err, valid) => {
if (err || !valid) {
cacheInvalidResolves++;
return doRealResolve(
itemCache,
resolver,
resolveContext,
request,
done
);
}
cachedResolves++;
if (resolveContext.missingDependencies) {
addAllToSet(
/** @type {LazySet<string>} */
(resolveContext.missingDependencies),
snapshot.getMissingIterable()
);
}
if (resolveContext.fileDependencies) {
addAllToSet(
/** @type {LazySet<string>} */
(resolveContext.fileDependencies),
snapshot.getFileIterable()
);
}
if (resolveContext.contextDependencies) {
addAllToSet(
/** @type {LazySet<string>} */
(resolveContext.contextDependencies),
snapshot.getContextIterable()
);
}
done(null, result);
}
);
} else {
doRealResolve(
itemCache,
resolver,
resolveContext,
request,
done
);
}
};
itemCache.get(processCacheResult);
if (withYield && callbacks === undefined) {
callbacks = [callback];
yields = [resolveContext.yield];
activeRequestsWithYield.set(
identifier,
/** @type {[any, any]} */ ([callbacks, yields])
if (withYield) {
const activeRequest = activeRequestsWithYield.get(identifier);
if (activeRequest) {
activeRequest[0].push(callback);
activeRequest[1].push(
/** @type {NonNullable<ResolveContext["yield"]>} */
(resolveContext.yield)
);
} else if (callbacks === undefined) {
callbacks = [callback];
activeRequests.set(identifier, callbacks);
return;
}
} else {
const activeRequest = activeRequests.get(identifier);
if (activeRequest) {
activeRequest.push(callback);
return;
}
}
);
}
);
const itemCache = cache.getItemCache(identifier, null);
/** @type {Callback[] | false | undefined} */
let callbacks;
/** @type {NonNullable<ResolveContext["yield"]>[] | undefined} */
let yields;
/**
* @type {function((Error | null)=, ResolveRequest | ResolveRequest[]=): void}
*/
const done = withYield
? (err, result) => {
if (callbacks === undefined) {
if (err) {
callback(err);
} else {
if (result)
for (const r of /** @type {ResolveRequest[]} */ (
result
)) {
/** @type {NonNullable<ResolveContext["yield"]>} */
(resolveContext.yield)(r);
}
callback(null, null);
}
yields = undefined;
callbacks = false;
} else {
const definedCallbacks =
/** @type {Callback[]} */
(callbacks);
if (err) {
for (const cb of definedCallbacks) cb(err);
} else {
for (let i = 0; i < definedCallbacks.length; i++) {
const cb = definedCallbacks[i];
const yield_ =
/** @type {NonNullable<ResolveContext["yield"]>[]} */
(yields)[i];
if (result)
for (const r of /** @type {ResolveRequest[]} */ (
result
))
yield_(r);
cb(null, null);
}
}
activeRequestsWithYield.delete(identifier);
yields = undefined;
callbacks = false;
}
}
: (err, result) => {
if (callbacks === undefined) {
callback(err, /** @type {ResolveRequest} */ (result));
callbacks = false;
} else {
for (const callback of /** @type {Callback[]} */ (
callbacks
)) {
callback(err, /** @type {ResolveRequest} */ (result));
}
activeRequests.delete(identifier);
callbacks = false;
}
};
/**
* @param {(Error | null)=} err error if any
* @param {(CacheEntry | null)=} cacheEntry cache entry
* @returns {void}
*/
const processCacheResult = (err, cacheEntry) => {
if (err) return done(err);
if (cacheEntry) {
const { snapshot, result } = cacheEntry;
fileSystemInfo.checkSnapshotValid(snapshot, (err, valid) => {
if (err || !valid) {
cacheInvalidResolves++;
return doRealResolve(
itemCache,
resolver,
resolveContext,
request,
done
);
}
cachedResolves++;
if (resolveContext.missingDependencies) {
addAllToSet(
/** @type {Set<string>} */
(resolveContext.missingDependencies),
snapshot.getMissingIterable()
);
}
if (resolveContext.fileDependencies) {
addAllToSet(
/** @type {Set<string>} */
(resolveContext.fileDependencies),
snapshot.getFileIterable()
);
}
if (resolveContext.contextDependencies) {
addAllToSet(
/** @type {Set<string>} */
(resolveContext.contextDependencies),
snapshot.getContextIterable()
);
}
done(null, result);
});
} else {
doRealResolve(
itemCache,
resolver,
resolveContext,
request,
done
);
}
};
itemCache.get(processCacheResult);
if (withYield && callbacks === undefined) {
callbacks = [callback];
yields = [
/** @type {NonNullable<ResolveContext["yield"]>} */
(resolveContext.yield)
];
activeRequestsWithYield.set(
identifier,
/** @type {[any, any]} */ ([callbacks, yields])
);
} else if (callbacks === undefined) {
callbacks = [callback];
activeRequests.set(identifier, callbacks);
}
}
);
});
return hook;
}
});

View File

@@ -34,27 +34,23 @@ const mergeEtags = (a, b) => {
if (typeof a === "string") {
if (typeof b === "string") {
return `${a}|${b}`;
} else {
const temp = b;
b = a;
a = temp;
}
} else {
if (typeof b !== "string") {
// both a and b are objects
let map = dualObjectMap.get(a);
if (map === undefined) {
dualObjectMap.set(a, (map = new WeakMap()));
}
const mergedEtag = map.get(b);
if (mergedEtag === undefined) {
const newMergedEtag = new MergedEtag(a, b);
map.set(b, newMergedEtag);
return newMergedEtag;
} else {
return mergedEtag;
}
const temp = b;
b = a;
a = temp;
} else if (typeof b !== "string") {
// both a and b are objects
let map = dualObjectMap.get(a);
if (map === undefined) {
dualObjectMap.set(a, (map = new WeakMap()));
}
const mergedEtag = map.get(b);
if (mergedEtag === undefined) {
const newMergedEtag = new MergedEtag(a, b);
map.set(b, newMergedEtag);
return newMergedEtag;
}
return mergedEtag;
}
// a is object, b is string
let map = objectStringMap.get(a);
@@ -66,9 +62,8 @@ const mergeEtags = (a, b) => {
const newMergedEtag = new MergedEtag(a, b);
map.set(b, newMergedEtag);
return newMergedEtag;
} else {
return mergedEtag;
}
return mergedEtag;
};
module.exports = mergeEtags;