mirror of https://github.com/webpack/webpack.git
add queues to Compilation
remove Semaphore and use AsyncQueue instead deprecate Module.needRebuild, add Module.needBuild remove Module.unbuild add Module.invalidateBuild
This commit is contained in:
parent
d48a331642
commit
5b4cbb5ee0
|
|
@ -36,8 +36,8 @@ const ModuleTemplate = require("./ModuleTemplate");
|
|||
const RuntimeTemplate = require("./RuntimeTemplate");
|
||||
const Stats = require("./Stats");
|
||||
const compareLocations = require("./compareLocations");
|
||||
const AsyncQueue = require("./util/AsyncQueue");
|
||||
const Queue = require("./util/Queue");
|
||||
const Semaphore = require("./util/Semaphore");
|
||||
const SortableSet = require("./util/SortableSet");
|
||||
const {
|
||||
concatComparators,
|
||||
|
|
@ -63,8 +63,7 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
|
|||
|
||||
// TODO use @callback
|
||||
/** @typedef {{[assetName: string]: Source}} CompilationAssets */
|
||||
/** @typedef {(err?: Error|null, result?: Module) => void } ModuleCallback */
|
||||
/** @typedef {(err?: Error|null, result?: Module) => void } ModuleChainCallback */
|
||||
/** @typedef {(err?: WebpackError|null, result?: Module) => void } ModuleCallback */
|
||||
/** @typedef {(err?: Error|null) => void} Callback */
|
||||
/** @typedef {(d: Dependency) => any} DepBlockVarDependenciesCallback */
|
||||
/** @typedef {new (...args: any[]) => Dependency} DepConstructor */
|
||||
|
|
@ -89,12 +88,6 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
|
|||
* @property {(data: ModuleFactoryCreateData, callback: ModuleCallback) => any} create
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SortedDependency
|
||||
* @property {ModuleFactory} factory
|
||||
* @property {Dependency[]} dependencies
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AvailableModulesChunkGroupMapping
|
||||
* @property {ChunkGroup} chunkGroup
|
||||
|
|
@ -203,7 +196,7 @@ class Compilation {
|
|||
buildModule: new SyncHook(["module"]),
|
||||
/** @type {SyncHook<Module>} */
|
||||
rebuildModule: new SyncHook(["module"]),
|
||||
/** @type {SyncHook<Module, Error>} */
|
||||
/** @type {SyncHook<Module, WebpackError>} */
|
||||
failedModule: new SyncHook(["module", "error"]),
|
||||
/** @type {SyncHook<Module>} */
|
||||
succeedModule: new SyncHook(["module"]),
|
||||
|
|
@ -381,7 +374,26 @@ class Compilation {
|
|||
this.moduleGraph = new ModuleGraph();
|
||||
this.chunkGraph = undefined;
|
||||
|
||||
this.semaphore = new Semaphore(options.parallelism || 100);
|
||||
this.factorizeQueue = new AsyncQueue({
|
||||
name: "factorize",
|
||||
parallelism: options.parallelism || 100,
|
||||
processor: this._factorizeModule.bind(this)
|
||||
});
|
||||
this.buildQueue = new AsyncQueue({
|
||||
name: "build",
|
||||
parallelism: options.parallelism || 100,
|
||||
processor: this._buildModule.bind(this)
|
||||
});
|
||||
this.rebuildQueue = new AsyncQueue({
|
||||
name: "rebuild",
|
||||
parallelism: options.parallelism || 100,
|
||||
processor: this._rebuildModule.bind(this)
|
||||
});
|
||||
this.processDependenciesQueue = new AsyncQueue({
|
||||
name: "processDependencies",
|
||||
parallelism: options.parallelism || 100,
|
||||
processor: this._processModuleDependencies.bind(this)
|
||||
});
|
||||
|
||||
/** @type {Map<string, EntryDependency[]>} */
|
||||
this.entryDependencies = new Map();
|
||||
|
|
@ -433,8 +445,6 @@ class Compilation {
|
|||
/** @type {WeakSet<Module>} */
|
||||
this.builtModules = new WeakSet();
|
||||
/** @private @type {Map<Module, Callback[]>} */
|
||||
this._buildingModules = new Map();
|
||||
/** @private @type {Map<Module, Callback[]>} */
|
||||
this._rebuildingModules = new Map();
|
||||
}
|
||||
|
||||
|
|
@ -446,26 +456,19 @@ class Compilation {
|
|||
* @typedef {Object} AddModuleResult
|
||||
* @property {Module} module the added or existing module
|
||||
* @property {boolean} issuer was this the first request for this module
|
||||
* @property {boolean} build should the module be build
|
||||
* @property {boolean} dependencies should dependencies be walked
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Module} module module to be added that was created
|
||||
* @param {any=} cacheGroup cacheGroup it is apart of
|
||||
* @returns {AddModuleResult} returns meta about whether or not the module had built
|
||||
* had an issuer, or any dependnecies
|
||||
* @returns {Module} returns the module in the compilation,
|
||||
* it could be the passed one (if new), or an already existing in the compilation
|
||||
*/
|
||||
addModule(module, cacheGroup) {
|
||||
const identifier = module.identifier();
|
||||
const alreadyAddedModule = this._modules.get(identifier);
|
||||
if (alreadyAddedModule) {
|
||||
return {
|
||||
module: alreadyAddedModule,
|
||||
issuer: false,
|
||||
build: false,
|
||||
dependencies: false
|
||||
};
|
||||
return alreadyAddedModule;
|
||||
}
|
||||
const cacheName = (cacheGroup || "m") + identifier;
|
||||
if (this.cache && this.cache[cacheName]) {
|
||||
|
|
@ -473,32 +476,6 @@ class Compilation {
|
|||
|
||||
cacheModule.updateCacheModule(module);
|
||||
|
||||
let rebuild = true;
|
||||
if (this.fileTimestamps && this.contextTimestamps) {
|
||||
rebuild = cacheModule.needRebuild(
|
||||
this.fileTimestamps,
|
||||
this.contextTimestamps
|
||||
);
|
||||
}
|
||||
|
||||
if (!rebuild) {
|
||||
this._modules.set(identifier, cacheModule);
|
||||
this.modules.add(cacheModule);
|
||||
for (const err of cacheModule.errors) {
|
||||
this.errors.push(err);
|
||||
}
|
||||
for (const err of cacheModule.warnings) {
|
||||
this.warnings.push(err);
|
||||
}
|
||||
ModuleGraph.setModuleGraphForModule(cacheModule, this.moduleGraph);
|
||||
return {
|
||||
module: cacheModule,
|
||||
issuer: true,
|
||||
build: false,
|
||||
dependencies: true
|
||||
};
|
||||
}
|
||||
cacheModule.unbuild();
|
||||
module = cacheModule;
|
||||
}
|
||||
this._modules.set(identifier, module);
|
||||
|
|
@ -507,12 +484,7 @@ class Compilation {
|
|||
}
|
||||
this.modules.add(module);
|
||||
ModuleGraph.setModuleGraphForModule(module, this.moduleGraph);
|
||||
return {
|
||||
module: module,
|
||||
issuer: true,
|
||||
build: true,
|
||||
dependencies: true
|
||||
};
|
||||
return module;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -535,40 +507,48 @@ class Compilation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module module with its callback list
|
||||
* @param {Callback} callback the callback function
|
||||
* Schedules a build of the module object
|
||||
*
|
||||
* @param {Module} module module to be built
|
||||
* @param {ModuleCallback} callback the callback
|
||||
* @returns {void}
|
||||
*/
|
||||
waitForBuildingFinished(module, callback) {
|
||||
let callbackList = this._buildingModules.get(module);
|
||||
if (callbackList) {
|
||||
callbackList.push(() => callback());
|
||||
} else {
|
||||
process.nextTick(callback);
|
||||
}
|
||||
buildModule(module, callback) {
|
||||
this.buildQueue.add(module, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the module object
|
||||
*
|
||||
* @param {Module} module module to be built
|
||||
* @param {TODO} thisCallback the callback
|
||||
* @param {ModuleCallback} callback the callback
|
||||
* @returns {TODO} returns the callback function with results
|
||||
*/
|
||||
buildModule(module, thisCallback) {
|
||||
let callbackList = this._buildingModules.get(module);
|
||||
if (callbackList) {
|
||||
callbackList.push(thisCallback);
|
||||
return;
|
||||
_buildModule(module, callback) {
|
||||
const currentProfile = this.profile
|
||||
? this.moduleGraph.getProfile(module)
|
||||
: undefined;
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markBuildingStart();
|
||||
}
|
||||
this._buildingModules.set(module, (callbackList = [thisCallback]));
|
||||
|
||||
const callback = err => {
|
||||
this._buildingModules.delete(module);
|
||||
for (const cb of callbackList) {
|
||||
cb(err);
|
||||
let rebuild = true;
|
||||
if (this.fileTimestamps && this.contextTimestamps) {
|
||||
rebuild = module.needBuild(this.fileTimestamps, this.contextTimestamps);
|
||||
}
|
||||
|
||||
if (!rebuild) {
|
||||
for (const err of module.errors) {
|
||||
this.errors.push(err);
|
||||
}
|
||||
};
|
||||
for (const err of module.warnings) {
|
||||
this.warnings.push(err);
|
||||
}
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markBuildingEnd();
|
||||
}
|
||||
return callback();
|
||||
}
|
||||
|
||||
this.hooks.buildModule.call(module);
|
||||
this.builtModules.add(module);
|
||||
|
|
@ -577,11 +557,14 @@ class Compilation {
|
|||
this,
|
||||
this.resolverFactory.get("normal", module.resolveOptions),
|
||||
this.inputFileSystem,
|
||||
error => {
|
||||
err => {
|
||||
module.dependencies.sort((a, b) => compareLocations(a.loc, b.loc));
|
||||
if (error) {
|
||||
this.hooks.failedModule.call(module, error);
|
||||
return callback(error);
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markBuildingEnd();
|
||||
}
|
||||
if (err) {
|
||||
this.hooks.failedModule.call(module, err);
|
||||
return callback(err);
|
||||
}
|
||||
this.hooks.succeedModule.call(module);
|
||||
return callback();
|
||||
|
|
@ -595,6 +578,15 @@ class Compilation {
|
|||
* @returns {void}
|
||||
*/
|
||||
processModuleDependencies(module, callback) {
|
||||
this.processDependenciesQueue.add(module, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module to be processed for deps
|
||||
* @param {ModuleCallback} callback callback to be triggered
|
||||
* @returns {void}
|
||||
*/
|
||||
_processModuleDependencies(module, callback) {
|
||||
const dependencies = new Map();
|
||||
|
||||
let currentBlock = module;
|
||||
|
|
@ -648,91 +640,37 @@ class Compilation {
|
|||
}
|
||||
}
|
||||
|
||||
this.addModuleDependencies(module, sortedDependencies, this.bail, callback);
|
||||
}
|
||||
// This is nested so we need to allow one additional task
|
||||
this.processDependenciesQueue.increaseParallelism();
|
||||
|
||||
/**
|
||||
* @typedef {Object} HandleNewModuleOptions
|
||||
* @property {Module} newModule
|
||||
* @property {Module | null} originModule
|
||||
* @property {Dependency[]} dependencies
|
||||
* @property {ModuleProfile} currentProfile
|
||||
* @property {boolean=} bail
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {HandleNewModuleOptions} options options object
|
||||
* @param {ModuleCallback} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
handleNewModule(
|
||||
{ newModule, originModule, dependencies, currentProfile, bail },
|
||||
callback
|
||||
) {
|
||||
this.semaphore.acquire(() => {
|
||||
const moduleGraph = this.moduleGraph;
|
||||
|
||||
const addModuleResult = this.addModule(newModule);
|
||||
|
||||
const module = addModuleResult.module;
|
||||
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dependency = dependencies[i];
|
||||
moduleGraph.setResolvedModule(originModule, dependency, module);
|
||||
}
|
||||
|
||||
if (addModuleResult.issuer) {
|
||||
if (currentProfile !== undefined) {
|
||||
moduleGraph.setProfile(module, currentProfile);
|
||||
}
|
||||
|
||||
if (originModule !== undefined) {
|
||||
moduleGraph.setIssuer(module, originModule);
|
||||
}
|
||||
} else {
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.mergeInto(moduleGraph.getProfile(module));
|
||||
}
|
||||
}
|
||||
|
||||
const afterBuild = () => {
|
||||
if (addModuleResult.dependencies) {
|
||||
this.processModuleDependencies(module, err => {
|
||||
if (err) return callback(err);
|
||||
callback(null, module);
|
||||
});
|
||||
} else {
|
||||
return callback(null, module);
|
||||
}
|
||||
};
|
||||
|
||||
if (addModuleResult.build) {
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markBuildingStart();
|
||||
}
|
||||
this.buildModule(module, err => {
|
||||
if (err) {
|
||||
if (!err.module) {
|
||||
err.module = module;
|
||||
asyncLib.forEach(
|
||||
sortedDependencies,
|
||||
(item, callback) => {
|
||||
this.handleModuleCreation(
|
||||
{
|
||||
factory: item.factory,
|
||||
dependencies: item.dependencies,
|
||||
originModule: module
|
||||
},
|
||||
err => {
|
||||
// In V8, the Error objects keep a reference to the functions on the stack. These warnings &
|
||||
// errors are created inside closures that keep a reference to the Compilation, so errors are
|
||||
// leaking the Compilation object.
|
||||
if (err && this.bail) {
|
||||
// eslint-disable-next-line no-self-assign
|
||||
err.stack = err.stack;
|
||||
return callback(err);
|
||||
}
|
||||
this.errors.push(err);
|
||||
this.semaphore.release();
|
||||
if (bail) return callback(err);
|
||||
return callback();
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
err => {
|
||||
this.processDependenciesQueue.decreaseParallelism();
|
||||
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markBuildingEnd();
|
||||
}
|
||||
|
||||
this.semaphore.release();
|
||||
afterBuild();
|
||||
});
|
||||
} else {
|
||||
this.semaphore.release();
|
||||
this.waitForBuildingFinished(module, afterBuild);
|
||||
return callback(err);
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -741,7 +679,6 @@ class Compilation {
|
|||
* @property {Dependency[]} dependencies
|
||||
* @property {Module | null} originModule
|
||||
* @property {string=} context
|
||||
* @property {boolean=} bail
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -750,99 +687,138 @@ class Compilation {
|
|||
* @returns {void}
|
||||
*/
|
||||
handleModuleCreation(
|
||||
{ factory, dependencies, originModule, context, bail },
|
||||
{ factory, dependencies, originModule, context },
|
||||
callback
|
||||
) {
|
||||
const semaphore = this.semaphore;
|
||||
semaphore.acquire(() => {
|
||||
const currentProfile = this.profile ? new ModuleProfile() : undefined;
|
||||
factory.create(
|
||||
{
|
||||
contextInfo: {
|
||||
issuer: originModule ? originModule.nameForCondition() : "",
|
||||
compiler: this.compiler.name
|
||||
},
|
||||
resolveOptions: originModule
|
||||
? originModule.resolveOptions
|
||||
: undefined,
|
||||
context: context
|
||||
? context
|
||||
: originModule
|
||||
? originModule.context
|
||||
: this.compiler.context,
|
||||
dependencies: dependencies
|
||||
},
|
||||
(err, newModule) => {
|
||||
semaphore.release();
|
||||
if (err) {
|
||||
const notFoundError = new ModuleNotFoundError(
|
||||
originModule,
|
||||
err,
|
||||
dependencies.map(d => d.loc).filter(Boolean)[0]
|
||||
);
|
||||
if (dependencies.every(d => d.optional)) {
|
||||
this.warnings.push(notFoundError);
|
||||
} else {
|
||||
this.errors.push(notFoundError);
|
||||
}
|
||||
if (bail) return callback(notFoundError);
|
||||
return callback();
|
||||
}
|
||||
if (!newModule) {
|
||||
return process.nextTick(callback);
|
||||
}
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markFactoryEnd();
|
||||
}
|
||||
const moduleGraph = this.moduleGraph;
|
||||
|
||||
this.handleNewModule(
|
||||
{
|
||||
newModule,
|
||||
originModule,
|
||||
dependencies,
|
||||
currentProfile,
|
||||
bail
|
||||
},
|
||||
callback
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module module to add deps to
|
||||
* @param {SortedDependency[]} dependencies set of sorted dependencies to iterate through
|
||||
* @param {(boolean|null)=} bail whether to bail or not
|
||||
* @param {function} callback callback for when dependencies are finished being added
|
||||
* @returns {void}
|
||||
*/
|
||||
addModuleDependencies(module, dependencies, bail, callback) {
|
||||
asyncLib.forEach(
|
||||
dependencies,
|
||||
(item, callback) => {
|
||||
this.handleModuleCreation(
|
||||
{
|
||||
factory: item.factory,
|
||||
dependencies: item.dependencies,
|
||||
originModule: module,
|
||||
bail
|
||||
},
|
||||
callback
|
||||
);
|
||||
},
|
||||
err => {
|
||||
// In V8, the Error objects keep a reference to the functions on the stack. These warnings &
|
||||
// errors are created inside closures that keep a reference to the Compilation, so errors are
|
||||
// leaking the Compilation object.
|
||||
const currentProfile = this.profile ? new ModuleProfile() : undefined;
|
||||
|
||||
this.factorizeModule(
|
||||
{ currentProfile, factory, dependencies, originModule, context },
|
||||
(err, newModule) => {
|
||||
if (err) {
|
||||
// eslint-disable-next-line no-self-assign
|
||||
err.stack = err.stack;
|
||||
if (dependencies.every(d => d.optional)) {
|
||||
this.warnings.push(err);
|
||||
} else {
|
||||
this.errors.push(err);
|
||||
}
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
return process.nextTick(callback);
|
||||
if (!newModule) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
const module = this.addModule(newModule);
|
||||
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dependency = dependencies[i];
|
||||
moduleGraph.setResolvedModule(originModule, dependency, module);
|
||||
}
|
||||
|
||||
if (module === newModule) {
|
||||
if (currentProfile !== undefined) {
|
||||
moduleGraph.setProfile(module, currentProfile);
|
||||
}
|
||||
|
||||
if (originModule !== undefined) {
|
||||
moduleGraph.setIssuer(module, originModule);
|
||||
}
|
||||
} else {
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.mergeInto(moduleGraph.getProfile(module));
|
||||
}
|
||||
}
|
||||
|
||||
this.buildModule(module, error => {
|
||||
if (error) {
|
||||
const err = /** @type {WebpackError} */ (error);
|
||||
if (!err.module) {
|
||||
err.module = module;
|
||||
}
|
||||
this.errors.push(err);
|
||||
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// This avoids deadlocks for circular dependencies
|
||||
if (this.processDependenciesQueue.isProcessing(module)) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
this.processModuleDependencies(module, err => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, module);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} FactorizeModuleOptions
|
||||
* @property {ModuleProfile} currentProfile
|
||||
* @property {ModuleFactory} factory
|
||||
* @property {Dependency[]} dependencies
|
||||
* @property {Module | null} originModule
|
||||
* @property {string=} context
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {FactorizeModuleOptions} options options object
|
||||
* @param {ModuleCallback} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
factorizeModule(options, callback) {
|
||||
this.factorizeQueue.add(options, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FactorizeModuleOptions} options options object
|
||||
* @param {ModuleCallback} callback callback
|
||||
* @returns {void}
|
||||
*/
|
||||
_factorizeModule(
|
||||
{ currentProfile, factory, dependencies, originModule, context },
|
||||
callback
|
||||
) {
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markFactoryStart();
|
||||
}
|
||||
factory.create(
|
||||
{
|
||||
contextInfo: {
|
||||
issuer: originModule ? originModule.nameForCondition() : "",
|
||||
compiler: this.compiler.name
|
||||
},
|
||||
resolveOptions: originModule ? originModule.resolveOptions : undefined,
|
||||
context: context
|
||||
? context
|
||||
: originModule
|
||||
? originModule.context
|
||||
: this.compiler.context,
|
||||
dependencies: dependencies
|
||||
},
|
||||
(err, newModule) => {
|
||||
if (err) {
|
||||
const notFoundError = new ModuleNotFoundError(
|
||||
originModule,
|
||||
err,
|
||||
dependencies.map(d => d.loc).filter(Boolean)[0]
|
||||
);
|
||||
return callback(notFoundError);
|
||||
}
|
||||
if (!newModule) {
|
||||
return callback();
|
||||
}
|
||||
if (currentProfile !== undefined) {
|
||||
currentProfile.markFactoryEnd();
|
||||
}
|
||||
|
||||
callback(null, newModule);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -851,7 +827,7 @@ class Compilation {
|
|||
*
|
||||
* @param {string} context context string path
|
||||
* @param {Dependency} dependency dependency used to create Module chain
|
||||
* @param {ModuleChainCallback} callback callback for when module chain is complete
|
||||
* @param {ModuleCallback} callback callback for when module chain is complete
|
||||
* @returns {void} will throw if dependency instance is not a valid Dependency
|
||||
*/
|
||||
addModuleChain(context, dependency, callback) {
|
||||
|
|
@ -877,10 +853,18 @@ class Compilation {
|
|||
factory: moduleFactory,
|
||||
dependencies: [dependency],
|
||||
originModule: null,
|
||||
context,
|
||||
bail: this.bail
|
||||
context
|
||||
},
|
||||
callback
|
||||
err => {
|
||||
if (this.bail) {
|
||||
this.buildQueue.stop();
|
||||
this.rebuildQueue.stop();
|
||||
this.processDependenciesQueue.stop();
|
||||
this.factorizeQueue.stop();
|
||||
return callback(err);
|
||||
}
|
||||
return callback();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -905,28 +889,24 @@ class Compilation {
|
|||
|
||||
/**
|
||||
* @param {Module} module module to be rebuilt
|
||||
* @param {Callback} thisCallback callback when module finishes rebuilding
|
||||
* @param {ModuleCallback} callback callback when module finishes rebuilding
|
||||
* @returns {void}
|
||||
*/
|
||||
rebuildModule(module, thisCallback) {
|
||||
let callbackList = this._rebuildingModules.get(module);
|
||||
if (callbackList) {
|
||||
callbackList.push(thisCallback);
|
||||
return;
|
||||
}
|
||||
this._rebuildingModules.set(module, (callbackList = [thisCallback]));
|
||||
|
||||
const callback = err => {
|
||||
this._rebuildingModules.delete(module);
|
||||
for (const cb of callbackList) {
|
||||
cb(err);
|
||||
}
|
||||
};
|
||||
rebuildModule(module, callback) {
|
||||
this.rebuildQueue.add(module, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module module to be rebuilt
|
||||
* @param {ModuleCallback} callback callback when module finishes rebuilding
|
||||
* @returns {void}
|
||||
*/
|
||||
_rebuildModule(module, callback) {
|
||||
this.hooks.rebuildModule.call(module);
|
||||
const oldDependencies = module.dependencies.slice();
|
||||
const oldBlocks = module.blocks.slice();
|
||||
module.unbuild();
|
||||
module.invalidateBuild();
|
||||
this.buildQueue.invalidate(module);
|
||||
this.buildModule(module, err => {
|
||||
if (err) {
|
||||
this.hooks.finishRebuildingModule.call(module);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const { OriginalSource, RawSource } = require("webpack-sources");
|
|||
const AsyncDependenciesBlock = require("./AsyncDependenciesBlock");
|
||||
const Module = require("./Module");
|
||||
const Template = require("./Template");
|
||||
const WebpackError = require("./WebpackError");
|
||||
const { compareModulesById } = require("./util/comparators");
|
||||
const contextify = require("./util/identifier").contextify;
|
||||
|
||||
|
|
@ -79,6 +80,7 @@ class ContextModule extends Module {
|
|||
}
|
||||
|
||||
this._identifier = this._createIdentifier();
|
||||
this._forceBuild = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -215,12 +217,20 @@ class ContextModule extends Module {
|
|||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
invalidateBuild() {
|
||||
this._forceBuild = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TODO} fileTimestamps timestamps of files
|
||||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
needBuild(fileTimestamps, contextTimestamps) {
|
||||
if (this._forceBuild) return true;
|
||||
const ts = contextTimestamps.get(this.context);
|
||||
if (!ts) {
|
||||
return true;
|
||||
|
|
@ -234,15 +244,18 @@ class ContextModule extends Module {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
this._forceBuild = false;
|
||||
this.buildMeta = {};
|
||||
this.buildInfo = {
|
||||
builtTime: Date.now(),
|
||||
contextDependencies: this._contextDependencies
|
||||
};
|
||||
this.dependencies.length = 0;
|
||||
this.blocks.length = 0;
|
||||
this.resolveDependencies(fs, this.options, (err, dependencies) => {
|
||||
if (err) return callback(err);
|
||||
|
||||
|
|
@ -318,7 +331,7 @@ class ContextModule extends Module {
|
|||
}
|
||||
} else {
|
||||
callback(
|
||||
new Error(`Unsupported mode "${this.options.mode}" in context`)
|
||||
new WebpackError(`Unsupported mode "${this.options.mode}" in context`)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDepende
|
|||
/** @typedef {import("./Module").SourceContext} SourceContext */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
/** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
|
|
@ -70,8 +71,8 @@ class DelegatedModule extends Module {
|
|||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
return false;
|
||||
needBuild(fileTimestamps, contextTimestamps) {
|
||||
return !this.buildMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -79,12 +80,13 @@ class DelegatedModule extends Module {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
this.buildMeta = Object.assign({}, this.delegateData.buildMeta);
|
||||
this.buildInfo = {};
|
||||
this.dependencies.length = 0;
|
||||
this.delegatedSourceDependency = new DelegatedSourceDependency(
|
||||
this.sourceRequest
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const Module = require("./Module");
|
|||
/** @typedef {import("./Module").SourceContext} SourceContext */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
class DllModule extends Module {
|
||||
|
|
@ -46,7 +47,7 @@ class DllModule extends Module {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
|
|
@ -68,8 +69,8 @@ class DllModule extends Module {
|
|||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
return false;
|
||||
needBuild(fileTimestamps, contextTimestamps) {
|
||||
return !this.buildMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ const Template = require("./Template");
|
|||
/** @typedef {import("./Module").SourceContext} SourceContext */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
/**
|
||||
|
|
@ -151,8 +152,8 @@ class ExternalModule extends Module {
|
|||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
return false;
|
||||
needBuild(fileTimestamps, contextTimestamps) {
|
||||
return !this.buildMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -160,7 +161,7 @@ class ExternalModule extends Module {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
|
|
|
|||
|
|
@ -450,6 +450,18 @@ class Module extends DependenciesBlock {
|
|||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needBuild(fileTimestamps, contextTimestamps) {
|
||||
return (
|
||||
!this.buildMeta || this.needRebuild(fileTimestamps, contextTimestamps)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use needBuild instead
|
||||
* @param {TODO} fileTimestamps timestamps of files
|
||||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -475,11 +487,8 @@ class Module extends DependenciesBlock {
|
|||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
unbuild() {
|
||||
this.dependencies.length = 0;
|
||||
this.blocks.length = 0;
|
||||
this.buildMeta = undefined;
|
||||
this.buildInfo = undefined;
|
||||
invalidateBuild() {
|
||||
// should be overriden to support this feature
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -505,7 +514,7 @@ class Module extends DependenciesBlock {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
|
|
|
|||
|
|
@ -15,9 +15,13 @@ class ModuleProfile {
|
|||
this.additionalIntegration = 0;
|
||||
}
|
||||
|
||||
markFactoryStart() {
|
||||
this.factoryStartTime = Date.now();
|
||||
}
|
||||
|
||||
markFactoryEnd() {
|
||||
this.factoryTime = Date.now();
|
||||
this.factory = this.factoryTime - this.startTime;
|
||||
this.factoryEndTime = Date.now();
|
||||
this.factory = this.factoryEndTime - this.factoryStartTime;
|
||||
}
|
||||
|
||||
markIntegrationStart() {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const contextify = require("./util/identifier").contextify;
|
|||
/** @typedef {import("./Module").SourceContext} SourceContext */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
const asString = buf => {
|
||||
|
|
@ -106,6 +107,7 @@ class NormalModule extends Module {
|
|||
|
||||
// Cache
|
||||
this._lastSuccessfulBuildMeta = {};
|
||||
this._forceBuild = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -417,17 +419,20 @@ class NormalModule extends Module {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
this.buildTimestamp = Date.now();
|
||||
this._forceBuild = false;
|
||||
this._source = null;
|
||||
this._ast = null;
|
||||
this._buildHash = "";
|
||||
this.error = null;
|
||||
this.errors.length = 0;
|
||||
this.warnings.length = 0;
|
||||
this.dependencies.length = 0;
|
||||
this.blocks.length = 0;
|
||||
this.buildMeta = {};
|
||||
this.buildInfo = {
|
||||
cacheable: false,
|
||||
|
|
@ -549,12 +554,22 @@ class NormalModule extends Module {
|
|||
return this._source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
invalidateBuild() {
|
||||
this._forceBuild = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TODO} fileTimestamps timestamps of files
|
||||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
needBuild(fileTimestamps, contextTimestamps) {
|
||||
// build if enforced
|
||||
if (this._forceBuild) return true;
|
||||
|
||||
// always try to rebuild in case of an error
|
||||
if (this.error) return true;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const Module = require("./Module");
|
|||
/** @typedef {import("./Module").SourceContext} SourceContext */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
module.exports = class RawModule extends Module {
|
||||
|
|
@ -52,8 +53,8 @@ module.exports = class RawModule extends Module {
|
|||
* @param {TODO} contextTimestamps timestamps of directories
|
||||
* @returns {boolean} true, if the module needs a rebuild
|
||||
*/
|
||||
needRebuild(fileTimestamps, contextTimestamps) {
|
||||
return false;
|
||||
needBuild(fileTimestamps, contextTimestamps) {
|
||||
return !this.buildMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -61,7 +62,7 @@ module.exports = class RawModule extends Module {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const NormalModule = require("../NormalModule");
|
||||
const LoaderDependency = require("./LoaderDependency");
|
||||
|
||||
/** @typedef {import("../Module")} Module */
|
||||
|
|
@ -57,61 +56,50 @@ class LoaderPlugin {
|
|||
)
|
||||
);
|
||||
}
|
||||
compilation.semaphore.release();
|
||||
compilation.addModuleDependencies(
|
||||
module,
|
||||
[
|
||||
{
|
||||
factory,
|
||||
dependencies: [dep]
|
||||
}
|
||||
],
|
||||
true,
|
||||
compilation.buildQueue.increaseParallelism();
|
||||
compilation.handleModuleCreation(
|
||||
{
|
||||
factory,
|
||||
dependencies: [dep],
|
||||
originModule: loaderContext._module,
|
||||
context: loaderContext.context
|
||||
},
|
||||
err => {
|
||||
compilation.semaphore.acquire(() => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
compilation.buildQueue.decreaseParallelism();
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
const referencedModule = moduleGraph.getModule(dep);
|
||||
if (!referencedModule) {
|
||||
return callback(new Error("Cannot load the module"));
|
||||
}
|
||||
const moduleSource = referencedModule.originalSource();
|
||||
if (!moduleSource) {
|
||||
throw new Error(
|
||||
"The module created for a LoaderDependency must have an original source"
|
||||
);
|
||||
}
|
||||
let source, map;
|
||||
if (moduleSource.sourceAndMap) {
|
||||
const sourceAndMap = moduleSource.sourceAndMap();
|
||||
map = sourceAndMap.map;
|
||||
source = sourceAndMap.source;
|
||||
} else {
|
||||
map = moduleSource.map();
|
||||
source = moduleSource.source();
|
||||
}
|
||||
if (referencedModule.buildInfo.fileDependencies) {
|
||||
for (const d of referencedModule.buildInfo.fileDependencies) {
|
||||
loaderContext.addDependency(d);
|
||||
}
|
||||
const referencedModule = moduleGraph.getModule(dep);
|
||||
if (!referencedModule) {
|
||||
return callback(new Error("Cannot load the module"));
|
||||
}
|
||||
if (referencedModule.buildInfo.contextDependencies) {
|
||||
for (const d of referencedModule.buildInfo
|
||||
.contextDependencies) {
|
||||
loaderContext.addContextDependency(d);
|
||||
}
|
||||
// TODO consider removing this in webpack 5
|
||||
if (
|
||||
referencedModule instanceof NormalModule &&
|
||||
referencedModule.error
|
||||
) {
|
||||
return callback(referencedModule.error);
|
||||
}
|
||||
const moduleSource = referencedModule.originalSource();
|
||||
if (!moduleSource) {
|
||||
throw new Error(
|
||||
"The module created for a LoaderDependency must have an original source"
|
||||
);
|
||||
}
|
||||
let source, map;
|
||||
if (moduleSource.sourceAndMap) {
|
||||
const sourceAndMap = moduleSource.sourceAndMap();
|
||||
map = sourceAndMap.map;
|
||||
source = sourceAndMap.source;
|
||||
} else {
|
||||
map = moduleSource.map();
|
||||
source = moduleSource.source();
|
||||
}
|
||||
if (referencedModule.buildInfo.fileDependencies) {
|
||||
for (const d of referencedModule.buildInfo
|
||||
.fileDependencies) {
|
||||
loaderContext.addDependency(d);
|
||||
}
|
||||
}
|
||||
if (referencedModule.buildInfo.contextDependencies) {
|
||||
for (const d of referencedModule.buildInfo
|
||||
.contextDependencies) {
|
||||
loaderContext.addContextDependency(d);
|
||||
}
|
||||
}
|
||||
return callback(null, source, map, referencedModule);
|
||||
});
|
||||
}
|
||||
return callback(null, source, map, referencedModule);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ const createHash = require("../util/createHash");
|
|||
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
||||
/** @typedef {import("../RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("../WebpackError")} WebpackError */
|
||||
/** @typedef {import("../util/createHash").Hash} Hash */
|
||||
|
||||
/**
|
||||
|
|
@ -441,7 +442,7 @@ class ConcatenatedModule extends Module {
|
|||
* @param {Compilation} compilation the compilation
|
||||
* @param {TODO} resolver TODO
|
||||
* @param {TODO} fs the file system
|
||||
* @param {function(Error=): void} callback callback function
|
||||
* @param {function(WebpackError=): void} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
build(options, compilation, resolver, fs, callback) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { SyncHook, AsyncSeriesHook } = require("tapable");
|
||||
|
||||
/** @template R @typedef {(err?: Error|null, result?: R) => void} Callback<T> */
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template R
|
||||
*/
|
||||
class AsyncQueue {
|
||||
/**
|
||||
* @param {Object} options options object
|
||||
* @param {string=} options.name name of the queue
|
||||
* @param {number} options.parallelism how many items should be processed at once
|
||||
* @param {function(T, Callback<R>): void} options.processor async function to process items
|
||||
*/
|
||||
constructor({ name, parallelism, processor }) {
|
||||
this._name = name;
|
||||
this._parallelism = parallelism;
|
||||
this._processor = processor;
|
||||
/** @type {Map<T, Callback<R>[]>} */
|
||||
this._callbacks = new Map();
|
||||
/** @type {Set<T>} */
|
||||
this._queued = new Set();
|
||||
/** @type {Set<T>} */
|
||||
this._processing = new Set();
|
||||
/** @type {Map<T, [Error, R]>} */
|
||||
this._results = new Map();
|
||||
this._activeTasks = 0;
|
||||
this._willEnsureProcessing = false;
|
||||
this._stopped = false;
|
||||
|
||||
this.hooks = {
|
||||
beforeAdd: new AsyncSeriesHook(["item"]),
|
||||
added: new SyncHook(["item"]),
|
||||
beforeStart: new AsyncSeriesHook(["item"]),
|
||||
started: new SyncHook(["item"]),
|
||||
result: new SyncHook(["item", "error", "result"])
|
||||
};
|
||||
|
||||
this._ensureProcessing = this._ensureProcessing.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item a item
|
||||
* @param {Callback<R>} callback callback function
|
||||
* @returns {void}
|
||||
*/
|
||||
add(item, callback) {
|
||||
if (this._stopped) return callback(new Error("Queue was stopped"));
|
||||
this.hooks.beforeAdd.callAsync(item, err => {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
const result = this._results.get(item);
|
||||
if (result !== undefined) {
|
||||
process.nextTick(() => callback(result[0], result[1]));
|
||||
return;
|
||||
}
|
||||
let callbacks = this._callbacks.get(item);
|
||||
if (callbacks !== undefined) {
|
||||
callbacks.push(callback);
|
||||
return;
|
||||
}
|
||||
callbacks = [callback];
|
||||
this._callbacks.set(item, callbacks);
|
||||
if (this._stopped) {
|
||||
this.hooks.added.call(item);
|
||||
this._activeTasks++;
|
||||
this._handleResult(item, new Error("Queue was stopped"));
|
||||
} else {
|
||||
this._queued.add(item);
|
||||
if (this._willEnsureProcessing === false) {
|
||||
this._willEnsureProcessing = true;
|
||||
process.nextTick(this._ensureProcessing);
|
||||
}
|
||||
this.hooks.added.call(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item a item
|
||||
* @returns {void}
|
||||
*/
|
||||
invalidate(item) {
|
||||
this._results.delete(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
stop() {
|
||||
this._stopped = true;
|
||||
for (const item of this._queued) {
|
||||
this._activeTasks++;
|
||||
this._queued.delete(item);
|
||||
this._handleResult(item, new Error("Queue was stopped"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
increaseParallelism() {
|
||||
this._parallelism++;
|
||||
if (this._willEnsureProcessing === false && this._queued.size > 0) {
|
||||
this._willEnsureProcessing = true;
|
||||
process.nextTick(this._ensureProcessing);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
decreaseParallelism() {
|
||||
this._parallelism--;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item an item
|
||||
* @returns {boolean} true, if the item is currently being processed
|
||||
*/
|
||||
isProcessing(item) {
|
||||
return this._processing.has(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item an item
|
||||
* @returns {boolean} true, if the item is currently queued
|
||||
*/
|
||||
isQueued(item) {
|
||||
return this._queued.has(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item an item
|
||||
* @returns {boolean} true, if the item is currently queued
|
||||
*/
|
||||
isDone(item) {
|
||||
return this._results.has(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
_ensureProcessing() {
|
||||
if (this._activeTasks >= this._parallelism) {
|
||||
this._willEnsureProcessing = false;
|
||||
return;
|
||||
}
|
||||
for (const item of this._queued) {
|
||||
this._activeTasks++;
|
||||
this._queued.delete(item);
|
||||
this._processing.add(item);
|
||||
this._startProcessing(item);
|
||||
if (this._activeTasks >= this._parallelism) {
|
||||
this._willEnsureProcessing = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._willEnsureProcessing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item an item
|
||||
* @returns {void}
|
||||
*/
|
||||
_startProcessing(item) {
|
||||
this.hooks.beforeStart.callAsync(item, err => {
|
||||
if (err) {
|
||||
this._handleResult(item, err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this._processor(item, (e, r) => {
|
||||
process.nextTick(() => {
|
||||
this._handleResult(item, e, r);
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this._handleResult(item, err, null);
|
||||
}
|
||||
this.hooks.started.call(item);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} item an item
|
||||
* @param {Error=} err error, if any
|
||||
* @param {R=} result result, if any
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleResult(item, err, result) {
|
||||
this.hooks.result.callAsync(item, err, result, hookError => {
|
||||
const error = hookError || err;
|
||||
|
||||
const callbacks = this._callbacks.get(item);
|
||||
this._processing.delete(item);
|
||||
this._results.set(item, [error, result]);
|
||||
this._callbacks.delete(item);
|
||||
this._activeTasks--;
|
||||
|
||||
if (this._willEnsureProcessing === false && this._queued.size > 0) {
|
||||
this._willEnsureProcessing = true;
|
||||
process.nextTick(this._ensureProcessing);
|
||||
}
|
||||
|
||||
for (const callback of callbacks) {
|
||||
callback(error, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AsyncQueue;
|
||||
|
|
@ -190,7 +190,7 @@ describe("NormalModule", () => {
|
|||
expect(normalModule.hasDependencies()).toBe(false);
|
||||
});
|
||||
});
|
||||
describe("#needRebuild", () => {
|
||||
describe("#needBuild", () => {
|
||||
let fileTimestamps;
|
||||
let contextTimestamps;
|
||||
let fileDependencies;
|
||||
|
|
@ -211,13 +211,14 @@ describe("NormalModule", () => {
|
|||
fileTimestamps = new Map([[fileA, 1], [fileB, 1]]);
|
||||
contextTimestamps = new Map([[fileA, 1], [fileB, 1]]);
|
||||
normalModule.buildTimestamp = 2;
|
||||
normalModule._forceBuild = false;
|
||||
setDeps(fileDependencies, contextDependencies);
|
||||
});
|
||||
describe("given all timestamps are older than the buildTimestamp", () => {
|
||||
it("returns false", () => {
|
||||
expect(
|
||||
normalModule.needRebuild(fileTimestamps, contextTimestamps)
|
||||
).toBe(false);
|
||||
expect(normalModule.needBuild(fileTimestamps, contextTimestamps)).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("given a file timestamp is newer than the buildTimestamp", () => {
|
||||
|
|
@ -225,9 +226,9 @@ describe("NormalModule", () => {
|
|||
fileTimestamps.set(fileA, 3);
|
||||
});
|
||||
it("returns true", () => {
|
||||
expect(
|
||||
normalModule.needRebuild(fileTimestamps, contextTimestamps)
|
||||
).toBe(true);
|
||||
expect(normalModule.needBuild(fileTimestamps, contextTimestamps)).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("given a no file timestamp exists", () => {
|
||||
|
|
@ -235,9 +236,9 @@ describe("NormalModule", () => {
|
|||
fileTimestamps = new Map();
|
||||
});
|
||||
it("returns true", () => {
|
||||
expect(
|
||||
normalModule.needRebuild(fileTimestamps, contextTimestamps)
|
||||
).toBe(true);
|
||||
expect(normalModule.needBuild(fileTimestamps, contextTimestamps)).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("given a context timestamp is newer than the buildTimestamp", () => {
|
||||
|
|
@ -245,9 +246,9 @@ describe("NormalModule", () => {
|
|||
contextTimestamps.set(fileA, 3);
|
||||
});
|
||||
it("returns true", () => {
|
||||
expect(
|
||||
normalModule.needRebuild(fileTimestamps, contextTimestamps)
|
||||
).toBe(true);
|
||||
expect(normalModule.needBuild(fileTimestamps, contextTimestamps)).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("given a no context timestamp exists", () => {
|
||||
|
|
@ -255,9 +256,9 @@ describe("NormalModule", () => {
|
|||
contextTimestamps = new Map();
|
||||
});
|
||||
it("returns true", () => {
|
||||
expect(
|
||||
normalModule.needRebuild(fileTimestamps, contextTimestamps)
|
||||
).toBe(true);
|
||||
expect(normalModule.needBuild(fileTimestamps, contextTimestamps)).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,12 +36,6 @@ describe("RawModule", () => {
|
|||
);
|
||||
});
|
||||
|
||||
describe("needRebuild", () => {
|
||||
it("returns false", () => {
|
||||
expect(myRawModule.needRebuild()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("source", () => {
|
||||
it(
|
||||
"returns a new OriginalSource instance with sourceStr attribute and " +
|
||||
|
|
|
|||
Loading…
Reference in New Issue