FED

©FrontEndDev.org
2015 - 2024
web@2.22.0 api@2.20.0

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,相反的,盲目引入新技术很容易让项目陷入困境,让开发人员不知所措,最好能采用一些温和的方式一步步来。

方案

  1. 采用Ajax模式,应用服务器只提供数据,由静态服务器或CDN承载HTML/CSS/JS文件,使用JS进行Ajax请求数据,动态生成最终页面。这里对网站架构师提出了新的要求,需要定义完备的Restful接口。

  2. 不使用AngularJS重型前端框架,只使用前端工程师最熟悉的jQuery类库,同时引用HandlerBars模板语言辅助生成页面。

  3. 模块划分上使用NodeJS进行html暴力插入,可以考虑换成Jade模板语言。

  4. 只做多页面方案,尽量不做页面内跳转,避免引入前端路由。

详解

<!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>

这是一个很典型的页面,雷拍列表。

  1. 公用元素

    由于没有后台服务器为我们组装页面,我在这里采用了自定义语法来引入公共控件,比如页头和页尾。

     @@include('../components/site-top/site-top.html')
     @@include('../components/site-footer/site-footer.html')
    

    这不是标准的html语法,所以这个页面也无法直接在浏览器中加载,需要使用NodeJS预编译成HTML发布。

    这里的NodeJS作为编译工具出现,而不是服务器,理论上也可以使用NodeJS原配的Jade模板语言来完成,不过需要引入一个不那么像HTML语法的生成器,不是很爽。

    有了这种设计,我们就不需要将公用元素在每个页面中重复,可以最大化地复用,也能方便地统一修改。

  2. 动态元素

动态元素由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再发布,可以大幅提升渲染速度

小结

优点

  1. 最容易落地的技术方案,避开AngularJS的学习曲线,只需要学习HandlerBars模板语言
  2. 简单粗暴的前后端分离,为之后的架构转型做准备,之后的进化就是前后端分别进行的了

缺点

  1. 首页加载速度不如服务器渲染,用户会看到数据加载过程

qbao-web2.1

随着项目越来越大,页面越来越多,web2.0的构建系统慢慢吃力起来,动辄要10分钟才可以构建一遍,而且要上传到构建服务器构建,成功后再从服务器上下载下来,构建周期太长,已经违反了架构的初衷。

针对这一情况,我们推出了web2.1框架,主要优化如下:

  1. 加速构建过程,在开发者本机就可以一键构建,自动生成Dist和CDN文件,并且在半分钟内构建完毕;
  2. 使用Reset.css替换Normalize.css;
  3. 控件支持按项目增删配置,而不是默认全部包含;

优化仍然是围绕着"自动化构建"开展的。

qbao-mobile

mobile的目录结构和web2.0是一样的,意味着构建过程也是一样的,主要区别如下:

  1. 使用HTML5 Template for Mobile作为模板
  2. 使用Zepto替换jQuery
  3. 使用FastClick加速按键响应
  4. 使用JS控制页面宽度为640px,开发时只要将PSD转换为640宽度,然后量出来是多少就可以写多少,非常方便

qbao-mobile2.1

mobile2.1对于mobile的改变主要也是构建系统的优化:

  1. 优化构建系统,支持开发者本机构建,支持一键构建,半分钟内完成;
  2. 使用Reset.css替换Normalize.css;
  3. 使用弹性布局,开发者将PSD设为640宽度,然后宽度使用%布局,高度使用rem(如:32px转化为.32rem)

QBao-Admin架构

QBao-Web和QBao-Mobile的主要目的是规范化前端开发过程,同时推动前后端分离的工作模式,而QBao-Admin更加关注前端框架后续的发展,尝试了很多新的第三方类库和先进的理念。

如图所示,分层管理、控件抽象、业务分离,QBao-Admin展现出来一个现代的前端架构应有的特性,将一些本来是后端的逻辑前移,让后端更加专注于业务,让前端处理路由、渲染,各司其职,各取所长。

在QBao-Admin中我们使用ReactJS作为展示框架,使用Reflux的单向数据流控制业务逻辑,使用Webpack作为打包工具。

这套方案是后述 QBao-H5App 和 QBao-Universal 框架的基础。