這兩天正好看到了程序員小卡同窗的一篇博客,裏面對requireJS路徑的解析作了一些說明,裏面有點問題待解決,我這裏正好知道一點,因此整理成文,不知對小卡同窗是否有幫助。html
requirejs.config({ baseUrl: 'js' }); // 依賴lib.js,實際加載的路徑是 js/common/lib.js,而lib模塊又依賴於util模塊('./util'),解析後的實際路徑爲 js/common/util.js require(['common/lib'], function(Lib){ Lib.say('hello'); });
// 依賴util模塊 define(['./util'], function(Util){ return { say: function(msg){ Util.say(msg); } }; });
如果變個寫法,util的目錄結構就變了node
requirejs.config({ baseUrl: 'js', paths: { lib: 'common/lib' } }); // 實際加載的路徑是 js/common/lib.js require(['lib'], function(Lib){ Lib.say('hello'); });
// util模塊解析後的路徑爲 js/util.js define(['./util'], function(Lib){ return { say: function(msg){ Lib.say(msg); } }; });
咱們今天便一塊兒來學習下這個問題程序員
require(['common/lib'], function(Lib){ Lib.say('hello'); });
該代碼會在require內部執行過程當中,具備第一個依賴項,這個依賴項是'common/lib',他的鍵值即是這個了app
這裏會首先加載器依賴項,common/lib,而此時便會作第一步的解析而且造成一個模塊ide
在模塊加載時,會建立一個script標籤,而且爲其綁定load事件,這裏會有第二個事件的觸發oop
② 在加載common/lib模塊時,有一個關鍵點須要注意:requirejs
上述雖然與本次討論的東西無關,倒是理解整個require的關鍵,各位能夠去看看學習
③ context.completeLoad(data.id) =>可是這個時候卻發現其有一個依賴項,因而便會先加載器依賴項,這裏又會進入,main.js中require的邏輯,即這段代碼:ui
1 //Enable each dependency 2 each(this.depMaps, bind(this, function (depMap, i) { 3 var id, mod, handler; 4 if (typeof depMap === 'string') { 5 //Dependency needs to be converted to a depMap 6 //and wired up to this module. 7 depMap = makeModuleMap(depMap, 8 (this.map.isDefine ? this.map : this.map.parentMap), 9 false, 10 !this.skipMap); 11 this.depMaps[i] = depMap; 12 handler = getOwn(handlers, depMap.id); 13 if (handler) { 14 this.depExports[i] = handler(this); 15 return; 16 } 17 this.depCount += 1; 18 on(depMap, 'defined', bind(this, function (depExports) { 19 this.defineDep(i, depExports); 20 this.check(); 21 })); 22 if (this.errback) { 23 on(depMap, 'error', bind(this, this.errback)); 24 } 25 } 26 id = depMap.id; 27 mod = registry[id]; 28 //Skip special modules like 'require', 'exports', 'module' 29 //Also, don't call enable if it is already enabled, 30 //important in circular dependency cases. 31 if (!hasProp(handlers, id) && mod && !mod.enabled) { 32 context.enable(depMap, this); 33 } 34 }));
這是很是關鍵的一段代碼,不管裏面的depcount仍是其中的on defined事件點註冊皆十分關鍵this
從這裏開始會加載util相關資源,因而util進入了相關加載流程了,這也是小卡關注的地方
可是這裏有一個不同的地方是,util模塊時具備parentModuleMap的,而common/lib不具備
這裏util與lib有一個映射關係lib->util,因此util的parentName就是common/lib
這個時候就到了解析URL這個步驟了
//name=>./util; parentName=>common/lib normalizedName = normalize(name, parentName, applyMap);
咱們要作的事情就是解析這個地址
/** * Given a relative module name, like ./something, normalize it to * a real name that can be mapped to a path. * @param {String} name the relative name * @param {String} baseName a real name that the name arg is relative * to. * @param {Boolean} applyMap apply the map config to the value. Should * only be done if this normalization is for a dependency ID. * @returns {String} normalized name */ function normalize(name, baseName, applyMap) { var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex, foundMap, foundI, foundStarMap, starI, normalizedBaseParts, baseParts = (baseName && baseName.split('/')), map = config.map, starMap = map && map['*']; //Adjust any relative paths. if (name) { name = name.split('/'); lastIndex = name.length - 1; // If wanting node ID compatibility, strip .js from end // of IDs. Have to do this here, and not in nameToUrl // because node allows either .js or non .js to map // to same file. if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); } // Starts with a '.' so need the baseName if (name[0].charAt(0) === '.' && baseParts) { //Convert baseName to array, and lop off the last part, //so that . matches that 'directory' and not name of the baseName's //module. For instance, baseName of 'one/two/three', maps to //'one/two/three.js', but we want the directory, 'one/two' for //this normalization. normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); name = normalizedBaseParts.concat(name); } trimDots(name); name = name.join('/'); } //Apply map config if available. if (applyMap && map && (baseParts || starMap)) { nameParts = name.split('/'); outerLoop: for (i = nameParts.length; i > 0; i -= 1) { nameSegment = nameParts.slice(0, i).join('/'); if (baseParts) { //Find the longest baseName segment match in the config. //So, do joins on the biggest to smallest lengths of baseParts. for (j = baseParts.length; j > 0; j -= 1) { mapValue = getOwn(map, baseParts.slice(0, j).join('/')); //baseName segment has config, find if it has one for //this name. if (mapValue) { mapValue = getOwn(mapValue, nameSegment); if (mapValue) { //Match, update name to the new value. foundMap = mapValue; foundI = i; break outerLoop; } } } } //Check for a star map match, but just hold on to it, //if there is a shorter segment match later in a matching //config, then favor over this star map. if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { foundStarMap = getOwn(starMap, nameSegment); starI = i; } } if (!foundMap && foundStarMap) { foundMap = foundStarMap; foundI = starI; } if (foundMap) { nameParts.splice(0, foundI, foundMap); name = nameParts.join('/'); } } // If the name points to a package's name, use // the package main instead. pkgMain = getOwn(config.pkgs, name); return pkgMain ? pkgMain: name; }
PS:我看requireJS版本,又老了,他的代碼又有更新啊!!!
上面這段代碼是一個關鍵
main.js=>require(['common/lib'], function (Lib)=>common/util main.js=>require(['lib'], function (Lib)=>util main.js=>require(['a/b/c/lib'], function (Lib)=>a/b/c/util
這裏util是相對於父級的目錄,這個是其地址變化的主要緣由
因此,如今關於小卡的問題應該獲得瞭解決,至於其map映射關係是如何造成的,這個話題就更加深了
小釵requireJS也是初學,不少不懂,不知是否是解決了小卡的問題,這裏提出來各位高手一塊兒看看,有誤請提出。