gulp插件介绍

为什么使用

代码同步

browser-sync 使用方法

browser-sync-spa

gulp-livereload 实时刷新

AngularJS

eslint-plugin-angular

gulp-angular-filesort

结合使用以gulp-inject正确的顺序注入您的AngularJS应用程序文件(脚本),以摆脱所有Uncaught Error: [$injector:modulerr]。为了正确工作,每个角度文件需要具有唯一命名的模块和setter语法(带括号),即angular.module('myModule', [])。

gulp-angular-templatecache 将html模板缓存到$templateCache中

gulp-ng-annotate //是一个处理angularjs依赖注入的插件,它的用法如下

gulp.task('build-app-js', function () {
    return gulp.src('src/app/**/*.js')
        .pipe(ngAnnotate({single_quotes: true}))
        .pipe(gulp.dest(buildDir + '/js/app'));
});

正常我们写angular代码是这样子的

angular.module('app', [])
    .controller('AppCtrl', ['$scope', function($scope) {
        // 别的代码
    }])

但使用了这个插件之后,每一个依赖注入的项就不用再写两遍了,如

angular.module('app', [])
    .controller('AppCtrl', function($scope) {
        // 别的代码
    })

gulp-ng-annotate会帮我们生成带中括号的写法 ,这样子是不是节省了很多重复工作呢?尤其是在注入的服务非常多的时候,可以少写很多代码,并且也不用担心顺序有没有写错。

文件操作

gulp-filter 过滤文件

Example:https://github.com/hjzheng/CUF_meeting_knowledge_share/blob/master/2015-11-10/gulpfile.js
gulp-filter可以把stream里的文件根据一定的规则进行筛选过滤。比如gulp.src中传入匹配符匹配了很多文件,可以把这些文件pipe给gulp-filter作二次筛选,如gulp.src('/.js').pipe($.filter(/a/.js)),本来选中了所有子文件下的js文件,经过筛选后变成名为a的子文件夹下的js文件。那有人要问了,为什么不直接将需要的筛选传入gulp.src,干嘛要多筛选一步呢?这里面有两种情况:

gulp.src与$.filter中间可能需要别的处理,比如我对所有文件做了操作1以后,还需要筛选出一部分做操作2。
第二种情况就要谈到gulp-filter的另外一个特性:筛选之后还可以restore回去。比如我对所有文件做了操作1,筛选了一部分做操作2,最后要把所有的文件都拷贝到最终的位置。代码如下:

var filter = $.filter('**/a/*.js');
gulp.src('**/*.js')
    .pipe(action1())
    .pipe(filter)
    .pipe(action2())
    .pipe(filter.restore())
    .pipe(gulp.dest('dist'))

可以看到,如果没有restore这个操作,那么拷贝到最终位置的文件将只包含被过滤出来的文件,这样一restore,所有的文件都被拷贝了。

gulp-flatten 当拷贝文件时,不想拷贝目录时使用

例子:https://segmentfault.com/q/1010000004266922
gulp-flatten非常实用,可能知道别的库中flatten函数的同学已经猜到它是干嘛的了。比如gulp.src('*/.js')匹配了很多文件,包括a/b/c.js,d/e.js,f/g/h/i/j/k.js,l.js,这些文件的层级都不一样,一旦我们将这个文件pipe给$.flatten(),则所有的文件夹层级都会去掉,最终的文件将是c.js,e.js,k.js,l.js,在一些场景下还是非常有用的。

JS/CSS自动注入

gulp-replace

gulp-rev 把静态文件名改成hash的形式。

gulp-rev-append 给页面引用的静态文件增加hash后缀,避免被浏览器缓存

效果如下:

"/css/base.css" => "/dist/css/base.css?v=1d87bebe"    
"/js/mod.js" => "/dist/mod.js?v=61e0be79"    
"/images/bg.png"  => "/images/bg.png?v=35c3af8134"

