requirejs好久不見奥吩。
技術(shù)不存在過時一說,合適就好构拳。
RequireJS就是一個工具庫咆爽,它的模塊管理遵守[AMD規(guī)范],通過define方法置森,將代碼定義為模塊斗埂;通過require方法,實現(xiàn)代碼的模塊加載凫海。
最近因為一個老的項目要做優(yōu)化呛凶,該項目用requirejs做的模塊加載,說起來
這個項目架子還是甚為奇行贪。
MVC------------M和C用的是backbone,V選擇了React,而且還引入了 JSX漾稀。
代碼中使用了很多的第三方庫,另外所有的UI公共組件都是單一的jsx文件,jsx文件是一個define定義的AMD模塊(但是內(nèi)部使用了React.createElement,沒看到j(luò)sx的語法)建瘫。
經(jīng)過分析崭捍,整體上目前上的優(yōu)化手段有
1, 所有的同步ajax優(yōu)化為異步---代碼中竟然很多使用了(無特殊情況)同步的ajax請求
2啰脚, 首頁資源加載方式優(yōu)化----(首頁document.write阻塞的方式殷蛇,加載一些資源文件)
3, 全局加載資源優(yōu)化橄浓,對冗余資源去冗
4粒梦, 靜態(tài)資源分域伺服提供加載,優(yōu)化加載性能.
5贮配, 前后端分離
6谍倦, 靜態(tài)資源開啟gizp壓縮優(yōu)化,調(diào)解最小文件大小為適當(dāng)值泪勒。
以上的手段優(yōu)化后昼蛀,在其中一個復(fù)雜的多表單共存的頁面宴猾,該頁面在第一次打開時拉取.jsx得請求數(shù)竟然到達(dá)100多個,嚴(yán)重影響該頁面性能叼旋。
經(jīng)過分析仇哆,還記得前文我們說的每個UI組件都是一個jsx文件,在當(dāng)前這個復(fù)雜的頁面夫植,基本上80%以上的組件都會用上兽间,所以該頁面打開時订雾,會通過XHR去獲取所有的jsx文件,理解AMD模塊的化,應(yīng)該理解帐姻,必須 在jsx文件獲取后靠抑,才會執(zhí)行回調(diào)函數(shù)的邏輯篮奄。因此改頁面所需要的jsx必須要適當(dāng)?shù)暮喜ⅰ?/p>
define(["react","jsx!js/component",,"jsx!js/multi"],function(React,Component,Multi){
//code
require(["jsx!js/component1",,"jsx!js/multi2"],function(Component1,Component2){
//code
....
})
....
})
那怎么合并呢商叹?
肯定不是簡單的把文件合起來就好,必須做好他的依賴管理饿凛,否則當(dāng)組件間存在依賴時狞玛,就會出問題,找不到某個模塊報undefined錯誤涧窒。
因此回過頭心肪,我們再一起看看requirejs
模塊定義
無依賴的模塊
define(function () {
return {
method1: function() {},
method2: function() {},
};
});
有依賴的模塊
define(['module1', 'module2'], function(m1, m2) {
...
});
模塊調(diào)用
1.require(['foo', 'bar'], function ( foo, bar ) {
foo.doSomething();
});
2. define內(nèi)注入require
define(function ( require ) {
var isReady = false, foobar;
require(['foo', 'bar'], function (foo, bar) {
isReady = true;
foobar = foo() + bar();
});
return {
isReady: isReady,
foobar: foobar
};
});
3. 異步
define(['lib/Deferred'], function( Deferred ){
var defer = new Deferred();
require(['lib/templates/?index.html','lib/data/?stats'],
function( template, data ){
defer.resolve({ template: template, data:data });
}
);
return defer.promise();
});
錯誤處理
requirejs.config({
enforceDefine: true,
paths: {
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min'
}
});
//Later
require(['jquery'], function ($) {
}, function (err) {
var failedId = err.requireModules && err.requireModules[0];
if (failedId === 'jquery') {
requirejs.undef(failedId);
requirejs.config({
paths: {
jquery: 'local/jquery'
}
});
require(['jquery'], function () {});
} else {
}
});
配置
require.config({
paths: {
"backbone": "vendor/backbone",
"underscore": "vendor/underscore"
},
shim: {
"backbone": {
deps: [ "underscore" ],
exports: "Backbone"
},
"underscore": {
exports: "_"
}
}
});
看到這里,該文件合并了吧纠吴,對~~~~
r.js出場了
npm install -g requirejs
node r.js -o <build.js>
build.js文件內(nèi)容
({
appDir: './',
baseUrl: './js',
dir: './dist',
modules: [
{
name: 'main'
}
],
fileExclusionRegExp: /^(r|build)\.js$/,
optimizeCss: 'standard',
removeCombined: true,
paths: {
jquery: 'lib/jquery',
underscore: 'lib/underscore',
backbone: 'lib/backbone/backbone',
backboneLocalstorage: 'lib/backbone/backbone.localStorage',
text: 'lib/require/text'
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: [
'underscore',
'jquery'
],
exports: 'Backbone'
},
backboneLocalstorage: {
deps: ['backbone'],
exports: 'Store'
}
}
})
appDir:項目目錄硬鞍,相對于參數(shù)文件的位置。
baseUrl:js文件的位置呜象。
dir:輸出目錄膳凝。
modules:一個包含對象的數(shù)組,每個對象就是一個要被優(yōu)化的模塊恭陡。
fileExclusionRegExp:凡是匹配這個正則表達(dá)式的文件名蹬音,都不會被拷貝到輸出目錄。
optimizeCss: 自動壓縮CSS文件休玩,可取的值包括“none”, “standard”,
“standard.keepLines”, “standard.keepComments”,
“standard.keepComments.keepLines”著淆。
removeCombined:如果為true,合并后的原文件將不保留在輸出目錄中拴疤。
paths:各個模塊的相對路徑永部,可以省略js后綴名。
shim:配置依賴性關(guān)系呐矾。如果不是AMD模式定義的苔埋,就用shim指定模塊的依賴
generateSourceMaps:是否要生成source map文件。
最終本項目的的build.js如下
({
appDir:'./',
baseUrl: 'static',
dir: "build",
mainConfigFile:'./static/config.js',
findNestedDependencies: true,
removeCombined:true,
generateSourceMaps:true,
modules: [
{
name: "main"
},
{
name: "admin"
}
]
})
node r.js -o build.js
補(bǔ)充
因為沒有找到方法蜒犯,用r.js去處理jsx文件组橄,所以后來就把jsx文件全部改為js(因為里面并沒有使用 jsx語法荞膘,其實質(zhì)就是js),最終使得可以通過r.js處理玉工。