切圖崽的自我修養-SeaJs重要概念剖析

大切圖崽發表於2019-02-16

前言

高能預警,前方山路十八彎

在上一篇文章裡簡單的討論了一下模組化Js, 先來回顧一下目前模組化的兩大規範:

  • CommonJs 同步載入模組規範

  • AMD/CMD 非同步載入模組規範

其中CMD規範的產出是國內目前十分火爆的SeaJs, 這篇文章主要是解釋幾個使用SeaJs會碰到的重要概念

  • 具名模組

  • 匿名模組

  • 路徑即ID原則


匿名模組

SeaJs定義匿名模組一般採用如下的方式:

define(function(require,exports,module){xx})


具名模組

SeaJs定義除了定義匿名模組,還可以定義具名模組

//define(BlockID,[Deps],function(require,exports,module){})
 define(‘A’,[],function(require,exports,module){xx})

其中可以

  • 第一個引數 定義該模組的名字(即ID),用來唯一標識該模組

  • 第二個引數 把該模組依賴的模組從函式體裡提到引數中,用來標識該模組還依賴了哪些模組

  • 第三個引數 模組主體

為什麼需要具名模組?

誠然,我們可以把所有模組都以匿名的形式書寫。但這樣有個很大的缺點,就是模組化會導致Js檔案特別多,這樣無形中會加大了http請求的數
我們在知道,在檔案比較小的時候, 檔案的大小並不顯著影響http的下載速度, 但是如果把這個檔案拆成兩個檔案下載,增加的一次http開銷確是很大的
所以,很多情況下我們需要把零碎的Js模組進行合併成一個檔案。但是這麼多模組合併在一個檔案裡,全是匿名的話,系統如何區別哪個是哪個模組呢? 因此,我們需要對這些模組給不同的ID進行標識。 於是這些帶了ID的模組,就叫做具名模組


路徑即ID

上面解釋了什麼是具名模組,為什麼需要用具名模組,我們現在就來給具名模組命名

SeaJs遵循的是路徑即ID命名規則,意思就是具名模組的ID名是路徑的一部分. 而沿著最終拼接出來的路徑,肯定可以找得到這個具名模組

聽起來很繞,但這個規則非常非常非常重要.作者也是在理解SeaJs路徑的過程中踩坑無數,這裡就來重點講一下
首先來看SeaJs的路徑的書寫種類,總的來說,可以分為3種.

  1. 相對路徑(以相對路徑符開頭,比如../js/), 路徑以本頁面為起點

  2. 直接路徑(以直接目錄開頭,比如js/), 路徑以baseUrl為起點

  3. 根路徑(以根路徑開頭, 比如/app/js/) 路徑以專案根目錄為起點

這裡拿入口檔案index.html舉例:


<!--例1-->
<script>
    seajs.config({
    base: "../js/",      
    alias:{"JQ":"lib/jquery"}        
    })
    
    seajs.use("src/index.js")  
</script>
    
  • base引數是以當前頁面(index.html)為參照,設定基礎相對路徑baseUrl.
    在本例中base設定採用相對路徑的形式, 那麼baseUrl = (index.html的位置) + (../js/)

  • alias能夠給具名模組(例子中該匿名模組ID為lib/jquery)取別名(JQ),取別名的好處在於可以把具名模組本身非常冗長的路徑命名變得很短很小清新,一般是針對頁面需要引用的庫檔案.
    在本例中JQ 後的路徑是採用直接路徑的形式, 那麼JQ的路徑= (baseUrl) + (lib/jquery) = (index.html的位置)+ (../js/) + (lib/jquery/)

  • sea.use用來指定SeaJS載入器的入口, 通過在入口js再載入七七八八頁面所需的JS模組達到按需載入的目的
    在本例中,sea.use的路徑是採用直接路徑的形式, 那麼入口檔案index.js的路徑 = (baseUrl) + (src/index.js) = (index的位置) + (../js/) + (src/index.js)

如果換一種形式寫:

<!--例2-->
<script>
    seajs.config({
    base: "../js/",      
    alias:{"JQ":"../js/lib/jquery"}        
    })
    
    seajs.use("../js/src/index.js")  
</script>

  • base設定採用相對路徑的形式, 那麼baseUrl = (index.html的位置) + (../js/)

  • alias JQ 後的路徑是採用相對路徑的形式, 那麼JQ的路徑= (index.html的位置) + (../js/lib/jquery)

  • sea.use的路徑是採用相對路徑的形式, 那麼入口檔案index.js的路徑= (index.html的位置) + (../js/src/index.js)

現在拿例1來說:

<!--例1-->
<script>
    seajs.config({
    base: "../js/",      
    alias:{"JQ":"lib/jquery"}        
    })
    
    seajs.use("src/index.js")  
</script>

既然alias中具名模組叫lib/jquery, 那麼你的jquery通過define定義的模組ID一定是lib/jquery

define(‘lib/jquery’,[],function(require,exports,module){xx})

又由於alias中具名模組(lib/jquery)的採用了直接路徑的方式, 根據路徑即ID的原則,你應該可以順著 (baseUrl) + (lib/jquery) 找到該具名模組的位置,如果找不到,肯定會報錯

現在拿例2來說:

<!--例2-->
<script>
    seajs.config({
    base: "../js/",      
    alias:{"JQ":"../js/lib/jquery"}        
    })
    
    seajs.use("../js/src/index.js")  
</script>

既然alias中具名模組叫../js/lib/jquery, 那麼你的jquery通過define定義的模組ID一定是../js/lib/jquery

define(‘../js/lib/jquery’,[],function(require,exports,module){xx})

又由於alias中具名模組(../js/lib/jquery)的採用了相對路徑的方式, 根據路徑即ID的原則,你應該可以順著 index.html當前位置 + (../js/lib/jquery) 找到該具名模組的位置,如果找不到,肯定會報錯


實際使用

但實際的使用上,我們基本不會去寫具名模組, 而是全部寫匿名模組
然後通過自動化構建工具(比如grunt,gulp,fis3)的外掛去自動解決匿名模組具名化的問題,比如grunt就提供了相關外掛:

  • grunt-cmd-transport 將匿名模組轉換成具名模組

  • grunt-cmd-concat 將具名模組合併壓縮到一個Js檔案裡


結語

SeaJs大法好,Grunt大法好 但在使用這些工具的之時,並不是簡單抄一兩個demo就完事. 很多情況下你要根據自己工程的特性來調整目錄結構,而模組所在的路徑,和模組的ID, 和最後JS合併壓縮的過程息息相關. 所以必須理解它們的規則,運用起來才能更加得心應手

相關文章