目的:自动化构建项目;完成压缩,编译,单元测试,代码检查以及打包发布的任务。
生成线上调试source map,代码行统计。
常用Grunt任务:
Cache :cache-breaker、usemin + rev
CSS :grunt-recess、less、cssmin、uncss、csslint(CSS检测)
JS :uglify(压缩JS,Beautify JS,生成线上调试source map)、 jshint(JS代码检测及检测规则配置)、sloc(代码行统计)、ng-min(Angular代码压缩)、plato(代码复杂度、可维护性)
HTML :html-validation、
测试 :jasmine、qunit
基本任务 :clean、concat、copy、watch
Cache清除缓存任务
. usemin + rev
目的是清除浏览器缓存。
给静态文件重名后,再将html、css中的静态文件引用的名称替换成新文件名。
rev给静态文件重命名。usemin替换html、css中引用的静态文件名。
虽然usemin任务执行之前会自动执行 concat、uglify、cssmin任务。一般还是要自己定义任务:要先执行clean清除重命名的静态文件;concat合并文件;recess重新编译和压缩css文件;uglify重新压缩js文件。最后再执行useminPrepare,rev,usemin。
useminPrepare: {
src: "<%= site.destination %>/{,*/ /* }*.html",
options: {
dest: "<%= site.destination %>",
root: "<%= site.destination %>"
}
},
rev: {
options: {
algorithm: 'md5',
length: 8
},
assets: {
files: {
src: [
'<%= kui_css %>',
'<%= kui_js %>',
'<%= kuidoc_css %>',
'<%= kuidoc_js %>',
'./images/{,*/ /* }*.{png,jpg,jpeg,gif,webp}',
]
}
}
},
usemin: {
html: ["<%= site.destination %>/{,*/ /* }*.html" ],
css: ["./css/*.css" ],
options : {
assetDirs: [
'<%= site.destination %>',
'./css'
]
}
},
. cache-breaker
这个任务也是清除静态文件的浏览器缓存,相对usemin简单些。但是,cache-breaker只替换head标签中的url,不替换body中的链接。一般都会有置底加载的JS文件,这个任务就不太适用。
// Turn these :
<script src="/js/dist/combined.min.js"></script>
<link href="/css/style.css"></link>
// Into these :
<script src="/js/dist/combined.min.js?rel=123456"></script>
<link href="/css/style.css?rel=123456"></link>
cachebreaker: {
kuidoc_js: {
asset_url : '<%= kuidoc_js %>',
files: {
src : './_kui/*.html'
}
},
kuidoc_css: {
asset_url : '<%= kuidoc_css %>',
files: {
src : './_kui/*.html'
}
}
},
. cacheBust
这个任务也是清除静态文件的浏览器缓存,支持的静态文件格式有:CSS, JavaScript, images 和 favicons。这个任务会忽略远程静态文件,因为一般这些远程文件是存储在CDN上的静态文件通常是很稳定的库文件,比如jQuery、Bootstrap...它们的url通常会有个版本标志,通过这个标识符来避免浏览器缓存。你的页面最好引用用这些标准的url,保证浏览器缓存的命中率。304总是比200快。也就是,类似以下的url会被忽略:
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
没有采用这个任务的理由:
1、项目中css和js独立部署和引用,静态文件引入的是绝对地址,我们也希望能够清除缓存,这个任务不适用。
2、cacheBust针对html文件中的静态文件寻址是相对于Grunt.js文件的,这就要求html文件和Grunt.js在同一个文件夹中。
3、任务执行后有漏掉的css。
JS任务
. Uglify
这个任务一直在更新增强:
1、压缩我们的JavaScript文件;
2、Beautify反压缩JS文件;
3、可以用它给多文件生成source-map。
注意:Angular压缩的时候会将$scope变成 a,压缩前要先执行ng-min任务。
uglify: {
controller: {
options: {
banner: '<%= banner %>',
report: 'min',
// for Angular keyword $scope
mangle: false,
// except: ['jQuery', 'Angular', '$scope'],
// for source map
sourceMapRoot: '<%= doc_dir %>',
sourceMap: '<%= doc_dir %>/js/kui-controller.min.js.map',
sourceMapUrl: '<%= doc_dir %>/js/kui-controller.min.js.map'
},
src: '<%= doc_dir %>/js/kui-controller.ngmin.js',
dest: '<%= doc_dir %>/js/kui-controller.min.js'
}
},
. ng-min
AngularJS控制器构造函数通常简写成
$var SomeCtrl = function($scope, $element) {}
$scope, $element 是参数,但换个名字代码就不能正常运行了。也就是AngularJS是通过控制器构造函数的参数名字来推断依赖服务名称。所以如果你要压缩控制器的JS代码,它所有的参数也同时会被压缩,这时候依赖注入系统就不能正确的识别出服务了。
为了克服压缩引起的问题,
第一种方法是在控制器函数里面给$inject属性赋值一个依赖服务标识符的数组。
第二种方法使用Javascript数组方式构造控制器:把要注入的服务放到一个字符串数组(代表依赖的名字)里,数组最后一个元素是控制器的方法函数,就像AMD声明一样,写成
$var SomeCtrl = ['$scope', '$element', function(s, e) {}
ng-min采用的是第二种方法,来避免压缩引起的依赖注入系统不能识别服务问题。
ngmin: {
controllers: {
src: ['<%= doc_dir %>/js/kui-controller.js'],
dest: '<%= doc_dir %>/js/kui-controller.ngmin.js'
}
},
. sloc
计算代码行。 sloc: {
options: {
reportType: 'json',
reportPath: '<%= doc_dir %>/sloc-v<%= pkg.version %>.json',
},
files: {
'./': '<%= doc_dir %>/js/kui-controller.js',
'./': [ 'kui.js' ]
}
},
CSS任务
. grunt-recess
包括less编译和css压缩。
recess: {
options: {
compile: true,
banner: '<%= banner %>'
},
kui: {
src: ['./less/kui.less'],
dest: './css/kui.css'
},
kui_min: {
options: {
compress: true
},
src: ['./less/kui.less'],
dest: '<%= kui_css %>'
}
},
. Less
less编译
. cssmin
css压缩(有时压缩后浏览器无法载入)
验证和测试任务
. jshint
检查js代码错误。通过.jshintrc 来定义检测项。
jshint: {
//JSHint (http://www.jshint.com/docs/options/)
options: {
jshintrc: 'js/.jshintrc',
globals: {
jquery: true
}
},
kui: {
src: ['<%= js_dir %>/modal.confirm.js']
},
controller: {
src: ['<%= doc_dir %>/js/controller/*.js']
},
kuidoc: {
src: ['<%= doc_dir %>/js/<%= pkg.name %>.min.js', '<%= doc_dir %>/js/<%= pkg.name %>.js']
}
},
{
/* https://gist.github.com/haschek/2595796 */
"asi" : true, // Tolerate Automatic Semicolon Insertion (no semicolons).
"boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
"browser" : true, // Standard browser globals e.g. `window`, `document`.
"curly" : false, // Require {} for every new block or scope.
"debug" : true, // Allow debugger statements e.g. browser breakpoints.
"devel" : true, // Allow development statements e.g. `console.log();`.
"eqeqeq" : false, // true: Require triple equals (===) for comparison
"eqnull" : true, // true: Tolerate use of `== null`
"expr" : true, // Tolerate `ExpressionStatement` as Programs.
"laxbreak" : true, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
"laxcomma" : true, // Suppress warnings about comma-first coding style.
"validthis": true, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function.
}
. html-validation
检查HTMlL。
options.relaxerror定义需要忽略的报错,可以基于正则表达式匹配。比如,AngularJS中需要忽略HTML标签中的“ng-”开头的属性: 'Attribute ng-[a-z]+ not allowed on element [a-z]+ at this point.'这个配置项非常有用。
validation: {
options: {
reset: true,
relaxerror: [
'Bad value X-UA-Compatible for attribute http-equiv on element meta.',
'Element link is missing one or more of the following attributes: itemprop, property, rel.',
'Attribute srcset not allowed on element img at this point.',
'Attribute ng-[a-z]+ not allowed on element [a-z]+ at this point.',
'document type does not allow element [a-z]+ here',
'& did not start a character reference. *',
'Element xmp not allowed as child of element div in this context. *'
]
},
files: {
src: ["_kui/*.html"]
}
},
. uncss
检测HTML中没有使用到的css,并去除多余的css。
uncss: {
dist: {
files: {
'dist/css/tidy.css': ['app/index.html','app/about.html']
}
}
},
. jasmine
前端单元测试
基本grunt任务
. clean
清除文件,每次编译,需要清除旧文件。
. concat
合并文件。注意:如果concat后的文件不清除,会不停的在该文件内容的最前concat内容。
. copy
拷贝代码到build路径。
. watch
使用grunt watch来运行这个任务。监视特定目录中的变化,然后把代码编译/打包。
注意:clean任务第一个执行,copy任务最后执行。
安装命令
//安装Grunt的命令行接口(CLI) npm install -g grunt-cli npm install grunt-contrib-clean --save-dev npm install grunt-contrib-copy --save-dev npm install grunt-contrib-concat --save-dev npm install grunt-contrib-uglify --save-dev npm install grunt-contrib-jshint --save-dev npm install grunt-recess --save-dev npm install grunt-html-validation --save-dev npm install grunt-contrib-watch --save-dev npm install grunt-cache-bust --save-dev npm install grunt-cache-breaker --save-dev npm install grunt-jekyll --save-dev npm install grunt-ngmin --save-dev npm install grunt-sloc --save-dev npm install grunt-contrib-less --save-dev npm install grunt-contrib-cssmin --save-dev npm install grunt-contrib-jasmine --save-dev
加载所需要的Grunt插件
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-ngmin');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-recess');
grunt.loadNpmTasks('grunt-html-validation');
grunt.loadNpmTasks('grunt-jekyll');
grunt.loadNpmTasks('grunt-cache-breaker');
grunt.loadNpmTasks('grunt-rev');
grunt.loadNpmTasks('grunt-usemin');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sloc');
http://24ways.org/2013/grunt-is-not-weird-and-hard/
http://mikemclin.net/configuring-package-json-and-gruntfile-js/
Semantic Versioning Specification http://semver.org
NPM | package.json https://npmjs.org/doc/json.html
149

被折叠的 条评论
为什么被折叠?



