gulp自动化构建工具快速入门和实战
来源:互联网 发布:一斩必杀·村雨淘宝 编辑:程序博客网 时间:2024/06/06 03:03
前端工作流-自动化工具Gulp
易于使用
通过代码优于配置的策略,Gulp 让简单的任务简单,复杂的任务可管理。
构建快速
利用 Node.js 流的威力,你可以快速构建项目并减少频繁的 IO 操作。
插件高质
Gulp 严格的插件指南确保插件如你期望的那样简洁高质得工作。
易于学习
通过最少的 API,掌握 Gulp 毫不费力,构建工作尽在掌握:如同一系列流管道。
为什么使用gulp?
当下的wap开发不仅仅是html+css+js,还有less、coffeeScript等。
要运行,就需要从开发到生产的转化,这是很重复的东西。可以使用自动化工具来完成。
Less等格式良好,但是用户并不需要这些注释和格式,只要运行良好即可。转化成css文件更好。
重复工作:
- 预处理语言的编译;
- js css html 压缩混淆
- 图片体积优化
除了gulp之外,还有一些类似的自动化工具,比如grunt、webpack。
使用上、效率上gulp更优!
为什么使用Gulp而不使用Grunt?
构建前端自动化的工具有很多Grunt, Brunch, Broccoli…… 而目前过内最流行的属于Grunt,那为什么选择Gulp来代替Grunt?
我简单的总结了以下3点:
- 简洁:Gulp侧重“代码优于配置”(code over configuration)。最直观的感受,更为简单和清晰,不需要像Grunt一样写一堆庞大的配置文件。
- 高效:Gulp基于Node Streams(流)来构建任务,避免磁盘反复I/O(读取/写入)。每个任务都是单独执行(坚持做一件事并且做好它),这使得它速度更快、更为纯粹。
- 易学:Gulp核心API只有4个。简洁的API易于上手,学习过程比较平滑。
Gulp的核心API只有4个:src、dest、task、watch
gulp.src(globs[, options]):指明源文件路径
- globs:路径模式匹配;
- options:可选参数;
gulp.dest(path[, options]):指明处理后的文件输出路径
path:路径(一个任务可以有多个输出路径);
options:可选参数;
gulp.task(name[, deps], fn):注册任务
name:任务名称(通过 gulp name 来执行这个任务);
deps:可选的数组,在本任务运行中所需要所依赖的其他任务(当前任务在依赖任务执行完毕后才会执行);
fn:任务函数(function方法);
gulp.watch(glob [, opts], tasks)
:监视文件的变化并运行相应的任务glob:路径模式匹配;
opts:可以选配置对象;
taks:执行的任务;
在我使用Gulp后,就明显感觉Grunt配置很是复杂。
安装gulp
gulp官网:http://www.gulpjs.com.cn/, 用自动化构建工具增强你的工作流程!
安装node.js
- node.js给前端掀起了一场工业革命。
- 如果访问失败,请使用http://npm.taobao.org(这是一个完整 npmjs.org 镜像),该页面有怎么使用的命令:$ npm install -g cnpm –registry=https://registry.npm.taobao.org
- 安装完使用命令行工具(cmd、PowerShell、git等)测试版本号 node -v,版本号为v4.3.1,测试npm版本号npm -v,2.14.12
- npm3以前的版本文件依赖是层级依赖,npm3以后的依赖关系改为平行依赖;
安装 gulp 命令行工具
npm -install -g gulp
- 其中-g参数,指定全局安装
- 测试是否安装成功:
gulp -v
,输出CLI version 3.9.1
翻墙:vpn、lantern
使用gulp
初始化gulp项目
- 在网站根目录建立文件夹
gulp_demo
- 命令行进入该目录,输入
npm init
,然后一路回车确认,该目录中产生一个package.json
文件。 - 除了全局安装,还要本地安装一次,
npm install --save-dev gulp
,参数save是保存到json文件; - 可见在gulp_demo中又多了一个
node_modules
文件夹,其下gulp/node_modules/
中是依赖的包;
- 在网站根目录建立文件夹
建立并运行第一个任务
建立文件
gulp_demo/gulpfile.js
,这个名字是固定的!文件内容如下:'use strict';//载入gulp核心包const gulp = require('gulp');//gulp是用来执行一些重复性操作的,//一般我们将这些重复性操作划分为不同的任务//如何定义一个任务//第一个参数是任务,第二个参数是任务的执行体gulp.task('hello',function(){ console.log('hello world, gulp!'); //这里编写一些重复性的流程});//使用命令行运行任务
使用命令行进入该文件夹,运行命令名:gulp hello,回车输出:
Jimmy@Jimmy-PC MINGW32 /c/xampp/htdocs/gulp_demo$ gulp hello[20:00:31] Using gulpfile C:\xampp\htdocs\gulp_demo\gulpfile.js[20:00:31] Starting 'hello'...hello world, gulp![20:00:31] Finished 'hello' after 88 μs
我们注意到,已经输出了’hello world, gulp!’
gulp基础API
gulp原生API一共四个:.src .pipe .watch .dest,其他则是第三方插件提供功能。
最简单的是拷贝任务,比如,把一个文件从
src/index.html
拷贝到dest目录,在刚才的gulpfile.js
文件夹后面接着写:
// 拷贝文件 任务gulp.task('dest',function(){ //获取文件 gulp.src('src/index.html').pipe(gulp.dest('dist/')); //基本就是照着.pipe().pie()...,构成了一个流水线。});
- 把所有html文件从src拷贝到dest目录,只需要使用*.html通配符即可:
// 拷贝文件 任务gulp.task('dest',function(){ //获取文件 gulp.src('src/*.html').pipe(gulp.dest('dist/')); //基本就是照着.pipe().pipe()...,构成了一个流水线。});
把所有文件都从src拷贝到dest目录,则使用
*.*
通配符。- 但是这样是取不到子目录中的文件的,使用
*/*.*
即可。 - 上述通配符只能统配一级目录,如果目录超过一级怎么办?使用
\*\*/\*.\*
,在gulp中2个\*
表示递归目录。
- 但是这样是取不到子目录中的文件的,使用
更多的globs正则匹配语法,参考其Glob Primer部分。
- src/*
- src/*/*
- src/**/*
- src/*.jpg
- src/*.{jpg|png}
- 多个globs可以使用数组:
- [‘src/*.{jpg,png}’, ‘a/a.html’]
- 排除语句: !demo.html
默认任务是名字为default的任务,运行时直接输入gulp即可运行。
// 默认任务gulp.task('default',function(){ console.log('hello world, from default!');});
- watch命令:监视文件是否变化,如果变化,则自动执行任务
// 默认任务gulp.task('default',function(){ console.log('hello world, from default!'); //当src目录的文件发生变化时,自动执行后面的任务 gulp.watch('src/*', ['dest']);});
- 使用命令行执行gulp后,命令并没有立刻结束,在src/下的文件发生修改时会继续自动执行。
第三方插件
编译less文件
先定义src/style.less文件:
@baseColor:#f40;body{ background-color:@baseColor; div{ height:100px; /*some comment*/ }}
接着安装less转css的gulp插件:npm install gulp-less –save
使用说明在https://www.npmjs.com/package/gulp-less在gulpfile.js中写任务:
//载入less模块var less=require('gulp-less');// 把less编译成css文件gulp.task('style',function(){ gulp.src('src/**/*.less') .pipe(less()) //让less转换为css .pipe(gulp.dest('dist/css'));});
运行该任务:
gulp style
,随后可见在dist/css/style.css
文件。body { background-color: #f40;}body div { height: 100px; /*some comment*/}
2. 自动化监视less文件
+ 继续向gulpfile.js中添加任务:
``` // 监视less文件 gulp.task('watch', function(){ gulp.watch('src/**/*.less',['style']); }); ```+ 然后命令行启动该任务:gulp watch+ 然后修改less文件的时候,dist中就立刻编译;+ 这样使用less才爽!
3. 小结:如何使用gulp插件?
+ 首先有一个需求;
+ 然后是大npmjs.org或github上搜索相关包;
+ 根据官方地址和基本使用方法做demo练习;
+ 详细看API。
+ 常用插件 * 编译 Less: gulp-less * 编译 Jade: gulp-jade * 创建本地服务器:[gulp-commect](https://www.npmjs.com/package/gulp-connect) * 实时预览 * 合并文件:[gulp-concat](https://www.npmjs.com/package/gulp-concat) * 最小化 js 文件:[gulp-uglify](https://www.npmjs.com/package/gulp-uglify) * 重命名文件:[gulp-rename](https://www.npmjs.com/package/gulp-rename) * 最小化 css 文件:[gulp-minify-css](https://www.npmjs.com/package/gulp-minify-css) * 压缩 html 文件:[gulp-minify-html](https://www.npmjs.com/package/gulp-minify-html) * 最小化图像:[gulp-imagemin](https://www.npmjs.com/package/gulp-imagemin)
4. 另一个插件实例:
gulp-connect创建本地服务器
- 安装模块npm install gulp-connect –save–dev
- 在gulpfile.js中继续写任务:
var connect = require('gulp-connect');gulp.task('connect', function() { connect.server({ root: 'app', livereload: true });});gulp.task('html', function () { gulp.src('./app/*.html') .pipe(connect.reload());});gulp.task('watch', function () { gulp.watch(['./app/*.html'], ['html']);});gulp.task('default', ['connect', 'watch']);
- 建立app/index.html文件,随便写内容;
- 运行该任务:gulp,输出文字提示可以访问的地址:http://localhost:8080
- 访问该地址,可见该文件的内容。说明服务器正常启动!
- 但是,更新index.html文件内容后,只有命令行在变化,网页没更新!!(暂时没找到原因)
======================================
常见插件使用
1. 构建项目目录结构(Directory Structure Build)
- my-gulp(项目文件夹)
- node_modules Gulp组件目录
- dist 发布环境
- css 编译后的CSS文件
- etc…
- images 压缩后的图片文件
- etc…
- js 编译后的JS文件
- etc…
- html 静态文件
- src 开发环境
- sass SASS文件
- etc… - images 图片文件
- etc… js JS文件
- etc…- gulpfile.js Gulp任务文件
基础配置:
gulp.task('html', function() {return gulp.src('src/**/*.html') // 指明源文件路径、并进行文件匹配.pipe('dist'); // 输出路径});
执行命令:
gulp html
2 样式处理(CSS Task)
CSS预处理/Sass编译 ( gulp-ruby-sass ) :
相比较glup-sass而言,速度会稍许慢点,但功能更多并且稳定。
安装SASS:
像Gulp基于Node.js一样,Sass基于Ruby环境,所以我们先去官网下载并安装 Ruby (在安装的时候,请勾选 Add Ruby executables to your PATH 这个选项,添加环境变量,不然以后使用编译软件的时候会提示找不到ruby环境)。
安装完ruby之后,在开始菜单中,找到刚才我们安装的ruby,打开 Start Command Prompt with Ruby
- 然后直接在命令行中输入 gem install sass 按回车键确认,等待一段时间就会提示你sass安装成功。
注:
由于近期墙的比较严重,如果安装失败,请使用淘宝的Ruby镜像。具体操作方法请参考 淘宝RubyGems镜像安装 sass 。
安装命令:
npm install gulp-ruby-sass --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var sass = require('gulp-ruby-sass'); // sass/scss编译gulp.task('sass', function () {return sass('src/sass', { style: 'compressed' }) // 指明源文件路径、并进行文件匹配(style: 'compressed' 表示输出格式).on('error', function (err) { console.error('Error!', err.message); // 显示错误信息}).pipe(gulp.dest('dist/css')); // 输出路径});
执行命令:
gulp sass
插件提供4种输出格式:
nested:嵌套缩进的css代码,它是默认值。
expanded:没有缩进的、扩展的css代码。
compact:简洁格式的css代码。
compressed:压缩后的css代码。
注:使用前清看清 gulp-ruby-sass
写法,不要直接拿 gulp-sass 的写法来套用,两者并不完全相同。
3 脚本压缩&重命名(javascript Task)
JS文件压缩( gulp-uglify ):
使用uglify引擎压缩JS文件。
安装命令:
npm install gulp-uglify --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var uglify = require('gulp-uglify'); // js压缩gulp.task('script', function() {return gulp.src('src/js/*.js') // 指明源文件路径、并进行文件匹配.pipe(uglify({ preserveComments:'some' })) // 使用uglify进行压缩,并保留部分注释.pipe(gulp.dest('dist/js')); // 输出路径});
执行命令:
gulp script
4 图片处理(Image Task)
图片压缩( gulp-imagemin ) + 深度压缩( imagemin-pngquant ):
压缩PNG、JPEG、GIF和SVG图像。
gulp-imagemin集成了 gifsicle 、 jpegtran 、 optipng 、 svgo 这4个插件。而imagemin-pngquant是imagemin插件的一个扩展插件,用于深度压缩图片。
安装命令:
npm install gulp-imagemin imagemin-pngquant --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var imagemin = require('gulp-imagemin'), // 图片压缩pngquant = require('imagemin-pngquant'); // 深度压缩gulp.task('images', function(){return gulp.src('src/images/**/*.{png,jpg,gif,svg}') // 指明源文件路径、并进行文件匹配.pipe(imagemin({progressive: true, // 无损压缩JPG图片svgoPlugins: [{removeViewBox: false}], // 不移除svg的viewbox属性use: [pngquant()] // 使用pngquant插件进行深度压缩})).pipe(gulp.dest('dist/images')); // 输出路径});
执行命令:
gulp images
注:一般我们所使用的图片压缩方法,都会对图像造成一定的损失,这个和压缩比率有一定的关系。通常我们所说的无损压缩,也只是控制在我们肉眼难以发现的范围内。换句话来说,在你保存切图的同时,其实已经对图像造成了一定的损失,因为没什么人会选择100%最佳质量导出图片。两者是差不多的概念。
5 自动刷新(LiveReload Task)
网页自动刷新(文件变动后即时刷新页面)( gulp-livereload ) + 静态服务器:( gulp-webserver ):
安装命令:
npm install gulp-livereload gulp-webserver --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var livereload = require('gulp-livereload'), // 网页自动刷新(文件变动后即时刷新页面)webserver = require('gulp-webserver'); // 本地服务器// 注册任务gulp.task('webserver', function() {gulp.src( '.' ) // 服务器目录(.代表根目录).pipe(webserver({ // 运行gulp-webserverlivereload: true, // 启用LiveReloadopen: true // 服务器启动时自动打开网页}));});// 监听任务gulp.task('watch',function(){// 监听 htmlgulp.watch('src/**/*.html', ['html'])// 监听 scssgulp.watch('src/scss/*.scss', ['css']);// 监听 imagesgulp.watch('src/images/**/*.{png,jpg,gif,svg}', ['images']);// 监听 jsgulp.watch('src/js/*.js', ['script']);});// 默认任务gulp.task('default',['webserver','watch']);
执行命令:
gulp
3. 扩展优化(Extend & Optimize Task)
至此, 一套简单的前端自动化工作流/Gulp工作流便已经完成 。现在,我们开始优化并扩展这些插件,使我们的工作流更为”智能”。
3.1 文件重命名( gulp-rename ):
像jQuery一样,通常为了表示该文件是压缩版,会在文件名后加上 .min 后缀。
安装命令:
npm install gulp-rename --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var uglify = require('gulp-uglify'), // js压缩rename = require('gulp-rename'); // 文件重命名gulp.task('script', function() {return gulp.src('src/js/*.js') // 指明源文件路径、并进行文件匹配.pipe(rename({ suffix: '.min' })) // 重命名.pipe(uglify({ preserveComments:'some' })) // 使用uglify进行压缩,并保留部分注释.pipe(gulp.dest('dist/js')); // 输出路径});
执行命令:
gulp script
3.2 来源地图( gulp-sourcemaps ):
这是个非常有用的插件,我们在压缩、合并等操作之后,调试时所看到的内容,都是编译后的代码。这样就导致一个问题,调试过程中无法和源码(编译时的代码)位置相对应,让调试变的十分困难。
例如:一个jQuery,源码接近1万行。但压缩后只有短短的3~4行,并且变量名称也已发生改变。此时一旦报错,你很难从错误信息中直接找到对应代码的原始位置。同样,CSS也会遇到类似问题。
而sourcemaps作用,便是成一个 .map 文件,里面储存着对应的源码位置。并内嵌在你转换后的文件底部 /*# sourceMappingURL=maps/filename.css.map */
。这样在我们调试时,就会直接显示(映射)源码,而不时编译后的代码。
安装命令:
npm install gulp-sourcemaps --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var uglify = require('gulp-uglify'), // js压缩rename = require('gulp-rename'), // 文件重命名sourcemaps = require('gulp-sourcemaps'); // 来源地图gulp.task('script', function() {return gulp.src(['src/js/*.js','!*.min.js']) // 指明源文件路径、并进行文件匹配,排除 .min.js 后缀的文件.pipe(sourcemaps.init()) // 执行sourcemaps.pipe(rename({ suffix: '.min' })) // 重命名.pipe(uglify({ preserveComments:'some' })) // 使用uglify进行压缩,并保留部分注释.pipe(sourcemaps.write('maps')) // 地图输出路径(存放位置).pipe(gulp.dest('dist/js')); // 输出路径});
执行命令:
gulp script
3.3 只操作有过修改的文件( gulp-changed ):
比如我们有20个文件,当你修改其中1个文件时,由于任务的局限性,也会把其余19匹配的无辜的同类给一并进行处理,这样就大大降低了效率。而 gulp-changed 插件,会首先把文件进行比对,如果文件没有改动,则跳过后续任务。
安装命令:
npm install gulp-changed --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var imagemin = require('gulp-imagemin'), // 图片压缩pngquant = require('imagemin-pngquant'), // 深度压缩changed = require('gulp-changed'); // 只操作有过修改的文件gulp.task('images', function(){return gulp.src('src/images/**/*.{png,jpg,gif,svg}') // 指明源文件路径、并进行文件匹配.pipe(changed('dist/images')) // 对比文件是否有过改动(此处填写的路径和输出路径保持一致).pipe(imagemin({progressive: true, // 无损压缩JPG图片svgoPlugins: [{removeViewBox: false}], // 不移除svg的viewbox属性use: [pngquant()] // 使用pngquant插件进行深度压缩})).pipe(gulp.dest('dist/images')); // 输出路径});
执行命令:
gulp images
此时我们再去 dist/images 文件夹,查看每个图片的最后修改日期,你就会发现只针对你刚才修改过的图片(文件)行了处理,而那些之前已经处理过的图片则没有再进行操作。
注:无论是 gulp-changed 还是下文中提到的 gulp-cache ,对 sass 文件无效,始终会对所有匹配文件进行操作。
3.4 文件合并( gulp-concat ):
比如我们有多个JS库,jquery.min.js、bootstrap.min.js、angular.min.js。此时可以通过合并,减少网络请求。
安装命令:
npm install gulp-concat --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var concat = require("gulp-concat"); // 文件合并gulp.task('concat', function () {gulp.src('js/*.min.js') // 要合并的文件.pipe(concat('libs.js')) // 合并成libs.js.pipe(gulp.dest('dist/js'));});
执行命令:
gulp concat
3.5 文件清理( gulp-clean ):
简单的说,就是一键删除(清理)文件。就拿为了调试所生成的 .map 文件为例,在正式发布时并不需要,此时我们就能通过 clean任务进行清理。
安装命令:
npm install gulp-clean --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var clean = require('gulp-clean'); // 文件清理gulp.task('clean', function() {return gulp.src(['dist/css/maps','dist/js/maps'], {read: false}).pipe(clean());});
执行命令:
gulp clean
4. 其他插件介绍(Other plug-ins)
这部分插件作为扩展阅读,只做简单介绍。每个插件都有每个插件的特性,根据你的喜好和实际操作环境而定,萝卜青菜各有所爱。用的人最多的,不代表就是适合你的。总之,有时间有精力的,可以多试试,多玩玩,多配配,这里也只是冰山一角。
4.1 CSS类
- CSS压缩 ( gulp-minify-css )
安装命令:
npm install gulp-minify-css --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var minifyCss = require('gulp-minify-css'); // CSS压缩gulp.task('minify-css', function() {return gulp.src('css/*.css').pipe(gulp.dest('dist'));});
执行命令:
gulp minify-css
2、 CSS预处理/Less编译 ( gulp-less )
安装命令:
npm install gulp-autoprefixer --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var less = require('gulp-less'); // LESS编译gulp.task('less', function () {gulp.src('src/less/*.less').pipe(less()).pipe(gulp.dest('src/css'));});
执行命令:
gulp less
3、 自动添加CSS3浏览器前缀( gulp-autoprefixer ):
-prefix-free 大家肯定都比较熟,会自动为CSS添加上浏览器的前缀,帮你摆脱前缀痛苦。而 gulp-autoprefixer 插件同样如此。
安装命令:
npm install gulp-autoprefixer --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var autoprefixer = require('gulp-autoprefixer'); // 自动添加CSS3浏览器前缀gulp.task('prefix', function () {gulp.src('src/css/*.less').pipe(less()).pipe(gulp.dest('src/css'));});var gulp = require('gulp'); // 基础库var sass = require('gulp-ruby-sass'), // sass/scss编译autoprefixer = require('gulp-autoprefixer'); // 自动添加CSS3浏览器前缀gulp.task('sass', function () {return sass('src/sass', { style: 'compressed' }) // 指明源文件路径、并进行文件匹配.on('error', function (err) {console.error('Error!', err.message); // 显示错误信息}).pipe(autoprefixer({browsers: ['last 2 versions'], // 主流浏览器的最新两个版本cascade: false // 是否美化属性值})).pipe(gulp.dest('dist/css')); // 输出路径});
执行命令:
gulp sass
4 图像类
- 使用TinyPNG API压缩图片( gulp-tinypng ):
使用TinyPNG官方API进行图片压缩。我个人比较喜欢这个,因为之前一直有在使用。但由于TinyPNG服务器在国外,有时执行起来会很慢,除非你有VPN,所以在这只做简单介绍。经过我的测试,gulp-tinypng压缩后的图片大小,相当于使用imagemin-pngquant深度压缩后的大小。使用时需先注册TinyPNG账户,获你的API KEY。免费版每个月可以压缩500张图片,对于一般项目而言已经足够。
安装命令:
npm install gulp-tinypng --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var tinypng = require('gulp-tinypng'); // 使用TinyPN API压缩图片gulp.task('tinypng', function(){return gulp.src('src/images/**/*') // 源地址.pipe(tinypng('填写TinyPN API KEY')).pipe(gulp.dest('dist/images')); // 输出路径});
执行命令:
gulp tinypng
2 缓存代理( gulp-cache ):
缓存操作过的文件,当文件修改时,只编译当前修改的文件。其余文件直接从缓存中调取,提高效率。缺点:因为是缓存,所以如果文件被删除,但没及时清理缓存文件时,就会导致被删除的文件又从缓存中读取了出来,所谓成也萧何败也萧何。
安装命令:
npm install gulp-cache --save-dev
基础配置:
var gulp = require('gulp'); // 基础库var imagemin = require('gulp-imagemin'), // 图片压缩pngquant = require('imagemin-pngquant'), // 深度压缩pngquant = require('imagemin-cache'), // 缓存代理clean = require('imagemin-clean'); // 文件清理// imagemin 图片压缩(利用cache)gulp.task('images', function(){return gulp.src('src/images/**/*.{png,jpg,gif,svg}') // 指明源文件路径、并进行文件匹配.pipe(cache(imagemin({progressive: true, // 无损压缩JPG图片svgoPlugins: [{removeViewBox: false}], // 不要移除svg的viewbox属性use: [pngquant()] // 使用pngquant插件进行深度压缩}))).pipe(gulp.dest('dist/images')); // 输出路径});// 清理缓存文件gulp.task('clean', function (done) {return cache.clearAll(done);});
3. 注意事项(Attention)
watch 的时候路径不要用 './path'
,直接使用 '/path'
即可不然会导致新增文件无法被 watch。 gulp 对于 one after one 的任务链,需要加 return,比如 gulp clean
- gulp自动化构建工具快速入门和实战
- 前端打包构建工具gulp入门实战
- gulp自动化构建工具
- gulp 自动化构建工具
- gulp 自动化构建工具
- Gulp前端自动化构建工具介绍及入门
- 前端基于流的自动化构建工具gulp入门
- 前端自动化构建工具gulp
- gulp --- 前端自动化构建工具
- 配置自动化构建工具Gulp
- 自动化构建工具(gulp)
- gulp自动化构建工具----------初探
- 前端自动化构建工具--gulp
- gulp前端自动化构建工具(三):gulp工具配置文件
- Gulp 自动化的项目构建工具
- js,css 自动化构建工具gulp初探
- nodejs之gulp自动化构建工具
- 前端自动化构建工具gulp使用指南
- 在ADO.NET中使用参数化SQL语句的大同小异
- Linked List->single linked list
- CSS-display(显示)与visibility(可见性)
- [Anaconda] 常用包的安装命令
- 2016.7.31
- gulp自动化构建工具快速入门和实战
- 图片上传预览
- spark内存分析模型(小于1.5版本)-无原文版本-原创翻译
- Mac上Mysql跳过密码和权限的方法
- fiddler抓包工具模拟post请求
- Swift基础语法-属性,存储属性,延迟存储属性,计算属性,属性观察器,类属性
- Binder学习笔记(十二)—— binder_transaction(...)都干了什么?
- preg_match_all 正则表达式贪婪与非贪婪模式
- [Python]--The Difference append() vs. extend()