前端模塊化開發方案小對比

jopen 9年前發布 | 37K 次閱讀 前端 前端技術


前端采用模塊化開發,使得開發體驗大大增強,擺脫了很多需要人力去做且容易出錯的點,使得代碼管理更加清晰、規范。主要表現為以下幾點:

  1. 減少命名沖突,消除全局變量
  2. 一個模塊一個文件,組織更清晰
  3. 依賴自動加載,按需加載
  4. </ol>

    其中文件按需加載,依賴自動管理,使得更多精力去關注模塊代碼本身,開發時不需要在頁面上寫一大堆script引用,一個require初始化模塊就搞定。不需要每增加一個文件,還要到HTML或者其他地方添加一個script標簽或文件聲明。

    前端模塊化規范標準

    1. CommonJs (Node.js)
    2. AMD (RequireJS)
    3. CMD (SeaJS)
    4. </ol>

      注:以下文中出現的AMD及CMD分別范指RequireJS、SeaJS。

      CommonJs

      CommonJS是服務器模塊的規范,Node.js采用了這個規范。根據CommonJS規范,一個單獨的文件就是一個模塊,每一個模塊都是一個單獨的作用域,在一個文件定義的變量(還包括函數和類),都是私有的,對其他文件是不可見的。CommonJS規范加載模塊是同步的,也就是說,只有加載完成,才能執行后面的操作。

      var x = 5;
      var addX = function(value) {
        return value + x;
      };

      module.exports.x = x; module.exports.addX = addX;</pre>

      AMD (RequireJS)

      由于Node.js主要用于服務器編程,模塊文件一般都已經存在于本地硬盤,所以加載起來比較快,不用考慮非同步加載的方式,因此CommonJS規范比較適用。但是,如果是瀏覽器環境,要從服務器端加載模塊,這時就必須采用非同步模式,因此瀏覽器端一般采用AMD規范。如下規范定義及一般寫法:

      //規范
      define(id?, dependencies?, factory);
      define.amd = {};
      //寫法1
      define(function(require, exports, module) {
        var $ = require('jquery');
        //code here
      });
      //寫法2
      define(['jquery'], function($) {
        //code here
      });
      //寫法3
      define(['require', 'jquery'], function(require) {
        var $ = require('jquery');
        //code here
      });

      CMD (SeaJS)

      CMD規范和AMD類似,都主要運行于瀏覽器端,寫法上看起來也很類似。主要是區別在于模塊初始化時機,AMD中只要模塊作為依賴時,就會加載并初始化,而CMD中,模塊作為依賴且被引用時才會初始化,否則只會加載。如下規范定義及一般寫法:

      //規范
      define(factory);
      define.cmd = {};
      //寫法1
      define(function(require, exports, module) {
        var $ = require('jquery');
        //code here
      });
      //寫法2
      define(['jquery'], function(require, exports, module) {
        var $ = require('jquery');
        //code here
      });

      兼容AMD、CMD及非模塊化

      很多時候如果我們引用第三方組件時,并沒有采用模塊化開發,通常我們自己需要包裝一下或通過模塊加載器的shim插件支持模塊化引用依賴。現在很多第三方庫已經默認支持AMD規范的引用,根據以上模塊定義規范,開放給第三方使用的組件能兼容不同的規范,如下示例:

      (function(root, factory) {
        if (typeof define === "function" && (define.amd || define.cmd) {
          define(function(require, exports, module) {
            return factory(root);
          });
        } else {
          root.dialog = factory(root);
        }
      })(window, function(root) {
        //code here
        return dialog;
      });

      AMD與CMD

      這里不對AMD及CMD作詳細對比,前面提到一點,最大的差異在于兩者的初始化時機不一樣,這種差異導致在遇到循環引用時,CMD在某些情況下是可解的,感興趣的同學可以看下,至于執行效率上,有人專門做過測試,這里不展開說明了。

      對于一般使用者來說,RequireJS、SeaJS都是不錯的選擇,對外調用API上,CMD的API設計更簡單,職能更單一,整體實現更輕量 也更傾向于CommonJS的規范寫法,提倡依賴就近聲明。前后端共享模塊時,只需要去掉define的包裝頭部就行了,雖然AMD也支持 CommonJS規范的寫法,但不是強制的。

      同時對于依賴的加載順序,AMD是不保證按照書寫的順序按序初始化模塊的,而這點CMD也更接近CommonJS規范,對于使用者來說require就是同步的。

      模塊化開發上線部署

      1. 壓縮
      2. 合并
      3. 更新版本
      4. </ol>

        不能直接壓縮:因為模塊加載器在分析模塊的依賴時,會先將模塊的工廠函數factory.toString(),然后通過正則匹配require局部變量,這樣意味著不能直接通過壓縮工具進行壓縮,若require這個變量被替換,加載器與自動化工具將無法獲取模塊的依賴。

        不能直接合并:我們在開發時,通過是省略模塊的ID的,如果多個模塊直接合并成一個文件,這樣加載器無法區分不同模塊了。

        所以采用模塊化開發上線部署時,壓縮前通常通過工具先提取依賴,這樣require就可以當做普通變量直接壓縮了,同時也不再需要加載器分析提取依賴,對于提升性能也是蠻有好處的。合并前同樣也需要借助工具先提取各個模塊的ID,然后才能按照合并配置進行合并。整個過程如下:

        前端模塊化開發方案小對比

        SeaJS和RequireJS官方都提供了構建工具,如SeaJS的 spm ,RequireJS的 r.js ,當然也很多grunt和glup插件可使用,區別于普通壓縮合并就是要有提取依賴及模塊ID的能力。

        對比構建工具使用感受,spm的整個上手并不是那么順暢,配置太復雜。r.js使用相對簡單,只需要配置好合并規范的配置文件即可,其它grunt或glup提供的插件相對靈活,可根據自身業務靈活配置。

        完成壓縮合并后,最后一步就是更新版本號上線了,通常是需要手動更新版本號,或是修改控制版本號的配置參數。這一步基本上還是需要人力手動干預一 下。當然如果合并是通過后端的combo服務就不需要了。不管怎么說,通過這些工具的組合使用,整個開發上線流程基本實現自動化了,比較方便。

        FIS的集成解決方案

        用過fis的同學都知道,采用fis開發,整體過程相當順暢,對于前端開發、性能、部署各方面的問題基本都考慮到了,內置的小巧mod.js加載器,就是一個特別輕量的模塊加載器,不需要做依賴分析,fis強大的編譯能力已經提前提取了依賴關系并生成jsmap.json。已經前置依賴了,一個輕量的加載器足足夠了,編譯的同時自動修改新生成的版本號,整個過程在fis下輕松完成。

        1. 語言擴展能力 (less, coffee, jade…)
        2. 前端模板預編譯
        3. xss自動轉義 無段手動干預
        4. 多域名支持,動態切換
        5. 編譯后自動修改版本號 (包括圖片的引用)
        6. 線上本地調試功能 ……
        7. </ol>

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