标签:
受《大公司怎样开发和部署前端代码?》这篇文章的启发,结合自己的项目实践,创建了一套JavaScript文件的版本管理和加载的机制,虽然比较粗糙,但是解决了不少实际的问题。
使用到的主要工具:
Node.js
NPM
grunt和相关插件(grunt-hashmap,grunt-contrib-uglify,自定义的插件)
LAB.js
功能能点:
利用grunt插件hashmap根据JavaScript的文件的内容生成hash码,可做为JavaScript文件名的一部分,有效防止在更改JavaScript文件内容后浏览器缓存的问题。
JSP页面中不再直接引用JavaScript文件,所有的JavaScript文件通过JSON格式的映射文件,由LAB.js根据映射关系负责加载,这样每次修改JavaScript文件后,再次发布时无需修改JSP页面。
开发环境和生成环境的切换。
对JavaScript文件压缩
前端的项目结构:

后端的主要文件:static_file.jsp
<script type="text/javascript" src="${staticroot}/static/js/lib/LAB.min.js"></script>
<script type="text/javascript">
(function() {
$LAB
.script("${staticroot}/static/js/lib/jquery.min.js")
.wait()
.script("${staticroot}/static/js/config/JspJsMapping.js")
.script("${staticroot}/static/js/config/VersionMapping.js").wait()
.script("${staticroot}/static/js/config/AppConfig.js")
.wait(function() {
AppConfig.getScripts(‘<%=request.getServletPath()%>‘, ‘${staticroot}‘);
})
})();
</script>
项目中的JSP文件中如果存在JavaScript文件,则只需引用static_file.jsp文件即可,其余的工作都交给static_file.jsp文件中的JavaScript代码即可。
通过观察static_file.jsp文件可以发现,首先要引用LAB.min.js类库,这是加载JavaScript文件的核心。另外由于项目中每个JSP文件都有对Jquery的引用,所以在此处Jquery文件也有LABjs默认加载。
另外,JspJsMapping.js、VersionMapping.js和AppConfig.js便是整个前端的配置文件,在某个JSP中加载哪些JavaScript文件,加载哪个版本的JavaScript文件,使用生成环境还是测试环境都由这三个配置文件进行管理。
下面分别介绍这三个配置文件:
JspJsMapping.js文件由JspJsMapping.tpl模板文件使用grunt自定义插件生成的,内容如下(部分):
/**
* Created by wanglu on 2014/12/16.
* 生成jsp中使用到的js文件的映射信息(模板)
*/
;(function(window) {
window.JspJsMapping = {
"public1": {
"scripts":[
"lib/spin.min.js",
"lib/iosOverlay.js",
"lib/fastclick.js",
"Utils.js"
]
},
"/WEB-INF/views/acc/about.jsp": {
"scripts":[
"include:public1"
]
},
"/WEB-INF/views/acc/applylist.jsp": {
"scripts":[
"lib/jquery.mobile.custom.min.js",
"lib/AjaxUtil.js",
"lib/iscroll.js",
"lib/iscrollAssist.js",
"PageController.js",
"lib/SessionStorageUtil.js",
"lib/LocalStorageUtil.js",
"include:public1",
{"name": "applylist.js", "wait": true}
]
},
"/WEB-INF/views/acc/favbranches.jsp": {
"scripts":[
"lib/jquery.mobile.custom.min.js",
"lib/AjaxUtil.js",
"lib/iscroll.js",
"lib/iscrollAssist.js",
"PageController.js",
"lib/SessionStorageUtil.js",
"lib/LocalStorageUtil.js",
"include:public1",
{"name": "favbranches.js", "wait": true}
]
},
"/WEB-INF/views/acc/favjobs.jsp": {
"scripts":[
"lib/jquery.mobile.custom.min.js",
"lib/AjaxUtil.js",
"lib/iscroll.js",
"lib/iscrollAssist.js",
"PageController.js",
"lib/SessionStorageUtil.js",
"lib/LocalStorageUtil.js",
"include:public1",
{"name": "favjobs.js", "wait": true}
]
},
"/WEB-INF/views/acc/index.jsp": {
"scripts":[
]
}
}
})(window);
这个文件配置的JSP页面与JavaScript的引用关系。
VersionMapping.js文件由Versionmapping.tpl模板文件使用grunt自定义插件生成,内容如下(部分):
/**
* Created by wanglu on 2014/12/16.
* 生成版本映射信息(模板)
*/
;(function(window) {
window.VersionMapping = {
version: ‘20150403174521‘,
mappings: {
‘CityHelper.js‘: ‘5e4cda‘,
‘DictionaryCache.js‘: ‘96ecdf‘,
‘FoodHelper.js‘: ‘ec65b2‘,
‘FunctionHelper.js‘: ‘350065‘,
‘Gruntfile.js‘: ‘f916ad‘,
‘PageController.js‘: ‘b5ed9d‘,
‘SocialHelper.js‘: ‘821373‘,
‘Utils.js‘: ‘cb4ade‘,
‘WorkFuncHelper.js‘: ‘3013b8‘,
‘app.js‘: ‘aecc0b‘,
‘apply.js‘: ‘baa38d‘,
‘applylist.js‘: ‘78be19‘,
‘branch.js‘: ‘388c5e‘,
‘branchjobs.js‘: ‘1fe1ec‘,
‘branchlist.js‘: ‘86d21a‘,
‘favbranches.js‘: ‘d2331a‘,
‘favjobs.js‘: ‘4970e4‘,
‘iscroll_kt.js‘: ‘0dc411‘
}
}
})(window);
这个文件配置的JavaScript文件和其当前的hashcode的映射关系,比如/WEB-INF/views/acc/favjobs.jsp文件引用了PageController.js文件,那么最终在JSP文件中将加载PageController_b5ed9d.js文件,对于一些公用的JavaScript文件,可将其配置如下的格式:
"public1": {
"scripts":[
"lib/spin.min.js",
"lib/iosOverlay.js",
"lib/fastclick.js",
"Utils.js"
]
}
然后在应用JavaScript文件的使用,改变为如下样式:
"/WEB-INF/views/acc/applylist.jsp": {
"scripts":[
"lib/jquery.mobile.custom.min.js",
"lib/AjaxUtil.js",
"lib/iscroll.js",
"lib/iscrollAssist.js",
"PageController.js",
"lib/SessionStorageUtil.js",
"lib/LocalStorageUtil.js",
"include:public1",
{"name": "applylist.js", "wait": true}
]
}
AppConfig.js文件是加载功能的实现,在此文件中使用LABjs,通过JspJsMapping.js和VersionMapping.js两个配置文件为JSP页面加载所需要的JavaScript的文件。内容如下(全部):
;(function($, window){
window.AppConfig = {
// mode: ‘debug‘,
min: true,
log: true,
baseUrl: ‘/static/js/build/‘,
debugUrl: ‘/static/js/‘,
getScripts: function(key, baseUrl) {
var scripts = JspJsMapping[key][‘scripts‘] || [];
var labJsScript = this.getLABScript(baseUrl, scripts);
if (labJsScript !== ‘$LAB‘) {
try {
window.eval(labJsScript + ‘;‘);
} catch(e) {
console && console.error(e);
}
}
},
getLABScript: function(baseUrl, scripts, labJsScript) {
labJsScript = labJsScript || ‘$LAB‘;
for (var sc; scripts && (scripts instanceof Array) && (sc = scripts.shift()); ) {
if (typeof sc === ‘string‘) {
if(sc.indexOf(‘include:‘) === 0) {
var key = sc.substring(sc.indexOf(‘:‘) + 1);
labJsScript = this.getLABScript(baseUrl, JspJsMapping[key][‘scripts‘] || [], labJsScript);
}
else {
var url = AppConfig.getFileName(sc);
labJsScript += ‘.script("‘+ baseUrl + url + ‘")‘;
this.log && console && console.log(‘loadding : ‘ + baseUrl + url);
}
}
else if (typeof sc === ‘object‘) {
var url = AppConfig.getFileName(sc[‘name‘]);
labJsScript += ‘.script("‘+ baseUrl + url + ‘")‘;
if (sc[‘wait‘]) {
labJsScript += ‘.wait()‘;
url = ‘wait ‘ + baseUrl + url;
}
this.log && console && console.log(‘loadding : ‘ + url);
}
}
return labJsScript;
},
getFileName : function(fileName) {
if (!fileName) {
return ‘‘;
}
if (this.mode === ‘debug‘) {
return ( AppConfig.debugUrl || AppConfig.baseUrl) + fileName;
}
else {
return (AppConfig.baseUrl || ‘‘)
+ (this.min ? ‘min/‘ : ‘‘)
+ fileName.substring(0, fileName.lastIndexOf(‘.‘))
+ ‘_‘ + VersionMapping.mappings[fileName] + ‘.js‘;
}
}
};
return window.AppConfig;
})($, window);
此文件中的代码最后生成是类似于$LAB.script(...).script(..)格式的代码字符串,然后用window.eval方式执行,实现JavaScript的代码加载。
在此文件中还可以配置是否开启debug(debug属性)模式,是否加载压缩过(min属性)的JavaScript文件等。由于在浏览器调试JavaScript的时候,压缩过的JavaScript的文件无法阅读,所以才使用min属性控制是否加载压缩过的JavaScript文件。
未压缩的文件放在build文件夹中,压缩过的文件放在build/min文件夹中。
整个机制就是这样,目前写的还不是太详细,后续将继续完善。另外,本方法不是对所有的项目都适用,比如由模块化开发的JavaScript项目,而且代码比较粗糙,只是写出来给有用的朋友一些帮助。
标签:
原文地址:http://my.oschina.net/zero2hero/blog/401293