1. 程式人生 > >require.js使用心得

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

),以實現諸如首先指定了從CDN中載入,一旦CDN載入失敗則從本地位置中載入這類的機制。

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.