Requirejs常用配置和應用


requirejs、require方法沖突

如果加載了多個requirejs腳本,每個requirejs會判斷是否瀏覽器已經實現了require和define方法。如果瀏覽器已經自帶require和define方法,或者之前已經有一個requirejs腳本執行,那么這個requirejs就會立刻停止執行。所以,即使頁面上加載了多次requirejs腳本也不會有什么問題。

配置Context

我把context叫做一個命名空間,因為每一個context都有一個名字,這樣同名而功能不同的模塊就可以放在不同的context中以防沖突。

如果開發人員沒有配置context,那么,requirejs還會生成一個默認的context,這個默認的context配置大致如下:

requirejs.config({

    context: "_",  // default context name

    baseUrl: "./",

    waitSeconds:7, // how long canloading last

    paths: {},

    bundles: {},

    pkgs: {},

    shim: {},

    config: {}

});

注意:在不指定context名稱的情況下,任何配置和調用都是針對默認context的修改和調用。

空間名稱 – context

如果requirejs初始化時自定義配置context,那么默認創建的context的name 就是”_”。如果需要添加新的context,只需指定一個新的contextName即可,比如下面這個調用就會創建一個新的context:

requirejs({context:”new content name”});

同名的context只會有一個,配置同名的context等於修改這個context的屬性。

加載超時 – waitSeconds

每個context都配置了一個加載超時的時間,某個模塊如果沒有初始化,加載的時間又超過了這個時間,就會被認為加載失敗。

加載超時是針對整個context下的所有模塊而言的,而不是單指某個模塊,也就是說這個默認的7秒是指所有模塊應該在7秒之內全部加載完成。7秒之后,如果有沒有被加載的模塊,將拋出error指示哪些模塊沒有加載。(requirejs每隔50毫秒做一次判斷)。

基准URL – baseUrl

每個context的基准URL默認值是”./”。

第一個context的基准URL

如果開發人員沒有指定context名稱,那么這個第一個context就是requirejs默認生成的context,否則就是開發人員自己定義的context。在不指定基准URL的前提下,第一個context的基准URL設定比較特殊,除了標准的設定方法(參考后面的基准URL標准設定方法),還可以使用以下兩種特殊方式設置:

第一種:通過requirejs或require對象配置

在確認requirejs腳本之前沒有其它requirejs執行過的前提下:

<script>requirejs={baseUrl: './'}</script>

<script data-main="scripts/app.js"src="../require.js"></script>

<script>require={baseUrl: './'}</script>

<script data-main="scripts/app.js"src="../require.js"></script>

注意:通過這種方式設置基准URL,data-main指定的腳本文件位置也會變成相對於基准URL的路徑,因為data-main指定的腳本本身只是依賴的關系之一。而且,data-main指定的腳本也屬於第一個context。

比如下面這種情況:

<script>requirejs={baseUrl: 'scripts/lib'}</script>

<script data-main="scripts/app.js"src="../require.js"></script>

腳本模塊app.js的最終路徑變成了"scripts/lib/scripts/app.js",不是原來的"scripts/app.js",而且它的依賴名稱也會變為scripts/lib/scripts/app(requirejs默認會去掉腳本路徑的最后一個“.js”,除非data-main的值以“/”開頭,或包含“:”,或包含“?”)

第二種:根據script元素的data-main屬性指定的腳本路徑計算

如果沒有設定baseUrl,requirejs會根據script元素data-main屬性指定的JavaScript文件路徑計算出一個基准URL。

比如data-main="scripts/app.js",那么baseUrl就是"scripts/":

<script data-main="scripts/app.js"src="../require.js"></script>

基准URL標准設定方法

除了第一個context可以使用上面的方法,其它自定義的context配置baseUrl就只能使用下面這兩種方法。但這兩種方法同樣也可以用來修改第一個context的屬性,在不指定context名稱的情況下,其實就是修改第一個context

通過requirejs或require方法(這兩個本身就是同一個方法)設置

以下兩個等於把默認命名空間的基准URL設置成了scripts/lib:

requirejs({baseUrl:'scripts/lib'});

require({baseUrl:'scripts/lib'});

通過requirejs.config方法

requirejs.config({baseUrl:'scripts/lib'});

require.config({baseUrl:'scripts/lib'});

其實config方法調用的就是requirejs方法,所以它們是一樣的。

模塊依賴 – deps

模塊依賴是指個模塊之間的相互依賴關系,腳本運行時,只有當依賴的模塊全部加載完成之后,當前腳本才會執行,這就是依賴關系的作用。

依賴關系使用數組配置,數組元素為字符串(即模塊的名稱),一般是相對於baseUrl的路徑,只不過沒有文件后綴。而且,為了比較方便的獲取模塊入口,模塊一般會通過define方法定義。因為,通過define定義的模塊,可以被依賴數組后面的回調函數直接獲取並使用。

jQuery為例,在jquery腳本的末尾一般有下面兩行代碼:

if(typeof define === "function"&& define.amd && define.amd.jQuery) {

    define("jquery", [], function () { return jQuery; } );

}

再以underscore為例,在腳本末尾有下面幾行代碼:

if (typeof define === 'function' && define.amd) {

  define('underscore', [],function() {

    return _;

  });

}

模塊和模塊位置

使用require配置依賴模塊的時候,只是聲明了模塊的名稱,卻不知道模塊的具體位置。在沒有特殊聲明的情況下,requirejs認為模塊名和文件名相同,因此,只要兩者一致,requirejs就可以正確找到腳本文件。但如果不同,就需要通過path配置:

