Grunt学习笔记【3】---- filter使用方式和实现原理详解
本文主要讲配置任务中的filter,包括使用默认fs.Stats方法名和自定义过滤函数,以及filter的实现原理。
通过设置filter属性可以实现一些特殊处理逻辑。例如:要清理某个文件夹下的所有空文件夹,这时使用clean任务时,需要判断该文件夹下的哪些是文件,哪些是文件夹,只对空文件执行clean任务。
具体使用方法分为如下两种:
一 使用fs.Stats方法作为过滤函数
fs.stats是NodeJS的一个类,上边提供了很多对文件判断的方法,具体可以参考这里。
如下将filter设置为'isFile'时,如果发现当前文件不是文件时,就不进行clean处理。
grunt.initConfig({
clean: {
foo: {
src: ['tmp/**/*'],
filter: 'isFile',
},
},
});
二 自定义过滤函数
自定义过滤函数,如果过滤函数返回true,就对当前文件进行处理;返回值是false时,就不处理当前文件。
下边示例是清理tmp下边所有的空文件夹:
grunt.initConfig({
clean: {
foo: {
src: ['tmp/**/*'],
filter: function(filepath) {
return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);
},
},
},
});
三 filter实现原理
在分析filter的实现原理之前,首先给出一个使用filter时的注意事项:
filter配置属性只能用于通过grunt.task.registerMultiTask()方法注册的复合任务。
如果使用的某个Grunt插件注册任务时,没有使用grunt.task.registerMultiTask 注册任务,则配置filter是不生效的。
而大多数的contrib任务,包括 jshint task、concat task 和 uglify task 都是复合任务。
下边说明filter在Grunt的实现原理:
通过grunt.task.registerMultiTask()方法注册复合任务时,会拿到配置信息中对应任务的配置对象,对配置对象中的filter属性进行判断,如果设置了filter,就对要处理的文件进行filter过滤,根据过滤结果将新的文件列表存到files属性中,各个任务函数中拿到的files属性实际上是已经过滤后的复合filter要求的文件。
下边以上边的clean任务为例,分析几个关键点的源码:
3.1 首先分析clean的源码:
在npm安装包node_module目录下grunt-contrib-clean中找到clean.js文件,该文件实际就是一个标准的nodeJS模块文件,找到其中通过grunt.registerMultiTask()方法注册clean任务代码,在第三个参数的处理函数中,我们可以看到这里实际是对this.filesSrc进行的处理,下边是部分代码:
module.exports = function(grunt) { function clean(filepath, options, done) {
// 省略的代码...
} grunt.registerMultiTask('clean', 'Clean files and folders.', function() {
// 省略的代码... // 要处理的文件
var files = this.filesSrc; async.eachSeries(files, function (filepath, cb) {
clean(filepath, options, cb);
}, function (err) {
grunt.log.ok(files.length + ' ' + grunt.util.pluralize(files.length, 'path/paths') + ' cleaned.');
done(err);
});
}); };
3.2 接下来分析task.normalizeMultiTaskFiles()函数的源码:
在该函数源码中,我们要找到传给上边clean函数的this.filesSrc来自哪里。
在grunt的npm源码包中,找到task.js,其中定义了task.registerMultiTask函数,从该函数中我们可以发现this.filesSrc实际是对this.files.src进行处理后得到的。
而this.files又是通过task.normalizeMultiTaskFiles(this.data, target)得到的,其中this.data和target就是源自于Grunt的配置信息。
在最后fn.apply(this, this.args)可以知道,这个fn实际就是注册任务时的回调函数。
下边是部分关键代码:
task.registerMultiTask = function(name, info, fn) {
// 省略的代码... task.registerTask(name, info, function(target) {
// 省略的代码... this.data = grunt.config([name, target]);
// 获取到files文件
this.files = task.normalizeMultiTaskFiles(this.data, target);
// 定义this.filesSrc文件
Object.defineProperty(this, 'filesSrc', {
enumerable: true,
get: function() {
return grunt.util._(this.files).chain().pluck('src').flatten().uniq().value();
}.bind(this)
});
// 调用任务的回调函数,并将指定this
return fn.apply(this, this.args);
}); // 省略的代码...
};
3.3 分析task.normalizeMultiTaskFiles()源码:
在这个源码中找到this.files.src是如何来的。从源码中可以发现来源于grunt.file.expand(expandOptions, src)函数。
下边是其中部分代码:
task.normalizeMultiTaskFiles = function(data, target) {
// 省略的代码... if ('src' in result) {
Object.defineProperty(result, 'src', {
enumerable: true,
get: function fn() {
var src;
if (!('result' in fn)) {
src = obj.src;
// If src is an array, flatten it. Otherwise, make it into an array.
src = Array.isArray(src) ? grunt.util._.flatten(src) : [src];
// Expand src files, memoizing result.
fn.result = grunt.file.expand(expandOptions, src);
}
return fn.result;
}
});
} // 省略的代码... return result;
};
3.4 分析grunt.file.expand源码:
在grunt的npm包中,找到file.js文件,在里边可以找到file.expand函数的定义,在该函数的定义中我们终于可以看到对filter的判断和处理,可以看到对filter是函数和字符时不同的处理。
下边是部分关键代码:
file.expand = function() {
// 省略的代码... if (options.filter) {
matches = matches.filter(function(filepath) {
filepath = path.join(options.cwd || '', filepath);
try {
if (typeof options.filter === 'function') {
return options.filter(filepath);
} else {
// If the file is of the right type and exists, this should work.
return fs.statSync(filepath)[options.filter]();
}
} catch(e) {
// Otherwise, it's probably not the right type.
return false;
}
});
}
return matches;
};
说明:本人实际分析源码过程是倒着来的,首先在grunt包中搜到filter判断的地方,然后一步一步查找方法的调用链。
参考资料&内容来源:
Grunt官网:https://www.gruntjs.net/configuring-tasks
Grunt学习笔记【3】---- filter使用方式和实现原理详解的更多相关文章
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...
- 【Ext.Net学习笔记】03:Ext.Net DirectEvents用法详解、DirectMethods用法详解
Ext.Net通过DirectEvents进行服务器端异步的事件处理.[Ext.Net学习笔记]02:Ext.Net用法概览.Ext.Net MessageBus用法.Ext.Net布局 中已经简单的 ...
- [原创]java WEB学习笔记43:jstl 介绍,core库详解:表达式操作,流程控制,迭代操作,url操作
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- <转>ASP.NET学习笔记之MVC 3 数据验证 Model Validation 详解
MVC 3 数据验证 Model Validation 详解 再附加一些比较好的验证详解:(以下均为引用) 1.asp.net mvc3 的数据验证(一) - zhangkai2237 - 博客园 ...
- 【精选】Nginx模块Lua-Nginx-Module学习笔记(一)Nginx Lua API 接口详解
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis 一.介绍 各种* _by_lua,* _by_lua_block和* _by_lua_file配置指令用 ...
- Nginx模块Lua-Nginx-Module学习笔记(一)Nginx Lua API 接口详解
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis 一.介绍 各种* _by_lua,* _by_lua_block和* _by_lua_file配置指令用 ...
- Linux学习笔记:644、755、777权限详解
一.问题 1.在Linux或者Android系统下用命令ll或者ls -la的时候会看到前面-rw-rw-r--一串字符,不知道代表什么? 2.新建vi一个文件之后,经常需要chmod 755 fil ...
- es6学习笔记(1) let和const命令详解
let和const命令: Es6新增了let命令,声明变量,但与var不一样的,只在let命令所在的代码块内有效(如for循环之外let声明的变量就不再有效).并且let不像var那样会发生" ...
- Android开发学习笔记:Intent的简介以及属性的详解【转】
一.Intent的介绍 Intent的中文意思是“意图,意向”,在Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述 ...
随机推荐
- Single Number II - LeetCode
Given an array of integers, every element appears three times except for one. Find that single one. ...
- spring-cloud - 服务之间的通信
上文中已经讲述了基本环境搭建,本文基于上文环境https://www.cnblogs.com/xxpandong/p/10485172.html. spring-cloud中微服务之间通信主要有俩种形 ...
- oracle小知识点16-诊断事件diagnostic events
http://blog.itpub.net/28539951/viewspace-1983919/
- iOS应用崩溃日志揭秘2
这篇文章还可以在这里找到 英语 场景 4: 吃棒棒糖时闪退! 用户邮件说, “当rage master吃棒棒糖时应用就闪退…” 另一用户说, “我让rage master 吃棒棒糖,没几次应用就闪退了 ...
- Flutter开发记录part1
(1)AppBar:automaticallyImplyLeading//是否带返回leading箭头 (2)非route路由页面跳转 :Navigator.of(context).push(Mate ...
- 计算机网络自顶向下第三章传输层二TCP
TCP 全双工 A-B,B-A 点对点 一对一的 TCP连接建立过程 客户首先发送一个特殊的TCP报文段,服务器用另一个特殊的TCP报文段来相应,最后,客户再用第三个特殊的报文段作为相应,前两个报文段 ...
- Codis的源码编译生成tar包
一.Go环境的安装 1.下载地址 https://golang.org/dl/2.解压 tar -zxvf go1.7.1.linux-amd64.tar.gz -C /usr/local 3.修改配 ...
- CentOS6.5环境配置笔记
CentOS6.5环境配置笔记 一.概述 服务器系统重装,配置应用运行环境 CentOS6.5 x64 二.修改密码 重新设置登录密码 $passwd 或 $passwd root 三.配置端口号及防 ...
- 【前端阅读】——《程序员思维修炼》摘记&读后感&思维导图
前言:这是一本介绍如何用脑的书,并从思维的角度(以程序员为例),介绍如何从新手成为专家.作者带领着读者(我)共同经历一次有关认知科学.神经学.学习和行为理论的旅程,探索人类大脑令人 惊奇的工作的机制, ...
- 2016.7.12 错误:syntax error at or near “(”
错误提示: 错误原因:漏了个,号.