最近在看公司項目的時候,對requireJS的define的路徑有一定的困惑,通過查閱資料做一下總結:
requirejs中無論是通過define來定義模塊,還是通過require來加載模塊,模塊依賴聲明都是很重要的一步。假設我們的目錄結構如下:
demo.html
js/main.js
js/lib.js
js/util.js
js/common/lib.js
js/common/jqury/lib.js
common/lib.js
- baseUrl
在requirejs的模塊路徑解析里, baseUrl
是非常基礎的概念,離開了它,基本就玩不轉了,所以這里簡單介紹一下。簡單的說, baseUrl
指定了一個目錄,然后requirejs基於這個目錄來尋找依賴的模塊。
在demo.html里加載requirejs,同時在requirejs所在的script上聲明 data-main
屬性,那么,requirejs加載下來后,它會做兩件事件:
- 加載js/main.js
- 將baseUrl設置為data-main指定的文件所在的路徑,這里是 js/
<script src="js/require.js" data-main="js/main.js"></script>
那么,下面依賴的lib模塊的實際路徑為 js/lib.js
main.js
require(['lib'], function(Lib){ // do sth });
除了 data-main
屬性,你也可以手動配置 baseUrl
,比如下面例子。需要強調的是: 如果沒有通過 data-main
屬性指定 baseUrl
,也沒有通過config的方式顯示聲明 baseUrl
,那么 baseUrl
默認為加載requirejs的那個頁面所在的路徑
demo.html
<script src="js/require.js"></script> <script src="js/main.js"></script>
main.js
requirejs.config({ baseUrl: 'js' }); require(['lib'], function(Lib){ // do sth });
- baseUrl+path:讓依賴更加簡潔、靈活
- 費力氣:每個加載的模塊前面都有長長的
common/fruits
- 難維護:說不定哪一天目錄名就變了(在大型項目中並不算罕見),想象一下目錄結構變更帶來的工作量
如下:
requirejs.config({ baseUrl: 'js' }); // 加載一堆水果 require(['common/fruits/apple', 'common/fruits/orange', 'common/fruits/grape', 'common/fruits/pears'], function(Apple, Orange, Grape, Pears){ // do sth });
將其修改為如下內容:
requirejs.config({ baseUrl: 'js', paths: { fruits: 'common/fruits' } }); // 加載一堆水果 require(['fruits/apple', 'fruits/orange', 'fruits/grape', 'fruits/pears'], function(Apple, Orange, Grape, Pears){ // do sth });
當項目結構變更時,好處就體現了。假設 common/fruits
某一天突然變成了 common/third-party/fruits
,那很簡單,改下 paths
就可以了。
- path:簡單但是實用
apple
:沒有在paths規則里定義,於是為 baseUrl + apple.js => js/apple.jscommon/fruits
:common已經在paths里定義,於是為baseUrl + common/fruits + apple.js => js/common/fruits/apple.js../common/apple
:common盡管已經在paths里定義,但是../common/apple
並不是以common開頭,於是為 baseUrl + ../common/apple.js => common/apple.js
1 requirejs.config({ 2 baseUrl: 'js', 3 paths: { 4 common: 'common/fruits' 5 } 6 }); 7 8 // 從左到右,加載的路徑依次為 js/lib.js、 js/common/jquery/lib.js、common/lib.js 9 require(['apple', 'common/apple', '../common/apple'], function(){ 10 // do something 11 });
- ./medole:疑惑的相對路徑
1、demo1
js/main.js
requirejs.config({ baseUrl: 'js/common' }); // 實際加載的路徑都是是 js/common/lib.js require(['./lib', 'lib'], function(Lib){ Lib.say('hello'); });
2、demo2
簡單改下上面的例子,可以看到:通過 define
定義模塊A時,模塊A依賴的模塊B,如果是 ./module
形式,則基於模塊A所在目錄解析模塊B的路徑。
js/main.js
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'); });
js/lib.js
// 依賴util模塊 define(['./util'], function(Util){ return { say: function(msg){ Util.say(msg); } }; });
3、demo 3
demo2實際上會有特例,比如下面,lib模塊依賴的util模塊,最終解析出來的路徑是 js/util.js
main.js
requirejs.config({ baseUrl: 'js', paths: { lib: 'common/lib' } }); // 實際加載的路徑是 js/common/lib.js require(['lib'], function(Lib){ Lib.say('hello'); });
lib.js
// util模塊解析后的路徑為 js/util.js define(['./util'], function(Lib){ return { say: function(msg){ Lib.say(msg); } }; });
4、demo 4
./module
路徑解析就會按照 baseUrl
+ moduleName
的方式,但稍微修改下main.js,發現結果就不一樣了。此時,util模塊對應的路徑為 js/common/util.js
main.js
requirejs.config({ baseUrl: 'js', paths: { common: 'common' } }); // 實際加載的路徑是 js/common/lib.js require(['common/lib'], function(Lib){ Lib.say('hello'); });
lib.js
define(['./util'], function(Lib){ return { say: function(msg){ Lib.say(msg); } }; });
requirejs中的路徑解析整體上不復雜,但 ./module
這種形式的路徑解析,總之,就是不要讓requirejs感到困惑,讓其尋找baseUrl。
另外,如果../module則表示在當前路徑回退兩個文件層。