gulp已经成为很多项目的标配了,gulp的插件生态也十分繁荣,截至2015.1.5,npm上已经有10190款gulp插件供我们使用。我们完全可以傻瓜式地搭起一套构建。
然而,我们经常会遇到一种情况,我们好不容易按照文档传入对应的参数调用了插件,却发现结果不如预期,这时候我们就要一点点去排错,这就要求我们对gulp插件的工作原理有一定的了解。本文以实现一个gulp插件为例,讲解一下gulp插件是如何工作的。
需求描述
通常,我们的构建资源为js/css/html以及其它的一些资源文件,在开发或发布阶段,js/css会经过合并,压缩,重命名等处理步骤。
有些场景下,我们不能确定经过构建后生成js/css的名称或者数量,如此就不能在HTML文件中写死资源的引用地址,那么该如何实现一个Gulp的插件用以将最终生成的资源文件/地址注入到HTML中呢?
假设我们需要实现的插件是这样使用方式:
1 2 3 4 5 6 7 8 |
<html> <head> <!--InlineResource:\.css$--> </head> <body> <!--InlineResource:\.js$--> </body> </html> |
我们通过一个HTML注释用以声明需要依赖的资源,InlineResource 是匹配的关键词,”:”做为分割,/*.css$/,/*.js$/ 是声明要依赖的文件的正则匹配。
在gulpfile.js我们需要这边配置:
1 2 3 4 5 6 7 8 |
gulp.task('dist', function () { return gulp.src('index.html') .pipe(InjectResources( gulp.src(['*.js', '*.css']) .pipe(hash(/*添加MD5作为文件名*/)) )) .pipe(gulp.dest('dist')) }) |
这里简单介绍下其中的一些方法与步骤:
- gulp.src(‘index.html’) 会读取文件系统中当前目录下的index.html,并生成一个可读的Stream,用于后续的步骤消费
- InjectResources(stream) 是我们将要实现的插件,它接受一个参数用以获取要注入到HTML中的JS/CSS,此参数应该是一个 Stream 实例,用生成一个Stream实例,用于接收并处理上一步流进来的数据
- hash(options) 是一个第三方插件,用于往当前流中的文件名添加md5串,如:gulp-hash
- gulp.dest(‘dist’) 用于将注入资源后的HTML文件生成到当前目录下
我们要关心的是第2点:如何接所有的资源文件并完成注入?
我们可以将该逻辑分成4个步骤
- 获取所有的js/css资源
- 获取所有的HTML文件
- 定位HTML中的依赖声明
- 匹配所依赖的资源
- 生成并注入依赖的资源标签
在开编之前,我们需要依赖一个重要的第三方库:map-stream
map-stream 用于获取当前流中的每一个文件数据,并且修改数据内容。
步骤1 (JS/CSS资源)
1 2 3 |
module.exports = function (resourcesStream) { // step 1: TODO => 这里要获取所有的js/css资源 } |
资源流会作为参数的形式传给InjectResources方法,在此通过一个异步的实例方法获取所有的文件对象,放到一个资源列表:
1 2 3 4 5 6 7 8 9 10 11 12 |
var resources = [] function getResources(done) { if (resources) return done(resources) // 由于下面的操作是异步的,此处要有锁... resourcesStream.pipe(mapStream(function (data, cb) { resources.push(data) cb(null, data) })) .on('end', function () { done(resources) }) } |
- mapStream的处理方法中获取到的data是由gulp.src生成的vinyl对象,代表了一个文件
- 每一个stream都会在接受后抛出end事件
Note: mapStream的处理方法中的cb方法,第二个参数可以用于替换当前处理的文件对象
到此,我们就完成了第一步的封装啦!
1 2 3 4 5 6 |
module.exports = function (resourcesStream) { // step 1: function getResources () { ... } } |
步骤2 (HTML文件)
1 2 3 4 5 6 7 8 |
module.exports = function (resourcesStream) { 我们就要一点点去排错,这就要求我们对gulp插件的工作原理有一定的了解。本文以实现一个gulp插件为例,讲解一下gulp插件是如何工作的。
需求描述通常,我们的构建资源为js/css/html以及其它的一些资源文件,在开发或发布阶段,js/css会经过合并,压缩,重命名等处理步骤。 有些场景下,我们不能确定经过构建后生成js/css的名称或者数量,如此就不能在HTML文件中写死资源的引用地址,那么该如何实现一个Gulp的插件用以将最终生成的资源文件/地址注入到HTML中呢? 假设我们需要实现的插件是这样使用方式:
我们通过一个HTML注释用以声明需要依赖的资源,InlineResource 是匹配的关键词,”:”做为分割,/*.css$/,/*.js$/ 是声明要依赖的文件的正则匹配。 在gulpfile.js我们需要这边配置:
这里简单介绍下其中的一些方法与步骤:
我们要关心的是第2点:如何接所有的资源文件并完成注入? 我们可以将该逻辑分成4个步骤
在开编之前,我们需要依赖一个重要的第三方库:map-stream map-stream 用于获取当前流中的每一个文件数据,并且修改数据内容。 步骤1 (JS/CSS资源)
资源流会作为参数的形式传给InjectResources方法,在此通过一个异步的实例方法获取所有的文件对象,放到一个资源列表:
到此,我们就完成了第一步的封装啦!
步骤2 (HTML文件)
|