gulp进阶- 自定义gulp插件_前端开发者

前端开发者丨前端开发
gulp进阶- 自定义gulp插件gulp已经成为很多项目的标配了, gulp的插件生态也十分繁荣, 截至2015 .1 .5, npm上已经有10190款gulp插件供我们使用。 我们完全可以傻瓜式地搭起一套构建。 然而, 我们经常会遇到一种情况, 我们好不容易按照文档传入对应的参数调用了插件, 却发现结果不如预期, 这时候我们就要一点点去排错, 这就要求我们对gulp插件的工作原理有一定的了解。 本文以实现一个gulp插件为例, 讲解一下gulp插件是如何工作的。 需求描述通常, 我们的构建资源jscsshtml以及其它的一些资源文件, 在开发或发布阶段, jscss会经过合并, 压缩, 重命名等处理步骤。 有些场景下, 我们不能确定经过构建后生成jscss的名称或者数量, 如此就不能在html文件中写死资源的引用地址, 那么该如何实现一个Gulp的插件用以将最终生成的资源文件/ 地址注入到HTML中呢? 假设我们需要实现的插件是这样使用方式:
<html>
<head>
<!–InlineResource:.css$–>
</head>
<body>
<!–InlineResource:.js$–>
</body>
</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我们需要这边配置:gulp.task(‘dist’,
function () { return gulp.src(‘index.html’) .pipe(InjectResources( gulp.src([‘*.js’, ‘*.css’]) .pipe(hash(/*添加MD5作为文件名*/
))
)).pipe(gulp.dest(‘dist’))
}) 1 2 3 4 5 6 7 8 gulp.task(‘dist’, function () {
returngulp.src(‘index.html’).
pipe(InjectResources(gulp.src([‘*.js’,’*.css’]).pipe(hash( /*添加MD5作为文件名*/ )))).pipe(gulp.dest(‘dist’))
}) 这里简单介绍下其中的一些方法与步骤: 我们要关心的是第2点: 如何接所有的资源文件并完成注入? 我们可以将该逻辑分成4个步骤获取所有的js / css资源 获取所有的HTML文件 定位HTML中的依赖声明 匹配所依赖的资源
生成并注入依赖的资源标签在开编之前, 我们需要依赖一个重要的第三方库: map – streammap – stream 用于获取当前流中的每一个文件数据, 并且修改数据内容。 步骤1(JS / CSS资源) module.exports = function (resourcesStream) { // step 1: TODO => 这里要获取所有的js/css资源 } 1 2 3 module . exports = function ( resourcesStream ) { // step
1: TODO=>这里要获取所有的js/css资源
}
资源流会作为参数的形式传给InjectResources方法, 在此通过一个异步的实例方法获取所有的文件对象, 放到一个资源列表:
var resources = []
function getResources(done) {
if (resources) returndone(resources) // 由于下面的操作是异步的,此处要有锁… resourcesStream.pipe(mapStream(function (data, cb) { resources.push(data)
cb(null,data)
})).on(‘end’, function () {
done(resources)
})
}
1 2 3 4 5 6 7 8 9 10 11 12
var resources = []
function
getResources(done) {
if (resources) returndone(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方法, 第二个参数可以用于替换当前处理的文件对象到此, 我们就完成了第一步的封装啦! module.exports = function (resourcesStream) { // step 1: function getResources () { … } } 1 2 3 4 5 6 module . exports = function ( resourcesStream
) { // step 1: function getResources ( ) { . . . } }步骤2 (HTML文件)module.exports = function (resourcesStream) { // step 1:
✔︎ // step 2: TODO => 获取当前流中的所有目标HTML文件 return mapStream(function (data, cb) { }) } 1 2 3 4 5 6 7 8 module . exports = function
(resourcesStream) { // step 1: ✔︎ // step 2: TODO => 获取当前流中的所有目标HTML文件 return mapStream ( function ( data , cb ) { } )
}
InjectResources插件方法会返回一个WritableStream实例, 用于接收并处理流到InjectResources的HTML文件, mapStream的返回值就是一个writablestream。 此时, mapStream的处理方法拿到的data就是一个HTML文件对象, 接下来进行内容处理。 步骤3
(定位依赖) module.exports = function (resourcesStream) { // step 1: ✔︎ // step 2: ✔ return mapStream(function (data, cb) { var
html=data.contents.toString() // step 3: TODO => 获取HTML中的资源依赖声明 }) } 1 2 3 4 5 6 7 8 9 10 module . exports = function (
resourcesStream) {// step 1: ✔︎ // step 2: ✔ return mapStream ( function ( data , cb ) { var html = data . contents . toString
() // step 3: TODO => 获取HTML中的资源依赖声明 } ) }我们拿到的data是一个vinyl对象,contents属性是文件的内容,类型可能是Buffer也可能是String, 通过toStraing()后可以获取到字符串内容。所有的依赖声明都有InlineResource关键词,简单点的做法,可以通过正则来定位并替换HTML中的资源依赖:html.replace(/
<!–InlineResource:(.*?)–>/g,function(expr,fileRegexpStr){// fileRegexp是用以匹配依赖资源的正则字符串 }) 1 2 3 html . replace ( /
<!–InlineResource:(.*?)–>/g,function(expr,fileRegexpStr){// fileRegexp是用以匹配依赖资源的正则字符串 } )到此,我们完成了资源依赖的定位,下一步将是获取所依赖的资源用以替换。步骤4 (依赖匹配)我们将通过步骤1定义的
getResources方法获取所需的资源文件: module.exports=function(resourcesStream){// step 1: ✔︎ // step 2: ✔ return mapStream(function
(data, cb) { // step 3: ✔ getResources(function (list) { html.replace(depRegexp, function (expr, fileRegexpStr) { var fileRegexp
=newRegExp(fileRegexpStr) // step 4: TODO => 获取匹配的依赖 }) }) }) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 module . exports =
function(resourcesStream){// step 1: ✔︎ // step 2: ✔ return mapStream ( function ( data , cb ) { // step 3: ✔ getResources
(function (list) {
html.replace(depRegexp,function(expr,fileRegexpStr){
varfileRegexp=newRegExp(fileRegexpStr) // step 4: TODO => 获取匹配的依赖 } ) } ) } ) }由于 getResources 是异步方法,因此需要把替换处理逻辑包裹在 getResources 的回调方法中根据依赖声明中的正则表达式,对资源列表一一匹配:function
matchingDependences(list,regexp) {
vardeps= [] list.forEach(function(file){
varfpath=file.path
if (fileRegexp.test(fpath)) {
deps.push(fpath)
}
}) returndeps
}
12345678910
functionmatchingDependences(list,regexp){
vardeps= [] list.forEach(function(file){
varfpath=file.path
if (fileRegexp.test(fpath)) {
deps.push(fpath)
}
}) returndeps
}
到此只差最后一步, 将资源转换为HTML标签并注入到HTML中步骤5(资源转换/ 依赖注入) module.exports=function(resourcesStream){// step 1:
✔︎ // step 2: ✔ return mapStream(function (data, cb) { // step 3: ✔ // step 4: ✔ // … html.replace(depRegexp, function
(expr, fileRegexpStr) {
vardeps=matchingDependences(list,fileRegexpStr) // step 5: 文件对象转换为HTML标签 }) }) } 1 2 3 4 5 6
789101112131415module.exports=function(resourcesStream){// step 1: ✔︎ // step 2: ✔ return mapStream ( function
(data, cb) { // step 3: ✔ // step 4: ✔ // … html . replace ( depRegexp , function ( expr , fileRegexpStr ) { var deps
=matchingDependences(list,fileRegexpStr) // step 5: 文件对象转换为HTML标签 } ) } ) }接下来的定义一个transform方法,用于将路径列表转换为HTML的资源标签列表,其中引入了
path模块用于解析获取文件路径的一些信息, 该模块是node内置模块。
varpath=require(‘path’)
functiontransform(deps){
returndeps.map(function(dep){
varext=path.extname(dep) switch (ext) {
case ‘js’:
‘ <script>
‘ + dep + ‘</script>’ break case ‘css’: return ‘<linkrel=”stylesheet”
href=”‘ + dep + ‘”>’ break } return ‘
‘ }).join(‘
‘) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var path = require ( ‘
path’ ) function transform
(deps) {
return deps.map(function (dep) {
varext=path.extname(dep) switch (ext) {
case ‘js’:
‘ <script>
‘ + dep + ‘</script>’ break case ‘css’ : return ‘<linkrel=”stylesheet”
href=”‘ + dep + ‘”>’ break } return ‘
‘ } ) . join ( ‘
‘ ) }最终,我们将标签列表拼接为一个字符串来HTML中的依赖声明(注入):html = html.replace(depRegexp, function (expr, fileRegexpStr) {
vardeps=matchingDependences(list,fileRegexpStr) // step 5: 文件对象转换为HTML标签 return transform(deps) }) // html文件对象 data.contents
=newBuffer(html) // 把修改后的文件对象放回HTML流中 cb(null, data) 1 2 3 4 5 6 7 8 9 html = html . replace ( depRegexp , function ( expr
, fileRegexpStr) {
var deps = matchingDependences(list, fileRegexpStr) // step 5: 文件对象转换为HTML标签 return transform ( deps
)
}) // html文件对象 data . contents = new Buffer ( html ) // 把修改后的文件对象放回HTML流中 cb ( null , data )到此也就完整地实现了一个拥有基本注入功能的插件~~~~~~One
MoreThing通过上面实现的示例步骤, 可以清楚了解到gulp插件的工作原理。 但要做一个易用/ 可定制性高的插件, 我们还要继续完善一下。
前端开发者丨前端开发
» 本文来自:前端开发者 » 《gulp进阶- 自定义gulp插件_前端开发者》
» 本文链接地址:https://www.rokub.com/2203.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!