Webpack 插件 - 何时调用 doResolve 以及何时回调?

Max*_*kyi 4 javascript webpack webpack-plugin

每个 webpack 解析插件都遵循以下结构:

resolver.plugin(this.source, function(request, callback) {
    if (something) {
         resolver.doResolve(target, obj, "aliased with mapping '" + name + "': '" + ...)
    } else {
         callback(...);
    }
Run Code Online (Sandbox Code Playgroud)

谁能解释一下我什么时候应该打电话doResolve,什么时候回电。我在 webpack 文档中发现了这句话:

要将请求传递给其他解析插件,请使用 this.doResolve(types: String|String[], request: Request, callback) 方法

但是,我不知道该怎么办。似乎doResolve从头开始这个过程。下面是堆栈的样子doResolve

在此处输入图片说明

你可以看到这些阶段从一开始就开始了。为什么?

Max*_*kyi 5

Webpack 运行解析器 usingapplyPluginsAsyncSeriesBailResult1方法的所有插件。此方法连续运行所有插件 - 仅在当前插件执行完毕后运行下一个插件。在bail这里意指该序列被中断只要一个插件返回一个错误。这种方法也称为“快速失败”。但这BailResult意味着一旦一个插件返回结果,序列也会被中断。您可以从以下来源看到它:

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);
};
Run Code Online (Sandbox Code Playgroud)

因此,从这段代码中您可以看到,只要您callback使用参数调用插件内部,就会中断序列。第一个参数是错误,第二个参数是结果。这符合Node.js回调签名的预期。如果您调用callback不带参数的 ,则序列会继续

现在,您还可以调用doResolvewhich 将再次运行整个插件序列。这通常在您对请求应用一些更改时完成,因此您希望再次给所有其他插件一个机会对新请求做出反应。由于您当前的插件将在下doResolve一轮再次调用,因此请确保构建它以防止递归。的WebPack后卫再次递归但前提是pathrequestquery directorymodule匹配可为从源头上可以看出:

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  "));
Run Code Online (Sandbox Code Playgroud)

在回调中,doResolve您通常会调用callback()中断当前一轮的插件,因为它们有机会对更新的请求做出反应:

resolver.plugin(this.source, function(request, callback) {
    if (something) {
         resolver.doResolve(target, obj, 
               "aliased with mapping '" + name + "': '" + ..., 
               function() { callback(error, result) }
         )
Run Code Online (Sandbox Code Playgroud)