gulp-rev-replace 配合 gulp-rev 使用,拿到生成的 manifest。json 后替换对应的文件名称。

gulp-useref 与 gulp-rev、gulp-rev-replace

这三个工具之所以放在一起讲,是因为它们一般都是一起使用的。它们要解决什么问题呢?通过上面的wiredep也好,gulp-inject也好,插入了一堆JS、CSS文件到HTML中,一旦部署到生产环境,这么多文件必然是要合并压缩的。光是压缩还不够,为了解决缓存问题,每次合并压缩后要给最终的文件加hash,这样每次文件内容一变动,hash也会跟着变动,就不存在浏览器依然使用缓存的老文件的问题。这样得到最终的文件以后,肯定还要将这个文件替换回HTML中去,一大堆的script和link标签替换成最终合并压缩带hash的版本。

前面啰啰嗦嗦的一大堆工作就是这三个插件要解决的问题了。首先,gulp-useref根据注释将HTML中需要合并压缩的区块找出来,对区块内的所有文件进行合并。注意:它只负责合并,不负责压缩!所以合并出来的文件我们要自行压缩,压缩以后调用gulp-rev负责在文件名后追加hash。最后调用gulp-rev-replace负责把最终的文件名替换回HTML中去。扯了大半天,还是直接上例子吧。先来看看HTML中的注释:

<!-- build:css static/styles/lib.css -->
<!-- bower:css -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:css static/styles/app.css -->
<!-- inject:css -->
<!-- endinject -->
<!-- endbuild -->
<!-- build:js static/js/lib.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:js static/js/app.js -->
<!-- inject:js -->
<!-- endinject -->
<!-- endbuild -->

gulp-useref识别的就是build开头的注释,build后面首先跟的是类型扩展名,然后后面的路径就是build区块中的所有文件进行合并后的文件路径,这个相对路径是相对于这个HTML的路径。上面的例子中我们用build区块把bower和inject进来的文件包起来,这些文件就可以被gulp-useref合并了。再来看gulp中useref相关task的定义:

var assets = $.useref.assets({searchPath: 'app/src/'});
var cssFilter = $.filter('**/*.css');
var jsAppFilter = $.filter('**/app.js');
var jslibFilter = $.filter('**/lib.js');
return gulp
    .src('index.html')
    .pipe(assets)
    .pipe(cssFilter)
    .pipe($.csso())
    .pipe(cssFilter.restore())
    .pipe(jsAppFilter)
    .pipe($.uglify())
    .pipe(getHeader())
    .pipe(jsAppFilter.restore())
    .pipe(jslibFilter)
    .pipe($.uglify())
    .pipe(jslibFilter.restore())
    .pipe($.rev())
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe($.revReplace())
    .pipe(gulp.dest('dist'));

首先一上来,先调用$.useref.assets()函数,这个函数返回一个stream,包含已经合并后的文件。可以尝试在第9行后面加上前面介绍过的gulp-print插件.pipe($.print()),打印出stream里的文件,发现就是前面HTML中4个build注释块后面的4个文件。注意这里调用的时候跟了一个searchPath的参数,它的用处就是指定从哪个路径开始寻找build区块底下的文件。比如build区块底下有这么一行<script src="static/js/a.js"></script>,那最终gulp-useref将从这个路径app/src/static/js/a.js找到这个文件。第3到5行定义了3个filter,这主要是为了后面压缩准备的。下面正式看stream的pipe流程。先选出要处理的HTML文件,然后调用刚才得到的assets得到合并后的4个文件,第10到12行筛选出合并后的CSS文件进行压缩(压缩类插件下篇文章再讲),第13到16行筛选出app.js进行压缩,第17到19行筛选出lib.js进行压缩。之所以要区别对待app.js和lib.js,是因为app.js是我们自己写的代码,压缩后要加上header(第15行,使用前面介绍过的gulp-header插件),而lib.js是第三方的各种库,直接压缩即可。后面调用gulp-rev给压缩后的4个文件加hash,然后调用assets.restore()将src源换回HTML文件,这是为了后面调用$.useref(),因为$.useref()做替换的src源是HTML文件,同样后面调用gulp-rev-replace将带hash的文件替换回HTML,它要求的src源也必须是HTML文件。这里的顺序很重要,因为这几个插件接受的源不一样,gulp-rev接受的是JS、CSS文件,而gulp-useref和gulp-rev-replace接受的是HTML。还有一个问题:gulp-rev-replace是怎么知道gulp-rev进行hash前后的文件名对应关系呢?其实gulp-rev会生成一个manifest的文件,内容是类似下面的JSON:

