Web前端持续集成方案(二)

三、利用Grunt实现项目自动化打包

    Grunt是一款基于node的javascript任务管理器工具。我们的项目使用Grunt实现项目自动化打包,以及后续的持续集成。Grunt如何使用,本文不详细介绍(其实是不会-_-!),详见《【grunt整合版】30分钟学会使用grunt打包前端代码》。

    1、打包思路

        项目从开发态到发布态,需要做哪些事情?一、代码检查,包括代码风格检查、js静态代码检查、单元测试、代码静态分析。二、文件预处理:包括sass转css、seajs模块转换、文件变量宏替换。三、文件拷贝、压缩、合并。所以处理流程也很简单。如下图所示:

Web前端持续集成方案(二)_第1张图片

    2、代码风格检查

        Grunt中代码风格检查插件很多,我们的项目采用的是jscs-dev/grunt-jscs。另外,为了生成代码风格检查报告,还需要aj-dev/jscs-html-reporter报表插件。配置参数如下:

jscs: {
  src: ['script/module/**/*.js', '!script/module/**/tpl/*.js'],
  options: {
    config: '.jscsrc',
    reporter: 'node_modules/jscs-html-reporter/jscs-html-reporter.js',
    reporterOutput: 'report/jscs/index.html'
  }
},

其中,.jscsrc是代码风格规则文件。参考配置如下:

{
    "disallowSpacesInNamedFunctionExpression": {
        "beforeOpeningRoundBrace": true
    },
    "disallowSpacesInFunctionExpression": {
        "beforeOpeningRoundBrace": true
    },
    "disallowSpacesInAnonymousFunctionExpression": {
        "beforeOpeningRoundBrace": true
    },
    "disallowSpacesInFunctionDeclaration": {
        "beforeOpeningRoundBrace": true
    },
    "disallowEmptyBlocks": true,
    "disallowSpacesInsideArrayBrackets": true,
    "disallowSpacesInsideParentheses": true,
    "disallowQuotedKeysInObjects": true,
    "disallowSpaceAfterObjectKeys": true,
    "disallowSpaceAfterPrefixUnaryOperators": true,
    "disallowSpaceBeforePostfixUnaryOperators": true,
    "disallowSpaceBeforeBinaryOperators": [
        ","
    ],
    "disallowMixedSpacesAndTabs": true,
    "disallowTrailingWhitespace": true,
    "disallowTrailingComma": true,
    "disallowYodaConditions": true,
    "disallowKeywords": [ "with" ],
    "disallowMultipleLineBreaks": true,
    "requireSpaceBeforeBlockStatements": true,
    "requireParenthesesAroundIIFE": true,
    "requireSpacesInConditionalExpression": true,
    "requireMultipleVarDecl": "onevar",
    "requireBlocksOnNewline": 1,
    "requireCommaBeforeLineBreak": true,
    "requireSpaceBeforeBinaryOperators": true,
    "requireSpaceAfterBinaryOperators": true,
    "requireCamelCaseOrUpperCaseIdentifiers": true,
    "requireLineFeedAtFileEnd": true,
    "requireCapitalizedConstructors": true,
    "requireDotNotation": true,
    "requireCurlyBraces": [
        "do"
    ],
    "requireSpaceAfterKeywords": [
        "if",
        "else",
        "for",
        "while",
        "do",
        "switch",
        "case",
        "return",
        "try",
        "catch",
        "typeof"
    ],
    "safeContextKeyword": "_this",
    "validateLineBreaks": "LF",
    "validateQuoteMarks": "'",
    "validateIndentation": 2
}

生成报表如下图所示:

Web前端持续集成方案(二)_第2张图片

    3、js代码静态检查

        js代码静态检查使用gruntjs/grunt-contrib-jshint插件。另外,为了生成静态检查报告,还需要adrianpietka/jshint-html-reporter报表插件。参数配置如下:

        其中,.jshintrc是静态检查规则文件。参考配置如下:

{
  "asi"      : true,
  "browser"  : true,
  "eqeqeq"   : false,
  "eqnull"   : true,
  "es3"      : true,
  "expr"     : true,
  "jquery"   : true,
  "qunit"    : true,
  "latedef"  : "nofunc",
  "nonbsp"   : true,
  "strict"   : false,
  "undef"    : true,
  "unused"   : "vars",
  "sub"      : true,
  "multistr" : true,
  "loopfunc" : true
}

        生成报表如下图所示:

Web前端持续集成方案(二)_第3张图片

    4、单元测试

        我们的项目中,单元测试采用qunit。所以需要下载grunt的qunit插件:jquery/qunit。另外,为了能够在jenkins中显示单元测试报告,还需要qunit转junit插件:sbrandwoo/grunt-qunit-junit。参数配置如下:

