接觸過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
下面的這兩個例子,看著很簡單吧,但應該大部分的人跟我一樣沒辦法一眼就識別出來相依模組最終轉化成的路徑。原因在於,這裡壓根就沒有提供足夠的上下文資訊。。。(= =b 別打我)
require例子:
// main.jsrequire(['./util'], function(){ // do sth});
define例子:
define(['./util'], function(){ // do sth });
下面,我們再一步步通過具體的例子來看下,requirejs在不同的情境下,是如何解析模組路徑的。 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的作者提供了 paths 這個配置項。我們看下修改後的代碼。
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 首碼,也沒節省多少代碼,但當項目結構變更時,好處就體現了。假設 common/fruits 某一天突然變成了 common/third-party/fruits ,那很簡單,改下 paths 就可以了。
requirejs.config({ baseUrl: 'js', paths: { fruits: 'common/third-party/fruits' }});
paths :簡單但需要記住的要點
上一節已經舉例說明了path的例子。這裡再來個例子,說明下下三種情況下,匹配路徑的規則
> apple :沒有在paths規則裡定義,於是為 baseUrl + apple.js => js/apple.js common/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
requirejs.config({ baseUrl: 'js', paths: { common: 'common/fruits' }});// 從左至右,載入的路徑依次為 js/lib.js、 js/common/jquery/lib.js、common/lib.jsrequire(['apple', 'common/apple', '../common/apple'], function(){ // do something});
./module :讓人疑惑的相對路徑
應該說,這個是最讓人疑惑的地方。 demo 1
js/main.js
requirejs.config({ baseUrl: 'js/common'});// 實際載入的路徑都是是 /lib.jsrequire(['./lib', 'lib'], function(Lib){ Lib.say('hello');});
demo 2
簡單改下上面的例子,可以看到:
通過 define 定義模組A時,模組A依賴的模組B,如果是 ./module 形式,則基於模組A所在目錄解析模組B的路徑。
js/main.js
requirejs.config({