{
    "static/styles/lib.css": "static/styles/lib-d41d8cd98f.css"
    "static/js/lib.js": "static/js/lib-273c2cin3f.js"
}

当然这个文件默认是不会生成在文件系统里的,可以通过.pipe($.rev.manifest())将这个文件保存到本地。有了这个文件,gulp-rev-replace甚至可以脱离gulp-rev独立工作哦!

gulp-inject //文件的注入

个人理解: 就是把 css,js全部利用这个插件添加到 index.html 页面里,不需要手动去添加

<script src="../bower_components/jquery/dist/jquery.js"></script>
<link src="css/index.css"/>
<!-- inject:js -->  
<script src="scripts/app.js"></script>  
<!-- endinject -->  

压缩

gulp-zip

gulp-mini-css 压缩css使用的

gulp-mini-html

gulp-useref 用uglify压缩js

url:https://www.npmjs.com/package/gulp-useref
说到优化的时候,我们需要想到:压缩,拼接。也就是减少体积和HTTP次数。

开发者面临的主要问题是很难按照正确的顺序合并文件。

<body>
  <!-- other stuff -->
  <script src="js/lib/a-library.js"></script>
  <script src="js/lib/another-library.js"></script>
  <script src="js/main.js"></script>
</body>

由于文件路径的的不同,使用 https://www.npmjs.com/package/gulp-concat 等插件非常困难。

庆幸的是, gulp-useref 解决了这个问题。

gulp-useref会将多个文件拼接成单一文件,并输出到相应目录。

<!-- build:<type> <path> -->
... HTML Markup, list of script / link tags.
<!-- endbuild -->

可以是js,css,或者remove。如果你设为remove,Gulp将不会生成文件。

指定产出路径。

我们想最终产出main.min.js。可以这样写:

<!--build:js js/main.min.js -->
<script src="js/lib/a-library.js"></script>
<script src="js/lib/another-library.js"></script>
<script src="js/main.js"></script>
<!-- endbuild -->

gulp-uglify //压缩、混淆js文件用的

基本使用

var gulp = require('gulp'),
    uglify = require('gulp-uglify');
 
gulp.task('jsmin', function () {
    gulp.src('src/js/index.js')
        .pipe(uglify())
        .pipe(gulp.dest('dist/js'));
});

压缩多个js文件

var gulp = require('gulp'),
    uglify = require('gulp-uglify');
 
gulp.task('jsmin', function () {
    gulp.src(['src/js/index.js','src/js/detail.js']) //多个文件以数组形式传入
        .pipe(uglify())
        .pipe(gulp.dest('dist/js'));
});

匹配符“!”,“”,“*”,“{}”

var gulp = require('gulp'),
    uglify= require('gulp-uglify');
 
gulp.task('jsmin', function () {
    //压缩src/js目录下的所有js文件
    //除了test1.js和test2.js(**匹配src/js的0个或多个子文件夹)
    gulp.src(['src/js/*.js', '!src/js/**/{test1,test2}.js']) 
        .pipe(uglify())
        .pipe(gulp.dest('dist/js'));
});

指定变量名不混淆改变

var gulp = require('gulp'),
    uglify= require('gulp-uglify');
 
