日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

.31-浅析webpack源码之doResolve事件流(3)

發布時間:2023/12/2 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .31-浅析webpack源码之doResolve事件流(3) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  放個流程圖:

  這里也放一下request對象內容,這節完事后如下(把vue-cli的package.json也復制過來了):

/*{ context: { issuer: '', compiler: undefined },path: 'd:\\workspace\\doc',request: './input.js',query: '',module: false,directory: false,file: false,descriptionFilePath: 'd:\\workspace\\doc\\package.json',descriptionFileData: *package.json內容*,descriptionFileRoot: 'd:\\workspace\\doc',relativePath: '.',__innerRequest_request: './input.js',__innerRequest_relativePath: '.',__innerRequest: './input.js' } */

  上一節看到這:

// 調用的是callback() function innerCallback(err, result) {if (arguments.length > 0) {if (err) return callback(err);if (result) return callback(null, result);return callback();}runAfter(); }

  這里接下來會調用runAfter方法,之前有講解過這個,簡單講就是觸發after-type的事件流,這里的type為parsed-resolve,即觸發after-parsed-resolve事件流。

  來源如下:

plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve"));

  這個插件就非常簡單了:

NextPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {resolver.doResolve(target, request, null, callback);}); };

  直接調用doResolve方法觸發下一個target的事件流,比起有描述文件的情況,這里的區別就是request少了幾個參數,觸發下一個事件流時沒有message。

?

  剛發現事件流的名字代表著某階段,此時代表描述文件解析完畢。

  接下來的事件流來源于以下幾個插件:

// described-resolve alias.forEach(function(item) {plugins.push(new AliasPlugin("described-resolve", item, "resolve")); }); plugins.push(new ConcordModulesPlugin("described-resolve", {}, "resolve")); aliasFields.forEach(function(item) {plugins.push(new AliasFieldPlugin("described-resolve", item, "resolve")); }); plugins.push(new ModuleKindPlugin("after-described-resolve", "raw-module")); plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));

?

AliasPlugin  

  先從第一個開始看,alias參數引用vue-cli的代碼,這里的alias在上面的第二部分進行了轉換(具體可參考28節)。

  數組的元素作為參數傳入了AliasPlugin插件中,源碼如下:

