《JavaScript开发框架权威指南》——2.4 处理任务

2.4 处理任务

对于配置来说,Grunt的config()方法既是“getter”,也是“setter”。在清单中,我们可以看到一个基本的Grunt任务是如何通过此方法来存取配置的。

清单2-9 管理一个基本Grunt任务的配置

module.exports = function(grunt) {

    grunt.config('basic-task', {
        'message': 'Hello, world.'
    });

    grunt.registerTask('basic-task', function() {
        grunt.log.writeln(grunt.config('basic-task.message'));
    });
};

注意:
 

清单2-9中“点记法”(dot notation)是用来访问多级嵌套的配置参数的。采用同样的方式,点记法还可以用于设置多级嵌套的配置参数值。而且无论在哪里遇到不存在的配置路径,Grunt都会为其创建一个新的空对象,而不抛出异常。
2.4.2 任务描述
随着时间的推移,项目复杂性会逐渐增加,因此需要不断添加新的Grunt任务。但是随着任务的增多,任务的可用性、用途以及调用方法等越来越难以追踪。幸运的是,Grunt已经为我们提供了一条解决此问题的途径。如清单所示,我们可以为任务设定相应的描述。

清单2-10 为Grunt任务设置描述

// example-task-description/Gruntfile.js

module.exports = function(grunt) {

    grunt.config('basic-task', {

        'message': 'Hello, world.'
    });
    grunt.registerTask('basic-task', 'This is an example task.', function() {
        grunt.log.writeln(grunt.config('basic-task.message'));
    });

    grunt.registerTask('default', 'This is the default task.', ['basic-task']);
};

要为任务设置描述,只要在调用registerTask()时多传入一个参数即可。如果在命令行中请求帮助信息,Grunt就会将这些任务描述打印出来。清单截取了其中的一个片段。

清单2-11 在命令行中请求帮助信息

$ grunt --help
...
Available tasks
    basic-task This is an example task.
        default This is the default task.
...

2.4.3 异步任务
默认情况下,Grunt任务是同步执行的。只要任务函数返回,即可认为任务已经执行完毕。然而,有时候我们需要在任务中使用异步函数,而且必须等待其执行完毕才能将控制权交还给Grunt。清单中展示了这个问题的解决方法。在任务中调用async()方法将通知Grunt此任务是异步执行的。该方法返回一个回调函数,用于在任务完成时调用。在此之前,Grunt暂不会执行任何额外的任务。

清单2-12 异步Grunt任务

// example-async/tasks/list-files.js

var glob = require('glob');
module.exports = function(grunt) {

    grunt.registerTask('list-files', function() {

        /**
         * Grunt将一直等待我们调用done()函数来通知它异步任务执行完毕。
         */
        var done = this.async();
        glob('*', function(err, files) {
            if (err) {
                grunt.fail.fatal(err);
            }
            grunt.log.writeln(files);
            done();
        });
    });
};

2.4.4 任务依赖
对于复杂的Grunt工作流程,我们最好将其看作由一系列协同工作以达成最终结果的任务步骤组成。这种情况下,为任务指定一个或多个其他任务作为先决条件往往很有帮助,如清单所示。

清单2-13 声明任务依赖

// example-task-dependency/tasks/step-two.js

module.exports = function(grunt) {
    grunt.registerTask('step-two', function() {
        grunt.task.requires('step-one');
    });
};

本例中,step-two任务要求step-one必须在其之前运行。任何试图直接调用step-two的行为都将导致错误发生,如清单所示。

清单2-14 依赖项运行之前直接运行任务导致Grunt报错

$ grunt step-two
Running "step-two" task
Warning: Required task "step-one" must be run first. Use --force to continue.

Aborted due to warnings.

2.4.5 多任务
除基本任务之外,Grunt还支持“多任务”(multi-task)。多任务差不多是Grunt里最复杂的概念,所以如果你一开始感到困惑,别担心,这很正常。事实上,只要看过几个例子之后,它们的用途就会变得清晰起来,你也会从此踏上精通Grunt的道路。继续之前,还是让我们先看一个比较简单的多任务示例及其配置(见清单)。

清单2-15 Grunt多任务

// example-list-animals/tasks/list-animals.js

module.exports = function(grunt) {
    /**
     * Our multi-task's configuration object. In this example, 'mammals'
     * and 'birds' each represent what Grunt refers to as a 'target.'
     */
    grunt.config('list-animals', {
        'mammals': {
            'animals': ['Cat', 'Zebra', 'Koala', 'Kangaroo']
        },
        'birds': {
            'animals': ['Penguin', 'Sparrow', 'Eagle', 'Parrot']
        }
    });

    grunt.registerMultiTask('list-animals', function() {
        grunt.log.writeln('Target:', this.target);
        grunt.log.writeln('Data:', this.data);
    });
};

多任务的使用极其灵活,其设计目的就是在单个项目中支持多种配置(称作“目标”,targets)。清单中的多任务有两个目标:mammals和birds。如清单所示,该任务可以按照任一目标运行。

清单2-16 按照特定目标运行清单中的任务

$ grunt list-animals:mammals
Running "list-animals:mammals" (#list-animals) task
Target: mammals
Data: { animals: [ 'Cat', 'Zebra', 'Koala', 'Kangaroo' ] }

Done, without errors.

运行多任务时也可以不传入任何参数。这种情况下,任务会为每个可用的目标都运行一次。清单展示了在不指定目标的情况下运行多任务所产生的结果。

清单2-17 在不指定目标的情况下,运行清单中的多任务

$ grunt list-animals
Running "list-animals:mammals" (#list-animals) task
Target: mammals
Data: { animals: [ 'Cat', 'Zebra', 'Koala', 'Kangaroo' ] }

Running "list-animals:birds" (#list-animals) task
Target: birds
Data: { animals: [ 'Penguin', 'Sparrow', 'Eagle', 'Parrot' ] }

上述示例中,我们的多任务运行了两次,每个目标一次(mammals和birds)。注意在清单中,我们的多任务引用了两个属性:this.target和this.data。这些属性使得多任务能够获取与当前正在运行的目标相关的信息。

2.4.6 多任务选项
在配置多任务时,任何存储在options键下的值(见清单)都会受到特殊处理。

清单2-18 Grunt多任务与Options配置项

// example-list-animals-options/tasks/list-animals.js

module.exports = function(grunt) {

    grunt.config('list-animals', {
        'options': {
            'format': 'array'
        },
        'mammals': {
            'options': {
                'format': 'json'
            },
            'animals': ['Cat', 'Zebra', 'Koala', 'Kangaroo']
        },
        'birds': {
            'animals': ['Penguin', 'Sparrow', 'Eagle', 'Parrot']
        }
    });

    grunt.registerMultiTask('list-animals', function() {

        var options = this.options();

        switch (options.format) {
            case 'array':
                grunt.log.writeln(this.data.animals);
            break;
            case 'json':
                grunt.log.writeln(JSON.stringify(this.data.animals));
            break;
            default:
                grunt.fail.fatal('Unknown format: ' + options.format);
            break;
        }
    });

};

多任务选项为开发者提供了一种机制,即为任务定义和全局选项可以被目标任务的选项覆写。本例中,动物列表的全局选项format在任务层级被定义为'array'。目标mammals将其覆写为'json',但是目标birds没有。这样,mammals将显示为JSON串,而birds则继承全局选项的设定仍然显示为数组。

今后你遇到的绝大多数Grunt插件都会是可配置的多任务。由此而来的灵活性使得我们可以针对不同的应用环境,以不同的方式运行同一个任务。一个常见的情景就是为不同的构建环境创建不同的输出目标。例如,在编译程序时,针对本地开发环境和产品发布可以选用不同的任务运行配置。

2.4.7 模板配置
Grunt配置对象支持配置嵌入式的模板字符串,可用于之后的其他配置。Grunt支持的模板格式遵循Lodash和Underscore,具体细节会涵盖在后续的章节中。清单和清单中的示例显示了该功能可以如何使用。

清单2-19 Gruntfile样例,Grunt配置对象的pkg键中保存了项目package.json的内容

// example-templates/Gruntfile.js

module.exports = function(grunt) {
    grunt.initConfig({
        'pkg': grunt.file.readJSON('package.json')
    });
    grunt.loadTasks('tasks');
    grunt.registerTask('default', ['test']);
};

清单2-20 使用自身配置的后续加载任务,可以使用模板来引用其他配置

// example-templates/tasks/test.js

module.exports = function(grunt) {
    grunt.config('test', {
        'banner': '<%= pkg.name %>-<%= pkg.version %>'
    });
    grunt.registerTask('test', function() {
        grunt.log.writeln(grunt.config('test.banner'));
    });
};

清单展示了Gruntfile配置样例,其通过使用一系列与文件系统交互的内置方法,实现了加载项目Package.Json文件的内容,这些内置方法会在本章后续内容中讨论。文件内容随后存储在Grunt配置对象的pkg属性中。在清单中可以看到,通过使用配置模板,任务能够直接引用配置对象pkg的信息。

2.4.8 命令行选项

通过如下格式可以为Grunt传递额外配置项。

$ grunt count --count=5
清单中的例子展示了Grunt任务是如何通过grunt.option()方法获取信息的。从清单可以看到调用该任务的结果。

清单2-21 简单Grunt任务计数到指定数字

// example-options/tasks/count.js

module.exports = function(grunt) {

    grunt.registerTask('count', function() {
        var limit = parseInt(grunt.option('limit'), 10);
        if (isNaN(limit)) grunt.fail.fatal('A limit must be provided (e.g. --limit=10)');
        console.log('Counting to: %s', limit);
        for (var i = 1; i <= limit; i++) console.log(i);
    });
};
清单2-22 执行清单中任务的输出结果

$ grunt count --limit=5
Running "count" task
Counting to: 5
1
2
3
4
5

Done, without errors.

2.4.9 提供反馈
为了在执行任务时为用户提供反馈信息,Grunt提供了一些内置方法,其中某些方法你已经在本章中看过。当然,我们不会在此处列出所有方法,但表中列出了一些常用的。

2.4.10 错误处理
在任务执行的过程中,会遇到错误。当遇到这种情况时,知道如何合理地处理它们是很重要的。当面对一个错误时,开发者需要使用Grunt的错误API。它很易于使用,因为它只提供了两个方法(见表)。

时间: 2024-08-03 02:27:33

《JavaScript开发框架权威指南》——2.4 处理任务的相关文章

《JavaScript开发框架权威指南》——第2章 Grunt 2.1安装Grunt

第2章 Grunt 我是一个懒人.但正是懒人发明了轮子和自行车,因为他们既不愿意走路,也不愿意负重前行. --莱赫·瓦文萨,波兰前总统 拉里·沃尔(Larry Wall,著名的Perl语言创始人)在他的<Programming Perl>一书中提到,所有成功的程序员都有三个重要的品质:懒惰.急躁以及狂妄.乍一看,这些都是相当糟糕的品质,但是只是深挖一下,你就会发现其言外之意. 懒惰:懒惰的程序员讨厌重复自己.他们通常会花费大量的时间去创造有用的工具,代替自己完成重复性的工作.他们往往还会为这些

《JavaScript开发框架权威指南》——2.5 操作文件系统

2.5 操作文件系统 可想而知,作为构建工具,大部分Grunt插件都要以某种方式和文件系统交互.鉴于操作文件的重要性,Grunt提供了有益的抽象允许开发者与文件系统交互,并且仅仅使用很少数量的样板代码. 当然,我们不会把所有方法都列举在此,表显示了Grunt文件操作API中一些使用频率最高的方法.2.5.1 源-目标映射 许多Grunt任务与文件系统交互是依赖于源-目标映射的,该映射描述了要被处理的文件及各文件对应的目标.构建这样的映射会很冗长乏味,感谢Grunt为我们提供了解决此问题的有益捷径

《JavaScript开发框架权威指南》——2.2 Grunt是如何工作的

2.2 Grunt是如何工作的 Grunt为开发者提供了一个工具包,用于创建命令行程序来执行项目构建过程中的重复性任务,如压缩JavaScript代码.编译Sass样式表等.不过,Grunt的能力并不限于创建简单的任务(通常这些任务不会被分享或者复用),以解决特定工程遇到的特定需求,其真正的力量源于其将任务打包为可复用的插件的能力.这些插件可以被发布.分享.使用以及由其他人进行改进.本书写作之时已经有超过4 400个这样的插件. Grunt的运转依赖于四个核心组件,接下来逐一论述. 2.2.1

《JavaScript开发框架权威指南》——第1章 Bower 1.1准备工作

第1章 Bower 九层之台,起于累土. -- 文森特·梵高 包管理(Package Management),又作依赖关系管理(Dependency Management),并不是什么新奇的概念.此类工具为开发者提供了一种机制,以管理软件项目所依赖的各种第三方库.一些得到广泛应用的例子有: npm:Node.js的包管理工具: Composer:一种PHP依赖关系管理工具: pip:PyPA的推荐工具,用于安装Python包: NuGet:包括.NET在内的微软开发平台的包管理工具. 尽管包管理

《JavaScript开发框架权威指南》——2.6 创建Grunt插件

2.6 创建Grunt插件 社区提供的丰富插件库是让Grunt真正变得闪耀的库,它能使你立即从Grunt中获益,而不是需要从头创建复杂的任务.如果你需要在项目中做自动构建,那么很可能某人已经为你做好这项"Grunt"工作.在这一节中,你可以懂得如何向社区回馈自己创建的Grunt插件. 2.6.1 开始 首先要做的事情之一是情创建一个公共的GitHub仓库,以存储你的新插件.下文中将要提及的示例包含在本书附带的源码中,本书附带了源码.一旦你准备好代码仓库,就把它克隆到你的电脑上.下一步,

《JavaScript开发框架权威指南》——1.6 维护依赖链

1.6 维护依赖链 Bower给开发者带来的一个主要好处,就是可以非常方便地对整个项目的依赖链以一种相对受控的方式进行集中升级.为此,我们先来看一下本章示例项目所包含的依赖项列表(见清单). 清单1-8 安装并列出示例项目所需的Bower包 $ bower install bower bootstrap#3.2.0 cached git://github.com/twbs/bootstrap.git#3.2.0 bower bootstrap#3.2.0 validate 3.2.0 again

《JavaScript开发框架权威指南》——2.3 将Grunt添加到项目中

2.3 将Grunt添加到项目中 在本章前面,为了添加Grunt命令行工具,我们将npm包grunt-cli作为全局模块进行了安装.现在我们应该已经可以在命令行中使用Grunt命令,但是对于每个要使用Grunt的工程,仍然需要为其配置Grunt本地依赖.为此,只需在工程根目录下运行以下命令即可.本例假设npm已经针对示例所用项目进行了初始化,package.json文件也已经存在. $ npm install grunt --save-dev 现在,我们项目的package.json文件应该已经

《JavaScript开发框架权威指南》——1.5 语义化版本控制

1.5 语义化版本控制 如果安装了jQuery(见清单),那么请查看项目的Bower清单.你所看到的应当与清单相仿. 清单1-7 语义化版本号 "dependencies": { "jquery": "~2.1.3" } 清单中的版本号2.1.3(请暂时忽略-)就是所谓的语义化版本号(Semver,Semantic Version).语义化版本控制能够帮助开发者按照通用格式为其项目指定版本号.该格式如下所示. Version X.Y.Z(Majo

《JavaScript开发框架权威指南》——1.7 创建Bower包

1.7 创建Bower包 截至目前,我们关注的焦点都在如何将Bower集成到项目中.我们先在项目中对Bower进行了初始化,然后探究了查找.添加以及移除软件包的方法.但是总有那么一天,你会希望将自己的软件包分享给其他人.要这么做的话,就必须遵守一些简单的规则,让我们从选择有效的包名开始. 1.7.1 选择有效的包名你需要为自己的包选定一个名字,该名字必须在整个Bower开放注册中心(public registry)唯一.通过Bower的search命令来检查你想要的名字是否可用.其他需要遵守的规