本节书摘来自异步社区《JavaScript开发框架权威指南》一书中的第2章,第2.5节,作者:【美】Tim Ambler , Nicholas Cloud著,更多章节内容可以访问云栖社区“异步社区”公众号查看
可想而知,作为构建工具,大部分Grunt插件都要以某种方式和文件系统交互。鉴于操作文件的重要性,Grunt提供了有益的抽象允许开发者与文件系统交互,并且仅仅使用很少数量的样板代码。
当然,我们不会把所有方法都列举在此,表显示了Grunt文件操作API中一些使用频率最高的方法。2.5.1 源-目标映射许多Grunt任务与文件系统交互是依赖于源-目标映射的,该映射描述了要被处理的文件及各文件对应的目标。构建这样的映射会很冗长乏味,感谢Grunt为我们提供了解决此问题的有益捷径。
假设你正在开发一个项目,该项目根目录有一个公共文件夹。一旦工程部署后,这个文件夹中的文件要通过网络提供服务(见清单)。
清单2-23 虚构项目的公共文件夹内容
// example-iterate1 . └── public └── images ├── cat1.jpg ├── cat2.jpg └── cat3.png如你所见,项目包含一个图片文件夹,其中有三个文件。了解这些内容之后,让我们看看Grunt能通过哪些方式来帮我们迭代这些文件。
如清单所示,Grunt的多任务配置和刚才介绍的很相似。关键不同之处在于任务配置中的src属性。在我们的任务中,Grunt提供了一个this.files属性,该属性提供了一个包含着匹配到每个文件路径的数组,这些文件通过node-glob模块取得匹配到的文件路径数组。任务输出的结果可以在清单中看到。
清单2-24 Grunt多任务配置对象,包含一个src键
// example-iterate1/tasks/list-files.js module.exports = function(grunt) { grunt.config('list-files', { 'images': { 'src': ['public/**/*.jpg', 'public/* * /* .png'] } }); grunt.registerMultiTask('list-files', function() { this.files.forEach(function(files) { grunt.log.writeln('Source:', files.src); }); }); };清单2-25 清单中Grunt任务输出的结果
$ grunt list-files Running "list-files:images" (#list-files) task Source: [ 'public/images/cat1.jpg', 'public/images/cat2.jpg', 'public/images/cat3.png' ] Done, without errors.配置属性src和多任务属性this.files的结合使用,在迭代多文件时给开发者提供了精确的语法。以上的例子明显设计得非常简单,不过Grunt也同样为更复杂的场景提供额外选项。下面让我们来看一下。
与清单中所示的键src的用法相反,清单的例子展示了文件数组的使用——尽管这种方法有点冗长,但它为选择文件提供了更强大的数据格式。该格式接受额外的选项,从而让我们能够更好地调整我们的选择。特别重要的是它的expand选项,如清单所示。请仔细关注,由于使用了expand选项,该示例与清单的输出有所不同。
清单2-26 使用“文件数组”格式迭代文件
// example-iterate2/tasks/list-files.js module.exports = function(grunt) { grunt.config('list-files', { 'images': { 'files': [ { 'cwd': 'public', 'src': ['**/*.jpg', '* */*.png'], 'dest': 'tmp', 'expand': true } ] } }); grunt.registerMultiTask('list-files', function() { this.files.forEach(function(files) { grunt.log.writeln('Source:', files.src); grunt.log.writeln('Destination:', files.dest); }); }); };清单2-27 清单中Grunt任务的输出
$ grunt list-files Running "list-files:images" (#list-files) task Source: [ 'public/images/cat1.jpg' ] Destination: tmp/images/cat1.jpg Source: [ 'public/images/cat2.jpg' ] Destination: tmp/images/cat2.jpg Done, without errors.当该expand选项与dest选项成对出现的时候,表示明Grunt会迭代访问任务中的this.files. forEach循环所找到的每个入口文件。在每个文件内,我们可以找到对应的dest属性。使用这种方法,我们就能很容易地创建源-目的地映射,可以用于把文件从一个位置复制(或移动)到另一个位置。
2.5.2 监视文件变化当特定模式下匹配到的文件被创建、修改、删除时,Grunt最为流行的插件之一grunt-contrib-watch使Grunt有能力运行预定义的任务。当和其他任务结合在一起时,grunt-contrib-watch让开发者能创建强大的工作流,用于自动执行如下工作:
检查JavaScript代码中的错误(如静态语法分析“linting”);编译Sass/L样式表;运行单元测试下面让我们看几个实践中运用上述工作流的例子。
1.JavaScript 自动化静态检查清单显示了一个基本的Grunt设置,和本章已经展示的示例相似。监视任务以默认任务作为别名注册在Grunt中,这样我们就能简单地在命令行中运行$ grunt来监视项目中的变化。本例中,Grunt会监视src文件夹下的变化。一旦变化发生,jshint任务就会触发。
清单2-28 发生变化时自动检查JavaScript错误
// example-watch-hint/Gruntfile.js module.exports = function(grunt) { grunt.loadTasks('tasks'); grunt.registerTask('default', ['watch']); }; // example-watch-hint/tasks/jshint.js module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.config('jshint', { 'options': { 'globalstrict': true, 'node': true, 'scripturl': true, 'browser': true, 'jquery': true }, 'all': [ 'src/**/*.js' ] }); }; // example-watch-hint/tasks/watch.js module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-watch'); grunt.config('watch', { 'js': { 'files': [ 'src/**/*' ], 'tasks': ['jshint'], 'options': { 'spawn': true } } }); };2.自动编译Sass样式表清单展示了这样一个示例,它引导Grunt来监视项目变化。然而这次不同于监视JavaScript文件,Grunt监视的是项目的Sass样式表。当变化发生的时候,插件grunt-contrib-compass被调用,把样式表编译为最终形态。
清单2-29 变化发生时自动编译Sass样式表
// example-watch-sass/Gruntfile.js module.exports = function(grunt) { grunt.loadTasks('tasks'); grunt.registerTask('default', ['watch']); }; // example-watch-sass/tasks/compass.js module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-compass'); grunt.config('compass', { 'all': { 'options': { 'httpPath': '/', 'cssDir': 'public/css', 'sassDir': 'scss', 'imagesDir': 'public/images', 'relativeAssets': true, 'outputStyle': 'compressed' } } }); }; // example-watch-compass/tasks/watch.js module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-watch'); grunt.config('watch', { 'scss': { 'files': [ 'scss/**/*' ], 'tasks': ['compass'], 'options': { 'spawn': true } } }); };注意:
若想让本例生效,前提是需要安装Compass。它是一个开源CSS编辑框架。3.自动化单元测试最后一个例子是使用grunt-contrib-watch插件来完成单元测试。清单展示了用于监视JavaScript变化的Gruntfile。变化发生时会立即触发项目的单元测试,单元测试由grunt-mocha-test插件完成。
清单2-30 当变化发生时自动运行单元测试
// example-watch-test/Gruntfile.js module.exports = function(grunt) { grunt.loadTasks('tasks'); grunt.registerTask('default', ['watch']); }; // example-watch-test/tasks/mochaTest.js module.exports = function(grunt) { grunt.loadNpmTasks('grunt-mocha-test'); grunt.config('mochaTest', { 'test': { 'options': { 'reporter': 'spec' }, 'src': ['test/**/*.js'] } }); }; // example-watch-test/tasks/watch.js module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-watch'); grunt.config('watch', { 'scss': { 'files': [ 'src/**/*.js' ], 'tasks': ['mochaTest'], 'options': { 'spawn': true } } }); }; 相关资源:Android开发权威指南.(人民邮电.李宁).pdf