.33-淺析webpack源碼之doResolve事件流(5)

file => FileExistsPluginjson

  這個事件流快接近尾聲了,接下來是FileExistsPlugin,很奇怪的是在最後纔來檢驗路徑文件是否存在。app

  源碼以下:async

FileExistsPlugin.prototype.apply = function(resolver) {
    var target = this.target;
    resolver.plugin(this.source, function(request, callback) {
        var fs = this.fileSystem;
        // file => d:\workspace\doc\input.js
        var file = request.path;
        fs.stat(file, function(err, stat) {
            // stat => 文件信息
            if (err || !stat) {
                if (callback.missing) callback.missing.push(file);
                if (callback.log) callback.log(file + " doesn't exist");
                return callback();
            }
            // 是否爲文件
            if (!stat.isFile()) {
                if (callback.missing) callback.missing.push(file);
                if (callback.log) callback.log(file + " is not a file");
                return callback();
            }
            // 只作信息提示 不對結果作處理
            this.doResolve(target, request, "existing file: " + file, callback, true);
        }.bind(this));
    });
};

  這裏只是簡單的對路徑文件進行狀態獲取,而後判斷是否存在?是不是文件?最後調用一個有message的doResolve方法進入到下一個事件流。函數

 

existing-file => NextPlugin測試

  這個插件沒什麼卵用,以前提到過,會直接跳到下一個事件流。this

 

resolved => ResultPluginspa

  這是最後一個插件,在注入的時候只有一個參數,表明事件流的結尾。prototype

ResultPlugin.prototype.apply = function(resolver) {
    resolver.plugin(this.source, function(request, callback) {
        var obj = Object.assign({}, request);
        // 調用resolver的事件流
        resolver.applyPluginsAsyncSeries1("result", obj, function(err) {
            if (err) return callback(err);
            callback(null, obj);
        });
    });
};

  這裏直接調用了resolver的result事件流,並無經過doResolve方法。插件

  通過測試,這個事件流並不存在,因此會直接調用無參callback,這個callback是什麼呢???code

  找了好久好久,終於找到了,回到最開始的resolve方法中,有個函數:

function onResolve(err, result) {
    // 無錯誤狀況下調用這個
    if (!err && result) {
        return callback(null, result.path === false ? false : result.path + (result.query || ""), result);
    }

    localMissing = [];
    log = [];
    // 錯誤處理
    return resolver.doResolve("resolve", obj, message, createInnerCallback(onError, {
        log: writeLog,
        missing: localMissing,
        stack: callback.stack
    }));
}

  這裏由於成功執行完事件流,第一個參數爲null,因此會進入第一個if分支,最後返回的是path與result。

  這個callback就簡單了,回到了resolve方法的調用地點:

asyncLib.parallel([
    callback => this.resolveRequestArray(contextInfo, context, elements, this.resolvers.loader, callback),
    callback => {
        if (resource === "" || resource[0] === "?")
            return callback(null, {
                resource
            });
        this.resolvers.normal.resolve(contextInfo, context, resource, (err, resource, resourceResolveData) => {
            // 從這裏開始
            if (err) return callback(err);
            /* 
                resource => d:\workspace\doc\input.js
                resourceResolveData => 
                {
                    context: { issuer: '', compiler: undefined },
                    path: 'd:\\workspace\\doc\\input.js',
                    request: undefined,
                    query: '',
                    module: false,
                    file: false,
                    descriptionFilePath: 'd:\\workspace\\doc\\package.json',
                    descriptionFileData:{ *配置文件內容* },
                    descriptionFileRoot: 'd:\\workspace\\doc',
                    relativePath: './input.js',
                    __innerRequest_request: undefined,
                    __innerRequest_relativePath: './input.js',
                    __innerRequest: './input.js' 
                }
            */
            callback(null, {
                resourceResolveData,
                resource
            });
        });
    }
], (err, results) => { /**/ })

 

總結

  這裏對以前的resolve方法所作的流程作一個總結,畫一個圖。

  剔除一些諸如NextPlugin這種垃圾插件以及重複加載的插件,插件加載按順序,全部的type的before、after均視爲一個事件流,特殊分支給給出說明。

相關文章
相關標籤/搜索