HTML5工程
本工程包括工程化管理模块、框架管理、业务实现,涉及到技术主要就是javascript、html、css,工程化主要依赖于:Nodejs、Grunt、Bower等。
前端工程化
我们一般的概念里面,只有Java代码需要进行编译、打包、发布,其实更加需要这些自动化的开发步骤;这里所谓工程化,就是通过现有前端技术对我们的前端代码,实现编译、打包、发布、框架和组件的版本维护,实现自动化、获得多端开发能力。
工程化主要是基于NodeJS,主要的依赖的框架结构如下:
工程环境:NodeJS
项目管理:NPM 项目js版本包的管理,GRUNT 项目构建。
前端框架:Angularjs
框架管理:Bower
构建工具:GRUNT("grunt": "^0.4.5")
页面刷新:connect-livereload、grunt-contrib-watch
版本控制:Git 、grunt-bump、grunt-changelog
插件集合:grunt-contrib-clean 、grunt-contrib-concat、grunt-contrib-copy、grunt-recess、grunt-contrib-uglify,这里包含js、css文件的整理、压缩、打包。
语法检测:grunt-contrib-jshint
本地服务器:http-server
测试框架:Karma + Jasmine
项目创建,建立基本目录结构
gtx.alias("jshint",['jshint:srcjs']);
gtx.alias('servers', ['connect:server','watch']);
gtx.alias('server', ['connect:server']);
gtx.alias('build:apps',[
        'clean:apps',
        'copy:libs',
        'copy:apps',
        'useminPrepare',
        'htmlmin',
        'recess:apps',
        'concat:apps',
        'uglify:apps',
        'usemin',
        'clean:tmp'
]);
gtx.alias('release', ['bower-install-simple', 'bump-commit']);
gtx.alias('release-patch', ['bump-only:patch', 'release']);
gtx.alias('release-minor', ['bump-only:minor', 'release']);
gtx.alias('release-major', ['bump-only:major', 'release']);
gtx.alias('prerelease', ['bump-only:prerelease', 'release']);
gtx.alias('deploy-staging', ['ssh_deploy:staging']);
// 本地启动服务和动态刷新(修改密码后不用刷新页面)
> grunt servers
// 本地启动服务
> grunt connect:server  
// 检查JavaScript的语法检查
> grunt jshint
// 组件版本控制打包需要使用的组件。
> grunt copy:libs
// 复制应用到指定目录
> grunt copy:apps
// 压缩html代码和替换index.html代码块。
> grunt useminPrepare
> grunt htmlmin
> grunt usemin
// 整合css文件到app.min.css
> grunt recess:apps
// 合并index.html的js到app.src.js
> grunt concat:apps
// 压缩app.src.js到app.min.js
> grunt uglify:apps
// 打包整个应用
> grunt build:apps
// 提交并进行版本号控制
// 补丁提交 0.0.1
> grunt release-patch
// 中端提交 0.1.0
> grunt release-minor
// 版本提交 1.0.0
> grunt relasse-major

| 目录或文件 | 解释说明 | 
|---|---|
| libs | 组件目录(从bower_components目录同步。) | 
| src | 源码目录 | 
| apps | 整合部署目录 | 
| grunt | 构建脚本目录 | 
| GruntFile.js | 构建工程组件 | 
| package.json | 构建工程组件 | 
| bower.json | 组件版本控制 | 
| bower_components | 版本控制自动生成,组件集合 | 
| node_components | 构建自动生成,构建框架 | 
| readme.txt | 初始化等说明 | 
| update.txt | 发布版本说明 | 
1.整理第三方框架,并整合到bower.js ,实现版本控制。
2.构建脚本:GruntFile.js package.json。
3.构建Grunt插件,工程化打包流程。
4.整理构建流程。
5.设计src的文件目录。
6.设计基本AngularJs结构。
安装 node.js
brew install node
打开根目录执行一下命令
npm install -g grunt-cli
npm install
npm install -g bower
bower install
grunt build:apps
grunt servers
前端结构约定
SRC目录约定

| 目录或文件 | 约定说明 | 
|---|---|
| css | 自主设计的样式表单。 | 
| I10n | 国际化目录。 | 
| images | 系统中使用的图片。 | 
| js | 业务代码。 | 
| tpl | 模版代码。 | 
| index.html | 项目总的入口。 | 
JS目录约定

| 目录或文件 | 约定说明 | 
|---|---|
| app | 目录:项目公共模块。 | 
| banniu | 目录: 班牛业务代码。 | 
| common | 目录:公共控制器。 | 
| directives | 目录:指令。 | 
| filters | 目录:筛选器。 | 
| salecrm | 目录: 销售CRM业务代码。 | 
| services | 目录:资源配置目录。 | 
| app.js | 应用启动加载模块。 | 
| config.js | 应用基础配置和静态常量。 | 
| config.lazyload.js | 准备延时加载的组件。 | 
| config.router.js | 路由配置。 | 
| config.session.js | 拦截器。 | 
| main.js | 应用初始化配置。 | 