gulp.task('jsmin', function () {
    gulp.src(['src/js/*.js', '!src/js/**/{test1,test2}.js'])
        .pipe(uglify({
            //mangle: true,//类型:Boolean 默认:true 是否修改变量名
            mangle: {except: ['require' ,'exports' ,'module' ,'$']}//排除混淆关键字
        }))
        .pipe(gulp.dest('dist/js'));
});

gulp-uglify其他参数 具体参看

var gulp = require('gulp'),
    uglify= require('gulp-uglify');
 
gulp.task('jsmin', function () {
    gulp.src(['src/js/*.js', '!src/js/**/{test1,test2}.js'])
        .pipe(uglify({
            mangle: true,//类型:Boolean 默认:true 是否修改变量名
            compress: true,//类型:Boolean 默认:true 是否完全压缩
            preserveComments: 'all' //保留所有注释
        }))
        .pipe(gulp.dest('dist/js'));
});

gulp-css-base64

把小图片的URL替换为Base64编码图片。

gulp-imagemin 压缩图片

压缩图片文件(包括PNG、JPEG、GIF和SVG图片)
github:https://github.com/sindresorhus/gulp-imagemin

基本使用

var gulp = require('gulp'),
    imagemin = require('gulp-imagemin');
 
gulp.task('testImagemin', function () {
    gulp.src('src/img/*.{png,jpg,gif,ico}')
        .pipe(imagemin())
        .pipe(gulp.dest('dist/img'));
});

gulp-imagemin其他参数 具体参看

var gulp = require('gulp'),
    imagemin = require('gulp-imagemin');
 
gulp.task('testImagemin', function () {
    gulp.src('src/img/*.{png,jpg,gif,ico}')
        .pipe(imagemin({
            optimizationLevel: 5, //类型:Number  默认:3  取值范围:0-7(优化等级)
            progressive: true, //类型:Boolean 默认:false 无损压缩jpg图片
            interlaced: true, //类型:Boolean 默认:false 隔行扫描gif进行渲染
            multipass: true //类型:Boolean 默认:false 多次优化svg直到完全优化
        }))
        .pipe(gulp.dest('dist/img'));
});

深度压缩图片

var gulp = require('gulp'),
    imagemin = require('gulp-imagemin'),
    //确保本地已安装imagemin-pngquant [cnpm install imagemin-pngquant --save-dev]
    pngquant = require('imagemin-pngquant');
 
gulp.task('testImagemin', function () {
    gulp.src('src/img/*.{png,jpg,gif,ico}')
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],//不要移除svg的viewbox属性
            use: [pngquant()] //使用pngquant深度压缩png图片的imagemin插件
        }))
        .pipe(gulp.dest('dist/img'));
});

只压缩修改的图片。

压缩图片时比较耗时,在很多情况下我们只修改了某些图片,没有必要压缩所有图片,使用”gulp-cache”只压缩修改的图片,没有修改的图片直接从缓存文件读取(C:\Users\Administrator\AppData\Local\Temp\gulp-cache)。

var gulp = require('gulp'),
    imagemin = require('gulp-imagemin'),
    pngquant = require('imagemin-pngquant'),
    //确保本地已安装gulp-cache [cnpm install gulp-cache --save-dev]
    cache = require('gulp-cache');
    
gulp.task('testImagemin', function () {
    gulp.src('src/img/*.{png,jpg,gif,ico}')
        .pipe(cache(imagemin({
            progressive: true,
            svgoPlugins: [{removeViewBox: false}],
            use: [pngquant()]
        })))
        .pipe(gulp.dest('dist/img'));
});

注意:它只负责合并,不负责压缩

编译

gulp-sass 编译sass用的

gulp-sourcemaps 编译sass时生成额外的.map文件用的

代码分析

gulp-eslint

工具

gulp-load-plugins 模块化管理。可以加载package.json文件中所有的gulp模块

gulp-autoprefixer 自动添加css前缀

基本用法

