javascript模塊化實踐——嘗試require.js

爲什麼會想到用這個

       最近寫webapp因爲需要引入很多不同的js插件,所以部分頁面甚至引用了10-15行js文件。。有些順序依賴很難維護。所以嘗試使用require.js實現模塊化,管理模塊依賴,減少頁面直接引用面積,實現按需加載。瞭解了一下相關的AMD規範,嘗試寫一個demo理解require.js的配置方式、使用方式。

關於AMD規範

     簡單描述就是異步加載模塊,並在某個模塊加載前先加載當前模塊依賴的其他模塊。

     AMD使用define定義模塊,require引入模塊。

     詳細解釋可以參考https://www.jianshu.com/p/9b44a1fa8a96

舉個栗子

  define(['依賴模塊1','依賴模塊2'],function(){ return {模塊3對象}});

  require(['模塊3對象'],function(){  do something });

前期準備工作

    demo結構如圖

     

目前我有三個js文件,分別爲module_1.js/module_2.js/module_3.js ,在文件夾modules內

爲了測試用,所以每個js都只輸出log。 在test.html文件中引用這3個模塊

原有引用方式

普通的引入方式:

運行一下test.html

這樣的問題也很明顯,如果需要加載的js文件多,需要寫一堆引用。

如果依賴比較多,module2如果依賴module1,則必須在module2之前先引用module1.  引用的js一多,很難維護和管理。

 

使用require.js模塊加載方式

1.require.js介紹

RequireJS 其實就是一個JavaScript模塊加載器。對符合AMD規範的js文件實現模塊化加載。對不符合AMD規範的提供配置參數,依然可以作爲模塊引入。RequireJS是AMD規範的一個具體實現。

require.js下載地址:http://requirejs.org/docs/release/2.3.5/comments/require.js

 

2.require.js基本使用

require.js的使用方式是function (name, deps, callback) ,但是name參數大部分時候不需要單獨去定義,因爲name也是一個路徑的字符串,一旦變更js路徑,不僅僅是引用模塊處要變更,連define定義的地方也要把模塊名變更。所以可以省略掉name參數,這樣require.js會自動幫我們處理。

定義模塊:define(['依賴模塊1','依賴模塊2'],function(){ return {模塊3對象}});

引入模塊:  require(['模塊3對象'],function(){  //do something });

(1)我們把之前的module1 module2修改成符合AMD規範的模塊格式

(2)在test.html引入require.js, 並按AMD規範引入module1,module2,調用其中的test函數

(3) 在瀏覽器運行 test.html

 在瀏覽器f12->sources  可以看到模塊module_1 module_2已經被加載進來了。

f12-console看一下  也成功調用了兩個模塊內的ready()函數

 

3.require.config

 上邊直接使用require(),是直接引用模塊所在的路徑引入模塊的。存在一些問題

    · 對於不符合AMD規範定義的對象直接引用會找不到模塊報錯

    · 在實際應用中,如果項目路徑很長,可讀性賊差

    · 在擴展方面,如果變更一個js路徑或者js文件名,模塊名因爲是直接引入路徑,也需要變更。

所以可以使用require.config配置解決上述問題.

    require.config提供一個模塊id 對於js路徑的映射。然後引入的時候可以直接通過定義的模塊id進行引用。使模塊名字更符合定義,修改也可以直接修改config,不需要動require的引入代碼。可以通過“shim”配置描述,把不符合AMD規範定義的模塊作爲模塊導出。

    module_3是一個沒有根據規範定義的匿名函數,只有一句輸出。

  test.html,使用require.config在paths配置module_3的模塊名和路徑,shim配置module_3的描述信息和導出模塊名(具體解釋在代碼註釋中)。

//test.html    

    <script type="text/javascript" src="require.js"></script>
    <script type="text/javascript">
         require.config({
            //baseUrl是一個統一的根路徑,如果沒有需要可以不配
            //baseUrl:"",
            //paths配置直接模塊名對應路徑即可
            paths:{
                "mod1":"modules/module_1",
                "mod2":'modules/module_2',
                "mod3":'modules/module_3'
            },
            //shim配置不符合AMD規範的模塊
            shim:{
                "mod3":{
                    deps:[],//依賴的模塊
                    exports:'mod3'//導出的模塊名
                }
            }
         });
        require(['mod1', 'mod2','mod3'], function (mod1, mod2,mod3) {
            //把module_1,module_2作爲參數引入進來,就是mod1和mod2
            mod1.ready();
            mod2.ready();
        })
    </script>

    頁面執行

已經把module_3加載了。看一下console控制檯輸出

module_3的匿名函數也執行了。

 

4.data-main

    在第3步中使用require.config完成對不符合規範的模塊加載,以及定義模塊名和路徑的映射。但是每個頁面都去配置一個require.config難免太過於麻煩。如果必須這樣的話,這個工作量甚至會讓我想放棄使用require.js。

    很容易想到的解決方案是我們寫一個公共的配置文件config.js,來配置項目內所用到的模塊信息。

    但是require是異步加載,如何保證先跑這個config.js呢? require.js提供了一個data-main,可以保證最先加載data-main指定的js文件。引入require.js的時候 加一個data-main="配置js的路徑"即可。

   (1)創建config.js 。命名隨意,只要和data-main對得上就可以。

//config.js
(function(){
    require.config({
        //baseUrl是一個統一的根路徑,如果沒有需要可以不配
        //baseUrl:"",
        //paths配置直接模塊名對應路徑即可
        paths:{
            "mod1":"modules/module_1",
            "mod2":'modules/module_2',
            "mod3":'modules/module_3'
        },
        //shim配置不符合AMD規範的模塊
        shim:{
            "mod3":{
                deps:[],//依賴的模塊
                exports:'mod3'//導出的模塊名
            }
        }
     });
}());

(2) test.html頁面引入require.js時候添加data-main,指定主模塊。

    <!-- data-main聲明主模塊路徑,先加載主模塊-->
    <script type="text/javascript" src="require.js" data-main="config.js"></script>
    <script type="text/javascript">
        //最外層還是要先像普通引入模塊一樣,引入主模塊,加載配置
        require(['config'], function () {
            //然後再根據配置文件中定義的模塊,按需要引入。
            require(['mod1', 'mod2', 'mod3'], function (mod1, mod2, mod3) {
                mod1.ready();
                mod2.ready();
            })
        });
    </script>

 

(3)運行test.html

可以看到config.js和引用的3個模塊都加載進來了。

 

有一個困惑,就是不嵌套外層require(['config'])的話會報錯,也就是require.js是把主模塊作爲一個模塊輸出的,我想引用config內配置的模塊,就必須套一層引用config模塊。看起來有些彆扭。但是能力有限沒找到好的解決方案。如果有的話歡迎告訴一下。

總結

        本文中展示的代碼demo在https://github.com/tennyxx/cx.require.demo

        使用requirejs在本文的demo中感覺並不如直接引入方便,但是在具體的開發環境中可能有N多需要引入的東西,比如基於mui的webapp開發,需要先引入mui.js,然後一系列的時間組件、選擇插件等等依賴mui.js.這種就需要要求一定的順序,並且數量很多。  使用require.js很好地解決了此類問題。

        自己有寫一個簡單的webapp的開發結構,各種公共的配置文件使用了require.js實現模塊化異步按需加載。有興趣可以參考歡迎提一些意見。https://github.com/tennyxx/cx.frame.webapp

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章