Webpack plugins - when to call doResolve and when to callback?
Each plugin for webpack solution follows the following structure:
resolver.plugin(this.source, function(request, callback) {
if (something) {
resolver.doResolve(target, obj, "aliased with mapping '" + name + "': '" + ...)
} else {
callback(...);
}
Can anyone explain when I should call doResolve
and on callback. I found this phrase in the webpack docs:
To pass the request to other allowing plugins, use this.doResolve (types: String | String [], request: Request, callback) Method
However, I don't know what to do about it. It seems to doResolve
start the process from the beginning. This is what the stack looks like in doResolve
:
You can see that the stages started from the very beginning. Why?
source to share
Webpack runs all the plugins for the recognizer using the method applyPluginsAsyncSeriesBailResult1
. This method runs all plugins in sequence - the next plugin is only run after the current plugin has finished.
bail
here means the sequence is aborted as soon as one plugin returns an error. This approach is also known as "failed". But it BailResult
means that the sequence is also aborted as soon as one plugin returns a result. You can see this from sources:
applyPluginsAsyncSeriesBailResult1 = function applyPluginsAsyncSeriesBailResult1(name, param, callback) {
var plugins = this._plugins[name];
if(!plugins || plugins.length === 0) return callback();
var i = 0;
var _this = this;
var innerCallback = function next(err, result) {
// if the plugin returned an error or a result - break
if(arguments.length > 0) return callback(err, result);
i++;
// if all plugins have run - break
if(i >= plugins.length) {
return callback();
}
// trigger next plugin - continue
plugins[i].call(_this, param, innerCallback);
});
plugins[0].call(this, param, innerCallback);
};
So from this code you can see that as soon as you call callback
inside the plugin with parameters, you break the sequence. The first parameter is the error, the second result is the result. This matches how the Node.js
signature of the callbacks expects. If you call callback
with no parameters, the sequence continues .
Now you can also invoke doResolve
that will start all the plugin sequences again. This is usually done when you apply some changes to a request and therefore want to allow all other plugins to respond to a new request again. Since your current plugin will be called again in the next round doResolve
, be sure to create it to prevent recursion. Webpack again protects recursion, but only if path
, request
, query
directory
and module
are the same as seen from the source:
Resolver.prototype.doResolve = function doResolve(type, request, message, callback) {
var resolver = this;
var stackLine = type + ": (" + request.path + ") " +
(request.request || "") + (request.query || "") +
(request.directory ? " directory" : "") +
(request.module ? " module" : "");
var newStack = [stackLine];
if(callback.stack) {
newStack = callback.stack.concat(newStack);
if(callback.stack.indexOf(stackLine) >= 0) {
// Prevent recursion
var recursionError = new Error("Recursion in resolving\nStack:\n " + newStack.join("\n "));
And inside the callback to, doResolve
you usually call callback()
to exit the current round of plugins, since they were able to respond to the updated request:
resolver.plugin(this.source, function(request, callback) {
if (something) {
resolver.doResolve(target, obj,
"aliased with mapping '" + name + "': '" + ...,
function() { callback(error, result) }
)
source to share