作者:Lin Xu
摘要
WebRex是eBay开源的Java项目,集成了很多前端开发的优化技术。与同类项目Wro4j和Jawr提供的静态优化不同,WebRex提供了动态优化。它使用定制tag和相对路径来操作管理web应用程序的静态资源。它为eBay这样的大型网站提供了一种有效的资源聚合模式。在eBay内部,WebRex作为基础平台架构的一部分,为web应用程序开发人员自动处理前端优化工作,在eBay的绝大多数应用程序中被广泛使用。
为什么我们需要WebRex
首先,通常静态资源优化器使用一个配置文件来管理整个项目的所有静态资源。开发人员需要
1. 列出很多资源文件名和聚合文件(aggregation)名
2. 在jsp文件里使用聚合文件名。
以wro4j为例,开发人员需要在下面的wro.xml里定义很多聚合(Wro4j <group> ),
然后在jsp里面使用这个聚合。对于大型项目,这种配置文件的维护并不容易。随着时间的推移,项目变得越来越繁杂,配置文件也变得越来越繁杂,维护起来变得非常困难。而且,如果要支持项目本地化,有些应用程序的聚合多达上百万。开发人员不知道哪些文件需要被删除,哪些需要被更新,以及各个聚合的使用情况,由此产生很多页面功能错误以及性能问题。WebRex可以很好的解决上述问题。使用WebRex,开发人员不需要维护复杂的配置文件,也不需要查找记住那些聚合,直接使用资源文件即可。
如果一些资源有更新或者不再被使用,这些资源就会被自动在聚合中更新或者从聚合中删除,而且在发送请求响应之前,WebRex会自动删除(Dedup)页面中使用的重复资源,以此来减少page weight,加快页面载入速度。
其次,WebRex 实现了resource bundle 功能,这个功能粗略看有点类似静态聚合,但实际上它也是动态的,主要功能包括
i. 提供了整个站点内(比如ebay.com)所有页面共享资源的功能,利用了浏览器缓存来提高页面加载速度。
ii. 开发人员只需要在页面上指定目标slot。
iii. Resourcebundle 可以被定义在一个单独的被共享的共享库里,这样所有的applications都可以使用它。
iv. 如果要修改目标slot的资源聚合顺序,开发人员只需要在配置文件里做一次性修改。
再次, WebRex 既支持 http 也支持https,在支持本地化L10N方面也非常灵活。在eBay内部,我们支持很多Locales,如果特定Locale有特定资源,开发人员只需要把这些资源放到Locale对应的文件夹(比如META-INF/resources/de_DE/sample/sample1.js),WebRex做聚合时会自动找到目标Locale的特定资源,用户访问页面时,如果locale是en_US,找到META-INF/resources/sample/sample1.js进行聚合,如果locale 是de_DE,找到META-INF/resources/de_DE/sample/sample1.js进行聚合。
另外,WebRex的开发中过程考虑和吸纳了很多前端开发的前沿技术,包括业界知名的Yahoo的网页加速最佳实践(best practices of speeding upwebsites)。
当然,WebRex是可扩展的,开发人员可以根据自己的项目需要进行扩展,比如上传聚合资源到资源服务器,对于大型项目,开发人员需要扩展使用资源服务器(我们会在以后的文章中重点阐述这部分)。
主要概念
* 聚合(Aggregation)
聚合多个资源文件到一个单独的文件里,这样可以很大程度地减少下载资源的round-trip 的数目,进而提高页面加载速度。
* 本地资源和共享资源(Local Resource and Shared/Library Resource)
本地资源Local Resource: 所有本地web项目里面的资源文件被归为 local resource.
共享资源Shared(Library) Resource: 所有在共享jar包的META-INF/resources 里的资源文件称为 shared(Library) resource.
* 资源根目录(Resource Base)
它指定了WebRex从哪个文件夹开始寻找本地资源,是可配的。
对本地资源,缺省的resource base 是 <webRoot>/resources.
对共享资源,缺省的resource base 是 META-INF/resources
WebRex首先从本地resource base开始寻找资源,如果没有找到,就会继续从共享资源的resource base寻找。
* 资源路径(Literal Path)
它指的是相对于资源根目录resource base的相对路径,被用来访问资源。
* 占位符(Slot)
占位符用来放置和调整聚合资源在页面上的位置. 开发人员可以定义占位符(使用slot tag res:jsSlot or res:cssSlot) ,用来设置resource tag 的target属性的值。
主要功能
* 通过resource tag引用资源
例如,为了使用<webRoot>/resources/css/comp.css,我们需要写如下代码,
<res:useCssvalue="/css/comp.css" target=”head-css”/>
<res:useCss> resource tag 指定CSS resource type
"/css/comp.css" 指定资源路径
“head-css”是占位符
在下图里,资源samples1.js和sample2.js被聚合到”page-js”这个占位符,这两个文件会被作为一个聚合文件通过一个http/https请求下载。
* 通过 JAVA API引用资源
例如,
1) 取得聚合结果的URL
List<IResource>iResources = new ArrayList<IResource>();
//Createresource
iResources.add(ResourceFactory.createResource("/tests/jsTest_sample3.js"));
iResources.add(ResourceFactory.createResource("/js/test1.js"));
//Try toget aggregation resource url with current context
Stringurl = ResourceFactory.createAggregatedResource(iResources)
.getUrl(ResourceRuntimeContext.ctx().getResourceContext());
2) 向页面上指定占位符加入资源
// GetSample1 JS
IResourceresource = ResourceFactory.createResource("/Sample1.js");
//Register resource in "page-js" slot
ResourceAggregatoraggregator = ResourceRuntimeContext.ctx().getResourceAggregator();
aggregator.registerResource("page-js",resource);
* 删除(dedup) Ajax response里面的重复资源
例如,在主页面jsp上,有一页面组件被某个js初始化了,随后一个ajax request又下载了这个js文件,这样初始化的代码会被再次执行,引起页面出错。
为了解决上面的问题,我们需要删除被主页面和ajax request都下载的重复资源,实现步骤主要包括,
1) 在主页面生成一个unique dedup "token"。
2) 把生成的token作为ajax request的参数。
3) 把token放在resource context里面。
以上步骤的详细代码放在WebRex Github的 sample 项目里。
* Resource Bundle
例如,开发人员认为JQuery.js 和initialize.js 应该被合并到一个文件里,因为大多数页面同时需要这两个文件,那么开发人员可以编辑/WEB-INF/webrex/resource_bundles.xml
添加以下配置,
<bundles>
<bundle id="common-js">
<resourcepath="/js/thirdparty/jquery/JQuery.js" />
<resourcepath="/js/common/initialize.js" />
</bundle>
</bundles>
在panel.jsp
file, 引用 bundle common-js.
JSP code:
<body>
...
<res:bundleid="common-js"></res:bundle>
...
</body>
页面输出output,
<body>
...
<script src="/ressvr/v/tmj5hmooge5n1b4ioh3igyoymin.js?debug=true&showRaw=true"type="text/javascript"></script>
...
</body>
在上面的output里,Jquery.js 和Initialize.js被聚合到一个slot,这个slot就是在JSP里面<res:bundleid="common-js"></res:bundle>所在的位置。
WebRex主要工作原理
1) 当JSP页面执行时,WebRex 会根据当前页面使用的resource tag构建一个usage model。
2) WebRex为每个resource tag和slot tag生成一个resource marker 比如 ${MARKER:css}
3) 页面render完成后,resource usage model也构建结束,不同slot的聚合也生成了。
4) JSP执行后,resource RequestFilter 会处理HTTP response,扫描输出HTML里面所有的marker,同时用最终聚合结果替换marker.
支持的资源类型
https://github.com/eBay/WebRex/blob/master/WebRex/src/main/resources/com/ebayopensource/webrex/resource/mimetypes.properties
Github 以及更多信息
https://github.com/eBay/WebRex
讨论社区Community
https://groups.google.com/forum/#!forum/webrex