requirejs.config({

    baseUrl:"scripts/lib",

    paths: {

        jquery:'jquery-1.7.2'

    }

});

這樣,requirejs就知道jquery模塊位於scripts/lib/jquery-1.7.2.js文件中。

第一個context的依賴關系

<script>requirejs={deps: ['jquery']}</script>

<script data-main="scripts/app.js"src="../require.js"></script>

其它context的依賴關系

與基准URL的方式一樣,既可以通過requirejs方法,也可通過requirejs.config方法配置。

模塊束-bundles

如果一個JS文件中有多個模塊,就可以使用模塊束的方式聲明:

requirejs.config({

    baseUrl:"scripts/lib",

    bundles: {

        jsUtil:['MathUtil', 'DateUtil']

    }

});

上面這個例子就是說在scripts/lib/jsUtils.js文件中有MathUtil和DateUtil這兩個子模塊。

JS包– packages

如果一個文件夾中有多個JS文件,使用path的方式寫全就需要很多行代碼,這個時候如果使用包的方式聲明就可以省去很多麻煩:

requirejs.config({

    baseUrl:"scripts/lib",

    pkgs: [{name:'jqueryui',location: 'jqueryui/',main: 'core'}]

});

這樣定義之后,凡是在scripts/lib/jqueryui/目錄下的模塊就可以通過這種方式正確找到:

require(['jqueryui/button', 'jqueryui/dialog']);

上面這個例子就是獲取scripts/lib/jqueryui/button.js和scripts/lib/jqueryui/dialog.js的例子。另外,因為jqueryui是一個目錄,並不對應一個JS文件,所以又有一個main屬性,這個屬性一般對應這個JS包中的主程序文件。上面的例子中,jqueryui的主程序就在scripts/lib/jqueryui/core.js中。

楔子 – shim

並不是所有的JS模塊都會像jquery和underscore那樣調用define方法定義自己,這樣requirejs就不知道你這個模塊的入口在哪,該通過哪個對象來調用這個模塊,特別是那些早版本的JS模塊,因為那是還沒有define和require的概念。

requirejs.config({

    baseUrl:"scripts/lib",

    shim: {jquery: {deps:[],exportsFn: func, exports:'jQuery',init:func}}

});

雖然模塊沒有使用define方法定義自己,但開發人員應該是知道如何獲取文件中的模塊的,所以,requirejs提供了兩種方式讓開發人員把模塊對象返回給requirejs管理:

  • 在exportsFn或init方法中設置,然后作為返回值;
  • 使用exports設置,比如”a.b.c”,那requirejs就知道通過window.a.b.c可以獲取。

映射 – Map

先來看問題:一些第三方JS插件的依賴關系是事先設定好的,不太好修改依賴模塊的名稱,而如果某個模塊有多個版本或有其他模塊和它同名,則使用上面的配置都無法解決問題。比如path只是解決模塊名稱到路徑的問題,而這個面對的是切換模塊名稱的問題。於是requirejs提出了映射的概念,根據當前腳本的名稱動態修改所依賴模塊的ID,是它指向正確的模塊。

假如在你的硬盤下有以下幾個模塊:

  • foo1.0.js
  • foo1.2.js
  • some/newmodule.js
  • some/oldmodule.js

在newmodule.js和oldmodule.js中都有require(‘foo’)調用,要解決沖突只需要這樣配置即可:

requirejs.config({

    map: {

        'some/newmodule':{

            'foo': 'foo1.2'

        },

        'some/oldmodule':{

            'foo':'foo1.0'

        }

    }

});

主程序入口data-main

<script data-main="scripts/app.js"src="../require.js"></script>

不管頁面上有多少個script元素有data-main屬性,requirejs只認最后一個script元素的data-main屬性,忽略其他script元素的data-main屬性。

Requirejs獲取data-main屬性之后,並沒有立即執行data-main指定的腳本文件(因為這個腳本文件可能還依賴了其他模塊),而是把它作為了一個被依賴的模塊,加入到第一個context的依賴數組中。比如下面這種情況就是把scripts/app這個模塊加到一個名叫linus的context中:

<script type="text/javascript">

    requirejs={

        context: 'linus',

        baseUrl:"./",

        skipDataMain: false

    };

</script>

<script data-main="scripts/app.js"src="../require.js"></script>

全局配置

忽略script元素的data-main

在瀏覽器中,有一個選項叫skipDataMain,可以讓requirejs忽略script元素的data-main。在默認情況下,requirejs成功加載之后,會立馬查找頁面上所有script元素,並且把最后一個有data-main屬性的script元素的data-main最為主程序入口。

<script>requirejs={skipDataMain:true}</script>

<scriptdata-main="scripts/app.js"src="../require.js"></script>

模塊定義 – define(name, deps, callback)

你會發現define方法沒有指定context名稱,這是因為define方法只調用於被依賴的模塊中,而require方法已經為依賴的模塊指定了context名稱,所以,這個模塊被哪個context需要,它就屬於那一個context。

參數name是模塊的名稱,deps是該模塊所依賴的其他模塊的名稱,callback一般返回該模塊的實際可被使用對象。比如jQuery的模塊定義回調函數返回的就是jQuery對象。

Error

加載Error

這種error就是瀏覽器自帶的Error對象,只不過requirejs給它附加了其他屬性。

  • message的格式為:msg + '\nhttp://requirejs.org/docs/errors.html#' + id。
  • error.requireType就是就是message后面的id;
  • error.requireModules一般指需要加載卻沒加載成功的模塊名稱;
  • error.originalError是指發生其他錯誤導致模塊加載失敗的原始error對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM