1. 程式人生 > >Web前端持續整合方案(二)

Web前端持續整合方案(二)

三、利用Grunt實現專案自動化打包

    Grunt是一款基於node的javascript工作管理員工具。我們的專案使用Grunt實現專案自動化打包,以及後續的持續整合。Grunt如何使用,本文不詳細介紹(其實是不會-_-!),詳見《【grunt整合版】30分鐘學會使用grunt打包前端程式碼》。

    1、打包思路

        專案從開發態到釋出態,需要做哪些事情?一、程式碼檢查,包括程式碼風格檢查、js靜態程式碼檢查、單元測試、程式碼靜態分析。二、檔案預處理:包括sass轉css、seajs模組轉換、檔案變數巨集替換。三、檔案拷貝、壓縮、合併。所以處理流程也很簡單。如下圖所示:


    2、程式碼風格檢查

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
}

生成報表如下圖所示:


    3、js程式碼靜態檢查

        其中,.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
}

        生成報表如下圖所示:


    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;
    }
  }
},

        生成的報表如下圖所示:


        點選失敗用例,可以檢視詳情:


        單元測試完成後,還要生成覆蓋率報告,這一部分內容坑比較多,另寫一篇文章詳細介紹。

    5、js程式碼靜態分析。

        js程式碼靜態分析需下載外掛:es-analysis/plato。引數配件比較簡單,如下圖所示:

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

        生成報表如下圖所示:


        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:很難維護

                提高可維護性的方法有:

                    降低圈複雜度

                    降低單檔案程式碼行數

            5.4、Average Maintainability

                平均可維護性=每個檔案的可維護性指數求平均。

            5.5、Halstead complexity measures

                Halstead複雜度測量演算法,如下圖所示:


            5.6、Estimated errors in implementation

                潛在bug數估計,演算法如下圖所示:


                降低潛在bug數的方法:

                    降低程式碼量。

            5.7、Lint errors

                jsLint錯誤數。

            5.8、Difficulty


                檔案中去重運算元越多,越難;重複操作符越多,越難。

            5.9、Complexity

                圈複雜度,表示程式碼塊中所有可能的路徑數。圈複雜度越低越好。

                降低圈複雜度的方法:

                    減少分支數。

            5.10、Function weight

                函式權重。有如下幾種分類方式:

                    By Complexity:按圈複雜度統計。

                    BySLOC:按照SLOC/LSLOC(原始碼行/邏輯程式碼行)統計。

                    SLOC:物理程式碼行,統計物理行數,包括註釋、空行等。

                    LSLOC:邏輯程式碼行,統計語句數。

            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、檔案刪除、合併、拷貝、壓縮。