在业务目录中添加相应的模块代码。每一个模块对应一个目录。
前端编码约定
命名和注释约定
(https://shimo.im/doc/bKCrIoqmEWw1CV7L)
延时加载
延时加载组件,就是在使用时加载组件。在config.lazyload.js中引入所有需要使用的组件。
有两种使用方式:
1.在路由中加载
resolve: load(['atwho','simditor','js/salecrm/tag/tag.js','ui.select'])
2.指令加载
ui-jq="atwho"
路由配置
这里路由是两级,根据情况,我们可以分成三级。通过路由来分解代码的耦合和重复。
.state('salecrm', {
        abstract: true,
        url: '/salecrm',
        templateUrl: layout_salecrm
})
.state('salecrm.customer_my', {
        url: '/my/customer/:customerId',
        views: {
                "header@salecrm" : {
                        templateUrl: "tpl/salecrm/customer/customer_my_header.html"
                },
                "container@salecrm" : {
                        templateUrl: 'tpl/salecrm/customer/customer.html',
                        resolve: load(['atwho','simditor','js/salecrm/customer/customer_my.js', 'js/salecrm/customer/customer_show.js', 'ui.select']),
                        controller: 'CustomerMyCtrl'
                }
        }
})
资源配置
一个对象或RESTFul资源配置一个资源对象。
app.factory('Linkmans', ['$resource','rserv',
    function($resource,rserv){
        var opts = rserv.operates(false);
        opts.checkMobile = {
          method: 'POST',
          isArray: false,
          url: rserv.baseUrl + '/customerLinkman/:mobile/check'
        };
        opts.doubleCall = {
            method: 'POST',
            isArray: false,
            url: rserv.baseUrl + '/customerLinkman/doubleCall'
        };
        return $resource(rserv.url('customerLinkman'), {id: '@id', mobile:'@mobile'}, opts);
    }]
);
app.factory('Visits', ['$resource','rserv',
    function($resource,rserv){
        return $resource(rserv.url('customerVisit'), {id: '@id'}, rserv.operates(false));
    }]
);
前端控制器
注意事项
* 调用资源的方式统一。
* 命名规范。
  * 控制器命名:      模块名+Ctrl
    * 初始化列表命名:  set+模型名
    *    查询:                     search+模型名
    * 新建:                     new+模块名
    * 编辑:                     edit+模块名
    * 查看:                     show+模块名
    * 保存/修改:         save+模块名
* 代码注释
    * 控制器说明
    * 复杂的算法和方法说明(包括方法、指令、服务、筛选器)
模版说明如下:
/**
 * 系统标签(包含子标签),比如:客户成熟度、客户类型。
 * Created by mifeng on 2017/3/9.
 */
app.controller('TagCtrl', ['$scope','$modal','$log','$aside','$stateParams','$http','toaster','Tags','svThrow','Linkmans', function($scope,$modal,$log,$aside,$stateParams,$http,toaster,Tags,svThrow,Linkmans) {
    // 标签ID(必传字段)
    $scope.tagId = $stateParams.tagId;
    // 搜索条件
    $scope.conditions = {
        pageNum: 1,
        pageSize: 10,
        tagId: $scope.tagId,
        tagType: null,
        tagName: null
    };
    // 加载分页信息和数据
    $scope.setTags = function() {
      // 由ui-paginate调用改变pageNum。
      if($scope.result) {
        $scope.conditions.pageNum = $scope.result.pageNum;
      }
            // 资源查询列表
      Tags.query($scope.conditions, function(result){
        $scope.result = result;
      });
    }
    // 搜索查询
    $scope.searchTags = function(tagType){
        if($scope.conditions.tagName == "") {
          $scope.conditions.tagName = null;
        }
        if (tagType) {
          $scope.conditions.tagType = tagType;
          $scope.setTags();
        }
        $scope.setTags();
    }
    // 初次加载
    $scope.setTags();
    // 新建标签
    $scope.newTag = function() {
      $scope.tag = new Tags({tagType: 1,status: 0, tagId: $scope.tagId });
      angular.element("#tag_modal").click();
    }
    // 新建子标签
    $scope.newSubTag = function(tag) {
      $scope.tag = new Tags({tagType: 1,status: 0,tagId: tag ? tag.id : 0 });
      angular.element("#tag_modal").click();
    }
    // 编辑标签(包括子标签)
    $scope.editTag = function(tag) {
      $scope.tag = tag;
      angular.element("#tag_modal").click();
    }
    // 新增或修改标签
    $scope.saveTag = function() {
      if($scope.tag.id) {
        $scope.uTag = new Tags($scope.tag);
        $scope.uTag.$update(
          function(result) {
            $scope.tag = $scope.uTag;
            angular.element("#tag_modal").click();
            toaster.pop('success','修改成功。');
          }
        );
      }else {
        $scope.tag.$save(
          function(result) {
            angular.element("#tag_modal").click();
            $scope.setTags();
            toaster.pop('success','添加成功。');
          },svThrow.throwError
        );
      }
    }
    // 查看标签
    var tagAside = $aside({    //侧栏——详情
        templateUrl: 'tpl/salecrm/tag/tag_show.html',
        controller: 'TagShowCtrl',
        show: false
    });
    $scope.showTag = function(tag) {
        console.log("显示详情");
        Tags.show({id: tag.id},function(result) {
          console.log(result);
        });
        tagAside.$scope.tag = tag;
        tagAside.show();
        tagAside.$promise.then(function () {
        });
    }
}]);
前端发布方案
1)通过Nginx的反向代理。
2)WEB工程发布后,HTML工程代码整合到WEB工程中。