安装
- 首先,grunt依赖Nodejs和npm环境
- 使用npm安装grunt-cli命令行工具
- 全局安装
1
| npm install -g grunt-cli
|
- 在项目中添加
1
| npm install grunt --save-dev
|
- 在项目根目录下创建Gruntfile.js文件
Gruntfile.js文件结构
- 一个’wrapper’方法
- 配置项目和任务
- 加载grunt插件
- 配置任务
Task
作为Task就是一个个任务
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| copy: { html: { files: [{ expand: true, cwd: './src/', src: '**/**.html', dest: './dist/' }] }, js:{ files:[{ expand:true, cwd:'./src/', src:'**/**.js', dest:'./dist/' }] } }
|
这个任务就是将html和js文件都复制到dist目录下
target
而target则是任务中针对不同操作分配的子项,在上述copy任务中,html和js就是两个target,他们分别负责复制不同的文件。
options
options就是每个任务的配置项目,在上述的copy任务中,expand,cwd,src,dest都是options
完整的Gruntfile.js示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| //wrapper函数 module.exports = function (grunt) { //配置项目和任务 grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), //复制html和图片文件到dist copy: { html: { files: [{ expand: true, cwd: './src/', src: '**/**.html', dest: './dist/' }] }, js:{ files:[{ expand:true, cwd:'./src/', src:'**/**.js', dest:'./dist/' }] }, images: { files: [{ expand: true, cwd: './src/images', src: '*', dist: './dist/images/', }] } }, //合并js concat:{ dist: { file: { './dist/js/all.js':['./dist/js/a1.js','./dist/js/a2.js'] } } }, //sass sass: { output: { files: { './dist/css/style.css': './src/less/a.sass' } } }, //压缩 uglify: { uglifyjs: { files: { './dist/js/all.js': ['./dist/js/all.js'] } } }, //打开服务器 connect: { options: { port: 9000, open: true, livareload: 35729, //change this to '0.0.0.0' to access the server from outside hostname: 'localhost' }, server: { options: { port: 9001, base: './' } } } });
//加载插件 grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-connect'); //注册任务 grunt.registerTask('copyhtml', ['copy:html']); //可以用task:target的方法分别注册 grunt.registerTask('concatjs', ['concat']); //也可以只用task名称注册,默认执行task下全部target grunt.registerTask('outputcss', ['sass']); // grunt.registerTask('watchit', ['concat', 'sass', 'jshint', 'uglify', 'connect', 'watch']); grunt.registerTask('default', ['copy', 'concat', 'sass', 'uglify']); };
|
配置任务
任务配置是Gruntfile通过grunt.initConfig方法指定的。这种配置大多会在任务命名的属性下,但可能包含任何任意的数据。只要属性不与任务需要的属性相冲突,它们将被忽略。
另外,因为这是JavaScript,所以不仅限于JSON。可以在这里使用任何有效的JavaScript。甚至可以编程生成配置,如果有必要的话。
1 2 3 4 5 6 7 8 9 10 11
| grunt.initConfig({ concat: { // concat task configuration goes here. }, uglify: { // uglify task configuration goes here. }, // Arbitrary non-task-specific properties. my_property: 'whatever', my_src_files: ['foo/*.js', 'bar/*.js'], });
|
配置task和target,添加options
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| grunt.initConfig({ concat: { options: { //task级别的options,会默认执行 }, foo: { options: { // "foo" 的options,会覆盖task级别的options }, }, bar: { //没有配置options,将会使用task级别的options }, }, });
|
文件输入和输出
src-dest两个options将用于定义他们
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| grunt.initConfig({ concat: { foo: { src:'/src/a.js', //可以使用字符串格式 dest:'/dist/a.js' }, bar: { src:['/src/a.js','/src/aa.js'], //可以使用数组格式 dest:'/dist/a.js' }, baz:{ files:{ '/dist/a.js':['/src/a.js','/src/aa.js'] //也可以使用文件对象格式 } }, boz:{ files:[ {'/dist/a.js':['/src/a.js','/src/aa.js']}, //文件对象格式也支持多个src-dest映射 {'/dist/b.js':['/src/b.js','/src/bb.js']} ] } }, });
|
Globbing模式
单独指定所有源文件路径通常是不切实际的,所以Grunt通过内置的node-glob和minimatch库支持文件名扩展(也称为globbing)。
在文件路径中:
- *匹配任意数量的字符,但不是 /
- ?匹配单个字符,但不匹配 /
- **匹配任意数量的字符,包括/只要它是路径部分中唯一的字符
- {}允许逗号分隔的“或”表达式列表
- !在一个模式的开始将忽略这种文件
所有大多数人需要知道的是,foo/.js将匹配.js在foo/子目录中结束的所有文件,但foo/**/.js将匹配.js在foo/子目录及其所有子目录中结束的所有文件。
另外,为了简化复杂的通配模式,Grunt允许指定文件路径或Globing模式的数组。模式按顺序处理,!前缀匹配不包括结果集中的匹配文件。结果集是唯一的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| // 匹配单文件: {src: 'foo/this.js', dest: ...} // 匹配数组中的文件: {src: ['foo/this.js', 'foo/that.js', 'foo/the-other.js'], dest: ...} // 以th开头的js文件: {src: 'foo/th*.js', dest: ...}
// 仅a.js和b.js: {src: 'foo/{a,b}*.js', dest: ...} // a,b开头的js文件: {src: ['foo/a*.js', 'foo/b*.js'], dest: ...}
// 根目录下的所有js文件: {src: ['foo/*.js'], dest: ...} // foo目录下的所有js文件,但是bar.js将优先匹配: {src: ['foo/bar.js', 'foo/*.js'], dest: ...}
// 除了bar.js外的所有js文件: {src: ['foo/*.js', '!foo/bar.js'], dest: ...} // 左右js文件,但是bar.js最后匹配. {src: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], dest: ...}
// 使用模板进行匹配: {src: ['src/<%= basename %>.js'], dest: 'build/<%= basename %>.min.js'} // 模板也可以引入文件列表: {src: ['foo/*.js', '<%= jshint.all.src %>'], dest: ...}
|
模板
使用<% %>分隔符指定的模板将在任务从配置中读取时自动展开。递归地扩展模板直到没有更多的剩余。
整个配置对象是属性被解析的上下文。另外,grunt它的方法在模板中可用,例如。<%= grunt.template.today(‘yyyy-mm-dd’) %>。
- <%= prop.subprop %>prop.subprop无论类型如何,展开到配置中的值。像这样的模板不仅可以用来引用字符串值,还可以用来引用数组或其他对象。
- <% %>执行任意的内联JavaScript代码。这在控制流程或循环中很有用。
导入外部数据
grunt由grunt.file.readJSON和grunt.file.readYAML导入JSON和YAML数据的方法。
1
| pkg: grunt.file.readJSON('package.json')
|
创建任务
注册任务
语法:
1
| grunt.registerTask(taskName, [description, ] taskList)
|
默认任务,将在输入grunt之后直接执行,一下任务将在不指定任何人物的情况下执行jshint,qunit,concat,uglify
1
| grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);
|
target可以以被指定,一下任务将在输入grunt dist命令时执行concat的dist target和uglify的dist target
1
| grunt.registerTask('dist', ['concat:dist', 'uglify:dist']);
|
多任务
当多任务运行时,Grunt在Grunt配置中查找同名的属性(task)。多任务可以有多个配置,使用任意命名的“target”定义。
1
| grunt.registerMultiTask(taskName, [description, ] taskFunction)
|
自定义任务
当一个基本任务运行时,Grunt不会查看配置或者环境 - 它只是运行指定的任务函数。
1
| grunt.registerTask(taskName, [description, ] taskFunction)
|
API
官方api地址:https://gruntjs.com/api/grunt
这里不赘述
Author: jianjian
Permalink: http://yoursite.com/2018/01/14/Grunt%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/
License: Copyright (c) 2019 CC-BY-NC-4.0 LICENSE
Slogan: Do you believe in DESTINY?