簡單介紹下modJS

ygfb 9年前發布 | 28K 次閱讀 modJS 前端技術
 

近期把團隊的項目構建遷移到fis3,同時把模塊加載器也由之前的requirejs切換到了modJS。

有些同學可能不了解modJS,這里做個簡單的介紹。

那么,modJS是什么呢?

簡單的說,modJS是百度fex-team提供的一個輕量級的模塊加載器,類似requirejs。

但modJS并不完全兼容規范amd/cmd,事實上,只支持非常簡單的全局方法define(id,factory)。

另外factory提供了3個參數require/exports/module,用于引用和導出模塊。

modJS源碼只有200行左右,相比之下requirejs的源碼達到了2000+行。

除了體量非常小之外,modJS配合fis3的fis3-hook-commonjs插件,可以在純前端項目中實現類似nodejs一樣的開發體驗。

那么,我們為什么要使用modJS呢?

有以下幾點:

  1. 加載器更小

上面已經提到,200+行和2000+行的差異

  1. 配合構建工具,開發體驗更好

之前開發時,需要將每一個模塊的代碼單獨放在define內部,并且需要申明每一個依賴。 而現在,只需要使用類似nodejs的方式編寫代碼,需要使用某個依賴模塊時,直接require('id')即可。 發布編譯時,由構建工具統一添加define包裹,自動添加模塊id(默認根據路徑生成,也可以在fis3的配置中聲明格式)。整體的開發體驗更好一些。

此外,js文件打包及異步依賴的問題,也可以通過生成resourceMap來解決。

一般情況下,modJS配合fis3已經可以滿足大部分需求,并且官方還提供了完整支持amd規范的esl-mod.js。

如果不夠用,也可以在modJS的基礎上定制一些功能來滿足需求,因為源碼只有200行,代碼也很清晰簡單。

我們的項目在切換到modJS時,由于項目比較復雜(2000+文件),一些特殊的需求最終也是通過定制modJS得到解決,這里分享幾點:

遇到哪些問題

  • 同步(直接require)的依賴需要打包,異步依賴使用require.async加載

requirejs將所有依賴模塊在define方法的參數中聲明,所以可以保證先異步加載需要的模塊,最后再執行factory。

而modJS設計之初,便考慮到稍微大型點的前端項目都會打包模塊js減少請求優化性能,依賴的模塊其實早已合并打包,并不需要在define中聲明后再異步加載。

所以需要將所有異步的模塊以require.async方法來加載。

以我們的項目為例,首次加載時,會加載3個打包的js文件,分別是基礎庫(modjs、jquery、badjs)、base.js(其他打包的通用模塊,初始化一些變量)、mod.main.js(當前頁面用到的邏輯打包)。 當用戶點擊其他頁面(非刷新)時,再異步加載該頁面用到的mod.main.js(其他頁面打包合并后的js),這部分js的模塊id和url由構建工具統一打到resourceMap中。

  • 不支持直接引用遠程url,包括同步和異步方式都不支持。

由于歷史原因,項目中存在一些如下形式的代碼:

define(id,['http://a','http://b'],function(a,b){
    a.xxx(b)
    ...
})

通過腳本統一替換為commonJS規范后,舊代碼變成了這樣:

var a = require('http://a'); var b = require('http://b');
a.xxx(b)
...

這種同步方式的代碼目前沒什么好的解決辦法,最后重構代碼解決。

異步的方式稍微好一些,可以通過構建將遠程url打入到resourceMap。

  1. 異步加載方法require.async([deps],callback)中的callback觸發

modJS加載異步模塊時,將callback回調加入一個隊列,然后將依賴模塊的script標簽打入html的head。 但是callback并不是通過script的onload事件觸發,而是通過依賴模塊的define方法觸發。

當我們只是想用require.async異步加載一個非amd規范的腳本時(例如一些第三方的組件、jquery插件等),由于該腳本并沒有被define方法包裹,所以無法觸發回調的邏輯。

雖然理論上不應該有這個問題,一個項目的模塊化方案應該統一,每一個模塊都應該使用define包裹,但現實就這樣。

  1. 同時異步加載多個模塊時,腳本的加載順序問題

modJS異步加載時,會將多個script腳本同時插入到head,并不會維護腳本的加載順序。

這個問題,怎么說,理論上模塊的依賴關系都應該由加載器來管理,而不應該出現腳本的加載依賴問題。但現實就這樣。

當然,如果你愿意的話也可以將源碼改成這樣的形式:

require.async(moduleA,function(){
  require.async(moduleB,function(){
    ...do something
    ...囧
    ...do something
  });
});

 本文由用戶 ygfb 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!