require.js使用心得
requirejs的基本功能"模組化載入"
1.下載引用require.js
2.html中定義
<head>
<script data-main="js/main" src="js/require.js"></script>
</head>
即將require.js引入,require.js引入後會自動尋找js/main.js
3.在main.js中可以定義require.js的配置檔案,並載入相應模組
4.你將配置作為全域性變數"require"在require.js載入之前進行定義,它會被自動應用
注意: 最好使用 var require = {} 的形式而不是 window.require = {}的形式。後者在IE中執行不正常。
支援的配置項:
baseUrl :所有模組的查詢根路徑。所以上面的示例中,"my/module"的標籤src值是"/another/path/my/module.js"。當載入純.js檔案(依賴字串以/開頭,或者以.js結尾,或者含有協議),不會使用baseUrl。因此a.js及b.js都在包含上述程式碼段的HTML頁面的同目錄下載入。
如未顯式設定baseUrl,則預設值是載入require.js的HTML所處的位置。如果用了data-main屬性,則該路徑就變成baseUrl。
baseUrl可跟require.js頁面處於不同的域下,RequireJS指令碼的載入是跨域的。唯一的限制是使用text! plugins載入文字內容時,這些路徑應跟頁面同域,至少在開發時應這樣。優化工具會將text! plugin資源內聯,因此在使用優化工具之後你可以使用跨域引用text! plugin資源的那些資源。
paths :path對映那些不直接放置於baseUrl下的模組名。設定path時起始位置是相對於baseUrl的,除非該path設定以"/"開頭或含有URL協議(如http:)。在上述的配置下,"some/module"的script標籤src值是"/another/path/some/v1.0/module.js"。
用於模組名的path不應含有.js字尾,因為一個path有可能對映到一個目錄。路徑解析機制會自動在對映模組名到path時新增上.js字尾。在文字模版之類的場景中使用require.toUrl()時它也會新增合適的字尾。
在瀏覽器中執行時,可指定路徑的備選(fallbacks
shim: 為那些沒有使用define()來宣告依賴關係、設定模組的"瀏覽器全域性變數注入"型指令碼做依賴和匯出配置。
下面有個示例,它需要 RequireJS 2.1.0+,並且假定backbone.js、underscore.js 、jquery.js都裝於baseUrl目錄下。如果沒有,則你可能需要為它們設定paths config:
requirejs.config({
//Remember: only use shim config for non-AMD scripts,
//scripts that do not already call define(). The shim
//config will not work correctly if used on AMD scripts,
//in particular, the exports and init config will not
//be triggered, and the deps config will be confusing
//for those cases.
shim: {
'backbone': {
//These script dependencies should be loaded before loading
//backbone.js
deps: ['underscore', 'jquery'],
//Once loaded, use the global 'Backbone' as the
//module value.
exports: 'Backbone'
},
'underscore': {
exports: '_'
},
'foo': {
deps: ['bar'],
exports: 'Foo',
init: function (bar) {
//Using a function allows you to call noConflict for
//libraries that support it, and do other cleanup.
//However, plugins for those libraries may still want
//a global. "this" for the function will be the global
//object. The dependencies will be passed in as
//function arguments. If this function returns a value,
//then that value is used as the module export value
//instead of the object found via the 'exports' string.
//Note: jQuery registers as an AMD module via define(),
//so this will not work for jQuery. See notes section
//below for an approach for jQuery.
return this.Foo.noConflict();
}
}
}
});
//Then, later in a separate file, call it 'MyModel.js', a module is
//defined, specifying 'backbone' as a dependency. RequireJS will use
//the shim config to properly load 'backbone' and give a local
//reference to this module. The global Backbone will still exist on
//the page too.
define(['backbone'], function (Backbone) {
return Backbone.Model.extend({});
});
RequireJS 2.0.*中,shim配置中的"exports"屬性可以是一個函式而不是字串。這種情況下它就起到上述示例中的"init"屬性的功能。 RequireJS 2.1.0+中加入了"init"承接庫載入後的初始工作,以使exports作為字串值被enforceDefine所使用。
那些僅作為jQuery或Backbone的外掛存在而不匯出任何模組變數的"模組"們,shim配置可簡單設定為依賴陣列:
requirejs.config({
shim: {
'jquery.colorize': ['jquery'],
'jquery.scroll': ['jquery'],
'backbone.layoutmanager': ['backbone']
}
});
但請注意,若你想在IE中使用404載入檢測以啟用path備選(fallbacks)或備錯(errbacks),則需要給定一個字串值的exports以使loader能夠檢查出指令碼是否實際載入了(init中的返回值不會用於enforceDefine檢查中):
requirejs.config({
shim: {
'jquery.colorize': {
deps: ['jquery'],
exports: 'jQuery.fn.colorize'
},
'jquery.scroll': {
deps: ['jquery'],
exports: 'jQuery.fn.scroll'
},
'backbone.layoutmanager': {
deps: ['backbone']
exports: 'Backbone.LayoutManager'
}
}
});
"shim"配置的重要注意事項:
-
shim配置僅設定了程式碼的依賴關係,想要實際載入shim指定的或涉及的模組,仍然需要一個常規的require/define呼叫。設定shim本身不會觸發程式碼的載入。
-
請僅使用其他"shim"模組作為shim指令碼的依賴,或那些沒有依賴關係,並且在呼叫define()之前定義了全域性變數(如jQuery或lodash)的AMD庫。否則,如果你使用了一個AMD模組作為一個shim配置模組的依賴,在build之後,AMD模組可能在shim託管程式碼執行之前都不會被執行,這會導致錯誤。終極的解決方案是將所有shim託管程式碼都升級為含有可選的AMD define()呼叫。
"shim"配置的優化器重要注意事項:
-
您應當使用 mainConfigFile build配置項來指定含有shim配置的檔案位置,否則優化器不會知曉shim配置。另一個手段是將shim配置複製到build profile中。
-
不要在一個build中混用CDN載入和shim配置。示例場景,如:你從CDN載入jQuery的同時使用shim配置載入依賴於jQuery的原版Backbone。不要這麼做。您應該在build中將jQuery內聯而不是從CDN載入,否則build中內聯的Backbone會在CDN載入jQuery之前執行。這是因為shim配置僅延時載入到所有的依賴已載入,而不會做任何define的自動裝裹(auto-wrapping)。在build之後,所有依賴都已內聯,shim配置不能延時執行非define()的程式碼。define()的模組可以在build之後與CDN載入程式碼一併工作,因為它們已將自己的程式碼合理地用define裝裹了,在所有的依賴都已載入之前不會執行。因此記住:shim配置僅是個處理非模組(non-modular)程式碼、遺留程式碼的將就手段,如可以應儘量使用define()的模組。
-
對於本地的多檔案build,上述的CDN載入建議仍然適用。任何shim過的指令碼,它們的依賴必須加載於該指令碼執行之前。這意味著要麼直接在含有shim指令碼的build層build它的依賴,要麼先使用require([], function (){})呼叫來載入它的依賴,然後對含有shim指令碼的build層發出一個巢狀的require([])呼叫。
-
如果您使用了uglifyjs來壓縮程式碼,不要將uglify的toplevel選項置為true,或在命令列中不要使用 -mt。 該選項會破壞shim用於找到exports的全域性名稱。
map: 對於給定的模組字首,使用一個不同的模組ID來載入該模組。
該手段對於某些大型專案很重要:如有兩類模組需要使用不同版本的"foo",但它們之間仍需要一定的協同。 在那些基於上下文的多版本實現中很難做到這一點。而且,paths配置僅用於為模組ID設定root paths,而不是為了將一個模組ID對映到另一個。
map示例:
requirejs.config({
map: {
'some/newmodule': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
如果各模組在磁碟上分佈如下:
- foo1.0.js
- foo1.2.js
- some/
- newmodule.js
- oldmodule.js
當“some/newmodule”呼叫了“require('foo')”,它將獲取到foo1.2.js檔案;而當“some/oldmodule”呼叫“`require('foo')”時它將獲取到foo1.0.js。
該特性僅適用於那些呼叫了define()並將其註冊為匿名模組的真正AMD模組指令碼。並且,請在map配置中僅使用絕對模組ID,“../some/thing”之類的相對ID不能工作。
另外在map中支援“*”,意思是“對於所有的模組載入,使用本map配置”。如果還有更細化的map配置,會優先於“*”配置。示例:
requirejs.config({
map: {
'*': {
'foo': 'foo1.2'
},
'some/oldmodule': {
'foo': 'foo1.0'
}
}
});
意思是除了“some/oldmodule”外的所有模組,當要用“foo”時,使用“foo1.2”來替代。對於“some/oldmodule”自己,則使用“foo1.0”。
config:常常需要將配置資訊傳給一個模組。這些配置往往是application級別的資訊,需要一個手段將它們向下傳遞給模組。在RequireJS中,基於requirejs.config()的config配置項來實現。要獲取這些資訊的模組可以載入特殊的依賴“module”,並呼叫module.config()。示例:
requirejs.config({
config: {
'bar': {
size: 'large'
},
'baz': {
color: 'blue'
}
}
});
//bar.js, which uses simplified CJS wrapping:
//http://requirejs.org/docs/whyamd.html#sugar
define(function (require, exports, module) {
//Will be the value 'large'
var size = module.config().size;
});
//baz.js which uses a dependency array,
//it asks for the special module ID, 'module':
//https://github.com/jrburke/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#wiki-magic
define(['module'], function (module) {
//Will be the value 'blue'
var color = module.config().color;
});
若要將config傳給包,將目標設定為包的主模組而不是包ID:
requirejs.config({
//Pass an API key for use in the pixie package's
//main module.
config: {
'pixie/index': {
apiKey: 'XJKDLNS'
}
},
//Set up config for the "pixie" package, whose main
//module is the index.js file in the pixie folder.
packages: [
{
name: 'pixie',
main: 'index'
}
]
});
packages: 從CommonJS包(package)中載入模組。參見從包中載入模組。
nodeIdCompat: 在放棄載入一個指令碼之前等待的秒數。設為0禁用等待超時。預設為7秒。
waitSeconds: 命名一個載入上下文。這允許require.js在同一頁面上載入模組的多個版本,如果每個頂層require呼叫都指定了一個唯一的上下文字串。想要正確地使用,請參考多版本支援一節。
context: 指定要載入的一個依賴陣列。當將require設定為一個config object在載入require.js之前使用時很有用。一旦require.js被定義,這些依賴就已載入。使用deps就像呼叫require([]),但它在loader處理配置完畢之後就立即生效。它並不阻塞其他的require()呼叫,它僅是指定某些模組作為config塊的一部分而非同步載入的手段而已。
deps: 指定要載入的一個依賴陣列。當將require設定為一個config object在載入require.js之前使用時很有用。一旦require.js被定義,這些依賴就已載入。使用deps就像呼叫require([]),但它在loader處理配置完畢之後就立即生效。它並不阻塞其他的require()呼叫,它僅是指定某些模組作為config塊的一部分而非同步載入的手段而已。
callback: 在deps載入完畢後執行的函式。當將require設定為一個config object在載入require.js之前使用時很有用,其作為配置的deps陣列載入完畢後為require指定的函式。
enforceDefine: 如果設定為true,則當一個指令碼不是通過define()定義且不具備可供檢查的shim匯出字串值時,就會丟擲錯誤。參考在IE中捕獲載入錯誤一節。
xhtml: 如果設定為true,則使用document.createElementNS()去建立script元素。
urlArgs: RequireJS獲取資源時附加在URL後面的額外的query引數。作為瀏覽器或伺服器未正確配置時的“cache bust”手段很有用。使用cache bust配置的一個示例:
urlArgs: "bust=" + (new Date()).getTime()
在開發中這很有用,但請記得在部署到生成環境之前移除它。
scriptType: 指定RequireJS將script標籤插入document時所用的type=""值。預設為“text/javascript”。想要啟用Firefox的JavaScript 1.8特性,可使用值“text/javascript;version=1.8”。
skipDataMain: Introduced in RequireJS 2.1.9: If set to true
, skips the data-main attribute scanning done to start module loading. Useful if RequireJS is embedded in a utility library that may interact with other RequireJS library on the page, and the embedded version should not do data-main loading.