// 单元测试
qunit: {
  script: ['test/**/*.html']
},
qunit_junit: {
  options: {
    dest: 'report/qunit',
    classNamer: function (moduleName, url) {
      var cn = url.replace(/\.html(.*)$/, '').replace(/[\\|\/]/g, '.');
      var index = cn.lastIndexOf('.');
      cn = cn.substr(index+1);
      return cn;
    },
    testNamer: function (testName, moduleName, url) {
      var tn = url.replace(/\.html(.*)$/, '').replace(/[\\|\/]/g, '.');
      var index = tn.lastIndexOf('.');
      tn = tn.substring(0, index);
      // return moduleName.replace(/[\\|\/]/g, '.').replace(/\s+/g, '_');
      return tn;
    }
  }
},


        生成的报表如下图所示:

Web前端持续集成方案(二)_第4张图片

        点击失败用例,可以查看详情:

Web前端持续集成方案(二)_第5张图片

        单元测试完成后,还要生成覆盖率报告,这一部分内容坑比较多,另写一篇文章详细介绍。

    5、js代码静态分析。

        js代码静态分析需下载插件:es-analysis/plato。参数配件比较简单,如下图所示:

plato: {
  your_task: {
    files: {
      'report/plato': ['script/**/*.js', '!script/**/tpl/*.js']
    }
  }
}

        生成报表如下图所示:

Web前端持续集成方案(二)_第6张图片

        Plato中通过一系列指标来衡量一个项目的代码质量情况。下面详细介绍一下各指标的意义。

            5.1、Total Lines

                总代码行,表示文件中的代码总行数。

            5.2、Avarage Lines

                平均代码行=总代码行/文件数。

            5.3、Maintainability

                Maintainability Index = MAX(0,(171 - 5.2 * log(Halstead Volume) - 0.23 * (Cyclomatic Complexity) - 16.2 * log(Lines of Code))*100 /171)。

                可维护性指标是0-100之间的数字,越高越容易维护。其中:

                    20-100:易于维护

                    10-19:较难维护

                    0-9:很难维护

                提高可维护性的方法有:

                    降低圈复杂度

                    降低单文件代码行数

                参考:http://blogs.msdn.com/b/zainnab/archive/2011/05/26/code-metrics-maintainability-index.aspx

            5.4、Average Maintainability

                平均可维护性=每个文件的可维护性指数求平均。

            5.5、Halstead complexity measures

                Halstead复杂度测量算法,如下图所示:

Web前端持续集成方案(二)_第7张图片

                参考:https://en.wikipedia.org/wiki/Halstead_complexity_measures

            5.6、Estimated errors in implementation

                潜在bug数估计,算法如下图所示:


                降低潜在bug数的方法:

                    降低代码量。

                参考:https://en.wikipedia.org/wiki/Halstead_complexity_measures

            5.7、Lint errors

                jsLint错误数。

            5.8、Difficulty


                文件中去重操作数越多,越难;重复操作符越多,越难。

                参考:https://en.wikipedia.org/wiki/Halstead_complexity_measures

            5.9、Complexity

                圈复杂度,表示代码块中所有可能的路径数。圈复杂度越低越好。

                降低圈复杂度的方法:

                    减少分支数。

            5.10、Function weight

                函数权重。有如下几种分类方式:

                    By Complexity:按圈复杂度统计。

                    BySLOC:按照SLOC/LSLOC(源代码行/逻辑代码行)统计。

                    SLOC:物理代码行,统计物理行数,包括注释、空行等。

                    LSLOC:逻辑代码行,统计语句数。

                参考:https://en.wikipedia.org/wiki/Source_lines_of_code

            6、css、js转换

                因为项目中有用到sass和seajs。所以,打包的时候需要把sass文件转为css文件,用到gruntjs/grunt-contrib-sass插件,具体配置如下:

sass: {
  dist: {
    options: {
      style: "compressed",
      sourcemap: 'none'
    },
    files: [{
      expand: true,
      cwd: 'theme/default/scss',
      src: ['**/*.scss'],
      dest: 'dist/theme/default/css',
      ext: '.css'
    }, {
      expand: true,
      cwd: 'theme/affairs/scss',
      src: ['**/*.scss'],
      dest: 'dist/theme/affairs/css',
      ext: '.css'
    }]
  }
}

                CMD规范规定一个文件内只能定义一个模块。因此多个模块文件不能合并为一个文件。为了解决这个问题,需要引入spmjs/grunt-cmd-transport插件。该插件可以为seajs模块分配id和提取依赖项,这样就能够支持多模块文件合并。相应配置如下:

// 转化
transport: {
  options: {
    debug: false,
    idleading: 'dist/',
    alias: {
      '$': '$',
      'helper': 'helper',
      'cache': 'cache',
      'fun': 'fun',
      'kissy': 'kissy'
    }
  },
  script: {
    options: {
      idleading: 'script/module/'
    },
    files: [{
      expand: true,
      cwd: 'script/module/',
      src: ['**/*.js', '!**/index.js', '!**/tpl/*.dev.js'],
      dest: '.build/script/module'
    }]
  }
}

7、文件删除、合并、拷贝、压缩。

需要用到gruntjs/grunt-contrib-clean、spmjs/grunt-cmd-concat、gruntjs/grunt-contrib-copy和gruntjs/grunt-contrib-uglify。这几个插件很常用,不解释。


你可能感兴趣的:(javascript)