/* 源配置alias: {'vue$': 'vue/dist/vue.esm.js','@': '../src'} 轉換后為alias:[{name: 'vue',onlyModule: true,alias: 'vue/dist/vue.esm.js'},{name: '@',onlyModule: false,alias: '../src' }] */ AliasPlugin.prototype.apply = function(resolver) {var target = this.target;var name = this.name;var alias = this.alias;var onlyModule = this.onlyModule;resolver.plugin(this.source, function(request, callback) {var innerRequest = request.request;if (!innerRequest) return callback();// 兩個元素傳進來并不滿足if條件 跳過// startsWith可參考ES6的新方法http://es6.ruanyifeng.com/#docs/string#includes-startsWith-endsWithif (innerRequest === name || (!onlyModule && startsWith(innerRequest, name + "/"))) {if (innerRequest !== alias && !startsWith(innerRequest, alias + "/")) {var newRequestStr = alias + innerRequest.substr(name.length);var obj = Object.assign({}, request, {request: newRequestStr});return resolver.doResolve(target, obj, "aliased with mapping '" + name + "': '" + alias + "' to '" + newRequestStr + "'", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// don't allow other aliasing or raw requestcallback(null, null);}, callback));}}return callback();}); };

  不太懂這里的處理是干什么,反正兩個元素傳進來都沒有滿足if條件,跳過。

?

ConcordModulesPlugin

  described-resolve事件流還沒有完,所以callback執行后只是記數,下一個插件源碼如下:

ConcordModulesPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {// 獲取的還是'./input.js'var innerRequest = getInnerRequest(resolver, request);if (!innerRequest) return callback();// request.descriptionFileData就是配置文件package.json中的內容var concordField = DescriptionFileUtils.getField(request.descriptionFileData, "concord");// 找不到該屬性直接返回if (!concordField) return callback();// 下面的都不用跑了var data = concord.matchModule(request.context, concordField, innerRequest);if (data === innerRequest) return callback();if (data === undefined) return callback();if (data === false) {var ignoreObj = Object.assign({}, request, {path: false});return callback(null, ignoreObj);}var obj = Object.assign({}, request, {path: request.descriptionFileRoot,request: data});resolver.doResolve(target, obj, "aliased from description file " + request.descriptionFilePath + " with mapping '" + innerRequest + "' to '" + data + "'", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// Don't allow other aliasing or raw requestcallback(null, null);}, callback));}); };

  這里有兩個工具方法:getInnerRequest、getFiled,第一個獲取request的inner屬性,代碼如下:

module.exports = function getInnerRequest(resolver, request) {// 第一次進來是沒有這些屬性的if (typeof request.__innerRequest === "string" &&request.__innerRequest_request === request.request &&request.__innerRequest_relativePath === request.relativePath)return request.__innerRequest;var innerRequest;// './input.js'if (request.request) {innerRequest = request.request;// 嘗試獲取relativePath屬性進行拼接if (/^\.\.?\//.test(innerRequest) && request.relativePath) {innerRequest = resolver.join(request.relativePath, innerRequest);}} else {innerRequest = request.relativePath;}// 屬性添加request.__innerRequest_request = request.request;request.__innerRequest_relativePath = request.relativePath;return request.__innerRequest = innerRequest; };

  總的來說就是嘗試獲取__innerRequest屬性,但是初次進來是沒有的,所以會在后面進行添加,最后返回的仍然是'./input.js'。

  第二個方法就比較簡單了,只是從之前讀取的package.json對象查詢對應的字段,代碼如下:

// content為package.json配置對象 function getField(content, field) {if (!content) return undefined;// 數組及單key模式if (Array.isArray(field)) {var current = content;for (var j = 0; j < field.length; j++) {if (current === null || typeof current !== "object") {current = null;break;}current = current[field[j]];}if (typeof current === "object") {return current;}} else {if (typeof content[field] === "object") {return content[field];}} }

  代碼非常簡單,這里就不講了。

  常規情況下,沒人會去設置concord屬性吧,在vue-cli我也沒看到,這里先跳過。

?

AliasFieldPlugin

  接下來是這個不知道干啥的插件,處理的是resolve.aliasFields參數,默認參數及插件源碼如下:

// "aliasFields": ["browser"], AliasFieldPlugin.prototype.apply = function(resolver) {var target = this.target;var field = this.field;resolver.plugin(this.source, function(request, callback) {if (!request.descriptionFileData) return callback();// 一樣的var innerRequest = getInnerRequest(resolver, request);if (!innerRequest) return callback();// filed => browservar fieldData = DescriptionFileUtils.getField(request.descriptionFileData, field);if (typeof fieldData !== "object") {if (callback.log) callback.log("Field '" + field + "' doesn't contain a valid alias configuration");return callback();}var data1 = fieldData[innerRequest];var data2 = fieldData[innerRequest.replace(/^\.\//, "")];var data = typeof data1 !== "undefined" ? data1 : data2;if (data === innerRequest) return callback();if (data === undefined) return callback();if (data === false) {var ignoreObj = Object.assign({}, request, {path: false});return callback(null, ignoreObj);}var obj = Object.assign({}, request, {path: request.descriptionFileRoot,request: data});resolver.doResolve(target, obj, "aliased from description file " + request.descriptionFilePath + " with mapping '" + innerRequest + "' to '" + data + "'", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// Don't allow other aliasing or raw requestcallback(null, null);}, callback));}); };

  開頭跟之前那個是一樣的,也是調用getField從package.json中獲取對應的配置,但是這個默認的browser我在vue-cli也找不到,暫時跳過。

?

  正常處理完described-resolve事件流,繼續執行runafter觸發after-described-resolve事件流,來源如下:

plugins.push(new ModuleKindPlugin("after-described-resolve", "raw-module")); plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));

?

ModuleKindPlugin

ModuleKindPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {// 判斷module屬性if (!request.module) return callback();var obj = Object.assign({}, request);// 刪除module屬性delete obj.module;// 直接觸發下一個事件流resolver.doResolve(target, obj, "resolve as module", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// Don't allow other alternativescallback(null, null);}, callback));}); };

  這里的處理十分簡單,判斷request對象是否是module,是則直接觸發下一個事件流。

  而在第一次時進來的是入口文件,module屬性為false,所以這里會跳過,后面處理module再回來講。

?

JoinRequestPlugin

JoinRequestPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {var obj = Object.assign({}, request, {// request.path => d:\\workspace\\doc// request.request => ./input.js// 在join方法中會被拼接成d:\workspace\doc\.\input.js// 最后格式化返回d:\workspace\doc\input.js path: resolver.join(request.path, request.request),// undefinedrelativePath: request.relativePath && resolver.join(request.relativePath, request.request),request: undefined});resolver.doResolve(target, obj, null, callback);}); };

  這個地方終于把入口文件的路徑拼起來了,接下來調用下一個事件流,這節先到這里。

?

  寫完這節,總算對Resolver對象有所了解,總結如下:

1、該對象可以處理resolve參數、loader、module等等

2、插件的鏈式調用類似于if/else,比如說如果傳進來的是一個module,插件會流向module事件流;如果是普通的文件,會流向本節所講的方,每一種情況都有自己的結局。

3、一部分參數處理依賴于package.json的配置對象內容

轉載于:https://www.cnblogs.com/QH-Jimmy/p/8340639.html

總結

以上是生活随笔為你收集整理的.31-浅析webpack源码之doResolve事件流(3)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。