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负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述 ...
随机推荐
- ETL之Kettle
Kettle是一款国外开源的ETL工具,纯java编写,可以在Window.Linux.Unix上运行. 说白了就是,很有必要去理解一般ETL工具必备的特性和功能,这样才更好的掌握Kettle的使用. ...
- NOI模拟题4 Problem B: 小狐狸(fox)
Solution 考虑分开统计朝向每一个方向的所有狐狸对答案的贡献. 比如说以向右为例, 我们用箭标表示每一只狐狸的方向, 用\('\)表示当前一步移动之前的每一只狐狸的位置. \[ \begin{a ...
- hosts不支持泛解析
hosts不支持泛解析,只能是一个域名对应一个IP. 如果想要实现只能用一些第三方的DNS软件做解析.
- lock与monitor的区别
1.Lock 只能对引用对象加锁 Lock锁定区间内可以对锁定值修改而不发生运行时错误,通常也会采用此种修改方式.这种方式又有点类同于使用Monitor.Wait取得资源,并对这个资源进行操作. 用法 ...
- Xocde 自动注释插件
github 地址 https://github.com/onevcat/VVDocumenter-Xcode 可以对xcode方法进行类似java那样的自动注释 源码下载下后编译运行一次 xo ...
- python tkinter GUI绘制,以及点击更新显示图片
tkinter 绘制GUI简单明了,制作一些简单的GUI足够,目前遇到的一个问题是不能同时排列显示多幅图片(目前没找到同时显示解决方法), 退而求其次,改成增加一个update按钮,每次点下按钮自动更 ...
- mysql 升序 字段值为NULL 排在后面
select * from yryz_products_t order by isnull(sort),sort;
- JAVA Eclipse开发Android如何让超出界面的部分自动显示滚动条
在原有布局的最外围添加一层ScrollView,注意原有布局的声明也要删了 <ScrollView xmlns:android="http://schemas.android.com/ ...
- PHP 变量定义及使用
php的变量前面必须有$符号,而且是解释型的弱类型语言,定义的时候不需要定义变量值的类型. $str="这是个变量"; 1.输出的时候可以用拼接字符串的方法 如:echo" ...
- 启动Nginx目录浏览功能及 让用户通过用户名密码认证访问web站点
一.启动Nginx目录浏览功能 [root@abcdocker extra]# cat w.conf server { listen 80; server_name IP地址; location / ...