2015前端总结:QBao前端架构小结
"自动化构建"是区分二线前端团队和一流前端团队的重要因素,只有工程化前端过程,才能让前端程序猿摆脱手工作坊式的开发,升级为前端工程师。
2015年的架构主要围绕"自动化构建"展开。我们选用了Gulp作为前端构建系统,串起标准构建过程:
- JS静态代码审查
- JS连接压缩混淆
- CSS连接压缩混淆
- 雪碧图生成,图片压缩
- 文件Hash值生成
- CDN地址生成
这样,就可以将_日常工作_交给机器去做,甚至开发者无需懂得细节也可以应用先进的前端优化技巧。
事实上,这个列表还可以扩充:
- SASS预处理
- CoffeeScript预处理
- 单元测试
- 集成测试
- UI测试
- 接口文档生成
完全可以满足团队进化的需求。
基于构建系统,我们创建了纯前端的组件框架:QBao-Web
在Gulp中,我们加入了两个定制的任务:
- Template任务 将静态组件嵌入到页面中相应的位置,同时引入相应的JS和CSS
- Handlebar任务 所有写在template目录下的模板文件,自动生成template.js,页面可以直接使用
所以说,2015年我们的前端框架,是围绕着"自动化构建"建立的。
qbao-web2.0
概述
前后端分离是这两年很热门的提法。
随着HTML5/CSS3广泛推广,前端框架不断进化,前端开发越来越专业化,自然想要摆脱后端的束缚,NodeJS的出现,也让前端工程师看到更多的可能。同时后端工程师也希望更多地专注于后台业务逻辑,而不是页面性能或是多浏览器适配。所以前后端分离,就是让“专业的人做专业的事”。
前后端分离不是一定要采用NodeJS做服务器,也不是一定要采用AngularJS,相反的,盲目引入新技术很容易让项目陷入困境,让开发人员不知所措,最好能采用一些温和的方式一步步来。
方案
-
采用Ajax模式,应用服务器只提供数据,由静态服务器或CDN承载HTML/CSS/JS文件,使用JS进行Ajax请求数据,动态生成最终页面。这里对网站架构师提出了新的要求,需要定义完备的Restful接口。
-
不使用AngularJS重型前端框架,只使用前端工程师最熟悉的jQuery类库,同时引用HandlerBars模板语言辅助生成页面。
-
模块划分上使用NodeJS进行html暴力插入,可以考虑换成Jade模板语言。
-
只做多页面方案,尽量不做页面内跳转,避免引入前端路由。
详解
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- build:css ../components/components.min.css -->
<!-- components:css -->
<!-- endinject -->
<link rel="stylesheet" href="../common/styles/base.css">
<link rel="stylesheet" href="styles/index.css">
</head>
<body>
@@include('../components/site-top/site-top.html')
@@include('../components/site-header/site-header.html')
<div id="banner" class="container">
<div class="main container clearfix">
<div id="auction-list" class="list">
<div class="right-side">...
...
@@include('../components/site-footer/site-footer.html')
<script id="banner-template" type="text/x-handlebars-template">
{ {#each list} }
<div>
<a href="{ {target} }">
<img src="{ {path} }" />
</a>
{ {/each} }
</script>
<script id="auction-list-template" type="text/x-handlebars-template">
<ul>
{ {#each list} }
<li class="item">
<p class="name">{ {product.name} }</p>
<section class="content">
<img class="picture" src="{ {picture} }" />
<div class="price-bar">
<div class="value">
<img src="images/rmb-icon-gray.png" />
<p class="number">{ {value} }</p>
<p class="note">市场价</p>
...
<footer>
<ul>
<li>
<p><span>{ {register} }</span>人</p>
<p class="note">报名人数</p>
</li>
...
</ul>
</footer>
</li>
{ {/each} }
</ul>
</script>
<script src="../bower_components/jquery/dist/jquery.min.js"></script>
<script src="../bower_components/handlebars/handlebars.min.js"></script>
<!-- components:js -->
<!-- endinject -->
<script src="scripts/index.js"></script>
</body>
</html>
这是一个很典型的页面,雷拍列表。
-
公用元素
由于没有后台服务器为我们组装页面,我在这里采用了自定义语法来引入公共控件,比如页头和页尾。
@@include('../components/site-top/site-top.html') @@include('../components/site-footer/site-footer.html')
这不是标准的html语法,所以这个页面也无法直接在浏览器中加载,需要使用NodeJS预编译成HTML发布。
这里的NodeJS作为编译工具出现,而不是服务器,理论上也可以使用NodeJS原配的Jade模板语言来完成,不过需要引入一个不那么像HTML语法的生成器,不是很爽。
有了这种设计,我们就不需要将公用元素在每个页面中重复,可以最大化地复用,也能方便地统一修改。
-
动态元素
动态元素由HandlerBars模板生成,比如这个Banner:
```
<script id="banner-template" type="text/x-handlebars-template">
{ {#each list} }
<div>
<a href="{ {target} }">
<img src="{ {path} }" />
</a>
{ {/each} }
</script>
```
选用HandlerBars,一是因为它的语法很接近HTML,二是因为它非常快。
数据获取通过jQuery的ajax函数:
```
var loadBanner = function() {
var source = $('#banner-template').html();
var template = Handlebars.compile(source);
$.get('http://localhost:3000/banners/54c98efa2d2c4b7517e8c63f').done(function(resp) {
var urlList = $.map(resp.pictures, function(picture) {
picture.path = 'http://localhost:3000/uploads/' + picture.name;
return picture;
});
var html = template({
list: urlList
});
$('#banner').append(html);
});
};
```
3. 目录结构
![](https://cdn.ydr.me/res/20151230113733504287782509)
模块化地组织目录结构,可以方便地分人员开发和负责。
* 顶级目录
* app 存放页面模板
* dist 存放发布的最终页面,由自动化构建系统生成
* test 自动化测试用例
* 二级目录
* components 公共模块,页头、页尾、通用控件等
* common 公共资源,如网站的基础css
* 其他 各子模块,如雷拍、宝筹、任务中心等
* 三级目录
* index.tpl.html 子模块的首页模板,配有同名的js和css文件
* detail.tpl.html 子模块的其他页面模板,配有同名的js和css文件
4. 自动化构建
![](https://cdn.ydr.me/res/20151230113715238021993516)
使用Gulp搭建自动化构建环境,除了前述公用元素插入,自动化构建还支持:
* 静态代码检查
* JS和CSS文件的连接和压缩
* 图片的压缩优化
* 雪碧图和相应的CSS生成
* 浏览器自动重载等
细节在之后统一写一篇专题介绍。
5. 改进点
* 需要考虑根据团队接受能力引入SASS,提升CSS架构能力
* 需要考虑把HandleBars模板预编译成JS再发布,可以大幅提升渲染速度
小结
优点
- 最容易落地的技术方案,避开AngularJS的学习曲线,只需要学习HandlerBars模板语言
- 简单粗暴的前后端分离,为之后的架构转型做准备,之后的进化就是前后端分别进行的了
缺点
- 首页加载速度不如服务器渲染,用户会看到数据加载过程
qbao-web2.1
随着项目越来越大,页面越来越多,web2.0的构建系统慢慢吃力起来,动辄要10分钟才可以构建一遍,而且要上传到构建服务器构建,成功后再从服务器上下载下来,构建周期太长,已经违反了架构的初衷。
针对这一情况,我们推出了web2.1框架,主要优化如下:
- 加速构建过程,在开发者本机就可以一键构建,自动生成Dist和CDN文件,并且在半分钟内构建完毕;
- 使用Reset.css替换Normalize.css;
- 控件支持按项目增删配置,而不是默认全部包含;
优化仍然是围绕着"自动化构建"开展的。
qbao-mobile
mobile的目录结构和web2.0是一样的,意味着构建过程也是一样的,主要区别如下:
- 使用HTML5 Template for Mobile作为模板
- 使用Zepto替换jQuery
- 使用FastClick加速按键响应
- 使用JS控制页面宽度为640px,开发时只要将PSD转换为640宽度,然后量出来是多少就可以写多少,非常方便
qbao-mobile2.1
mobile2.1对于mobile的改变主要也是构建系统的优化:
- 优化构建系统,支持开发者本机构建,支持一键构建,半分钟内完成;
- 使用Reset.css替换Normalize.css;
- 使用弹性布局,开发者将PSD设为640宽度,然后宽度使用%布局,高度使用rem(如:32px转化为.32rem)
QBao-Admin架构
QBao-Web和QBao-Mobile的主要目的是规范化前端开发过程,同时推动前后端分离的工作模式,而QBao-Admin更加关注前端框架后续的发展,尝试了很多新的第三方类库和先进的理念。
如图所示,分层管理、控件抽象、业务分离,QBao-Admin展现出来一个现代的前端架构应有的特性,将一些本来是后端的逻辑前移,让后端更加专注于业务,让前端处理路由、渲染,各司其职,各取所长。
在QBao-Admin中我们使用ReactJS作为展示框架,使用Reflux的单向数据流控制业务逻辑,使用Webpack作为打包工具。
这套方案是后述 QBao-H5App 和 QBao-Universal 框架的基础。