var gulp = require('gulp'),
    autoprefixer = require('gulp-autoprefixer');
 
gulp.task('testAutoFx', function () {
    gulp.src('src/css/index.css')
        .pipe(autoprefixer({
            browsers: ['last 2 versions', 'Android >= 4.0'],
            cascade: true, //是否美化属性值 默认:true 像这样:
            //-webkit-transform: rotate(45deg);
            //        transform: rotate(45deg);
            remove:true //是否去掉不必要的前缀 默认:true 
        }))
        .pipe(gulp.dest('dist/css'));
});

gulp-autoprefixer的browsers参数详解

  • last 2 versions: 主流浏览器的最新两个版本
  • last 1 Chrome versions: 谷歌浏览器的最新版本
  • last 2 Explorer versions: IE的最新两个版本
  • last 3 Safari versions: 苹果浏览器最新三个版本
  • Firefox >= 20: 火狐浏览器的版本大于或等于20
  • iOS 7: IOS7版本
  • Firefox ESR: 最新ESR版本的火狐
  • 5%: 全球统计有超过5%的使用率

gulp-gh-pages 使用gulp来把markdown生成html文档并上传到git pages上

chalk

del 清除文件

gulp-plumber

gulp 的错误处理有点坑,假如发生错误进程就挂了。相对的解决办法不少,但是这个是我个人比较推荐的,比特么在容易出错的地方写错误监听靠谱。所以这个插件可以阻止 gulp 插件发生错误导致进程退出并输出错误日志。

estraverse 遍历函数

gulp-prompt 将交互式控制台提示添加到gulp

gulp-protractor

gulp-rename 修改文件名称。比如有时我们需要把app.js改成app.min.js,瞬间高级了

gulp-shell

gulp-size 显示您的项目的规模

gulp-util

gulp-util带有很多方便的函数,其中最常用的应该就是log了。$.util.log()支持传入多个参数,打印结果会将多个参数用空格连接起来。它与console.log的区别就是所有$.util.log的结果会自动带上时间前缀。另外,它还支持颜色,如$.util.log($.util.colors.magenta('123'));打印出来的123是品红色的。其实$.util.colors就是一个 chalk的实例,而chalk是专门用来处理命令行打印着色的一个工具。

http-proxy-middleware

lodash

main-bower-files

uglify-save-license

wiredep

wiredep就是wire dependence的意思,它的作用就是把bower.json中声明的dependence自动的包含到HTML中去。
要插入文件,wiredep需要解决两个问题:

插入的位置:wiredep通过识别HTML中的注释来识别插入位置,如

<!-- bower:css -->
<!-- endbower -->
<!-- bower:js -->
<!-- endbower -->

不同类型的文件被插入到不同的区块。

插入什么文件:要插入的文件列表自然来自bower.json,每个bower安装的依赖库,根目录下边都有一个自己的bower.json文件,其中的main字段指明了使用这个库需要包含的文件,wiredep最终包含的文件列表就来自这个字段。有些情况下,库自身的bower.json的main字段可能会多包含文件或少包含文件,如果想要定制这个列表,则可以在自己的bower.json中使用overrides字段,如下面的代码覆盖了mdi这个库的main字段。

"overrides": {
  "mdi": {
    "main": [
      "css/materialdesignicons.css"
    ]
  }
},

wiredep插件支持很多参数,常用的主要有两个:

bowerJson:指定bower.json的内容,注意这个字段不是bower.json文件的位置,这个参数需要使用require后的结果赋值:require('bower.json')。
directory:指定存放bower安装后的依赖包的路径,通常是bower_components。注意最终插入到HTML中的文件列表的路径是index.html文件相对于本文件夹的相对路径。
使用wiredep也比较简单,直接把它传入到stream中即可,如gulp.src('index.html').pipe(wiredep(options))。

gulp-order 对src中的文件按照指定顺序进行排序

本地整理,留作备份。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容