安装Gulp
首先需要安装Node.js,并在控制台输入$ npm install gulp -g
Mac端需要写成$ sudo npm install gulp -g
(因为Mac端需要在管理员下运行来安装Gulp,-g
表示全局安装。
创建一个Gulp项目
学习过程,将使用一个名为project的文件夹作为项目根目录,在文件夹内运行$ npm init
,这将会为你的项目创建一个叫package.json的文件,文件会存储关于你的项目的信息,就像在项目里使用的依赖(Gulp就是依赖的一个例子)在创建了package.json之后,就可以通过$ npm install gulp --save-dev
在项目中安装Gulp,这次我们是把Gulp安装到project项目中,而不是全局安装。(这次Mac端也不需要使用sudo)--save-dev
意思是把gulp作为依赖添加到当前项目。现在,可以在原来的文件夹中看到一个node_modules
文件夹,在node_modules
文件夹中包含着gulp
文件夹。
已经做好使用Gulp的准备工作,在我们使用Gulp之前我们必须清楚我们将要怎么在项目中使用Gulp,其中之一就是决定目录结构。
确定文件结构
一般webapp文件结构
在这个结构中,app
文件夹是用来做开发的,dist
文件夹是用来包含生产现场的优化文件。因为app
是用于开发,所以我们所有的代码都会放在app
文件夹下。在配置Gulp时,我们必须记住文件夹的结构。现在就可以开始在存储所有Gulp配置的gulpfile.js创建第一个Gulp任务。
写你的第一个Gulp任务
使用Gulp的第一步是把它require
到gulpfile中
var gulp=require('gulp');
这个require
语句会告诉Node在node_modules
文件夹中查找一个叫gulp
的包,一旦找到,就会把包的内容赋值到变量gulp
中。接下来就可以使用这个gulp
变量来写gulp
任务,一个gulp
任务的基础语法是:
gulp.task('task-name',function(){ //stuff here});
task-name
指的是任务的名字,将会被用在你想在Gulp
运行一个任务的时候。你也可以使用命令行gulp task-name
来运行相同的任务。
测试例子:
var gulp=require('gulp');gulp.task('hello',function(){ console.log('Hello world!');});
我们可以通过在控制台输入$ gulp hello
来运行这个任务。就可以在控制台看到以下的结果:
Gulp任务通常会比这个复杂,通常会包含两个额外的Gulp方法,和各种Gulp插件。以下是一个真实任务可能的情况:
gulp.task('task-name', function () { return gulp.src('source-files') // Get source files withgulp.src .pipe(aGulpPlugin()) // Sends it through a gulp plugin .pipe(gulp.dest('destination')) // Outputs the file in the destination folder})
可以看到,一个真实的任务会用到两个额外的gulp方法——gulp.src
和gulp.dest
gulp.src
告诉Gulp 任务在这个任务中使用哪些文件。gulp.dest
告诉Gulp当任务完成时应该在哪里输出。
用Gulp预处理
使用一个叫gulp-sass
的插件可以在Gulp将Sass编译成CSS,使用像安装Gulp一样的npm install
命令安装gulp-sass
到项目中:
$ npm install gulp-sass --save-dev
使用--save-dev
标记来保证gulp-sass被添加到package.json
中的devDependencies
中。
PS:在下载插件的过程中可能会遇到下载较慢的问题,可通过调用国内镜像来解决 来源镜像使用方法(三种办法任意一种都能解决问题,建议使用第三种,将配置写死,下次用的时候配置还在):1.通过config命令npm config set registry https://registry.npm.taobao.org npm info underscore (如果上面配置正确这个命令会有字符串response)2.命令行指定npm --registry https://registry.npm.taobao.org info underscore3.编辑~/.npmrc加入下面内容registry = https://registry.npm.taobao.org搜索镜像: https://npm.taobao.org建立或使用镜像,参考: https://github.com/cnpm/cnpmjs.org
在安装过程中我自己还遇到另一个问题,错误信息
gyp verb check python checking for Python executable "python2" in the PATHgyp verb which
failed Error: not found: python2
解决办法: $ npm install python
在我们使用这个插件之前,我们必须像使用gulp那样先把gulp-sass
从node_modules
文件夹中require
进来。
var gulp = require('gulp');// Requires the gulp-sass pluginvar sass = require('gulp-sass');
现在就可以把上面的aGulpPlugin()
替换成sass()
。
gulp.task('sass', function(){ return gulp.src('source-files') .pipe(sass()) // Using gulp-sass .pipe(gulp.dest('destination'))});
现在我们需要为sass
任务提供源文件和目标文件来使得任务运行,现在在app/scss创建一个styles.scss文件。这个文件将会在gulp.src()
中被添加到sass任务。这里我们把最终的styles.css
文件输出到app/css
文件夹中,这将是gulp.dest
的destination
。
gulp.task('sass', function(){ return gulp.src('app/scss/styles.scss') .pipe(sass()) // Converts Sass to CSS with gulp-sass .pipe(gulp.dest('app/css'))});
为了测试sass任务是否像我们希望的那样运行。我们会在styles.scss
中添加一个Sass方法。
// styles.scss.testing { width: percentage(5/7);}
在控制台上运行gulp sass
后,回到app/css
目录下,可以看到一个styles.css
的文件。内容如下:
.testing { width: 71.42857%; }
PS:Gulp-sass使用LibSass把Sass转换成CSS,这会比基于Ruby的方法更快。如果你想依然在gulp中使用Ruby方法的话,可以使用gulp-ruby-sass或者gulp-compass.
Node中的通配符(Globbing in Node)
Globs(通配符)是允许你添加多于一个文件进gulp.src()
中的匹配模式。这就像是普通的表达式,但是是专门给文件路径的。当你使用一个glob的时候,电脑会根据特定的模式来检查你的文件名称和路径。若存在,则该文件就被匹配。多数Gulp工作流通常只需要4种不同的通配符模式:
** .scss: ***
是一个在当前目录匹配所有模式的通配符。在这个栗子中,我们会匹配在根目录(project)下所有以.scss
结尾的文件。
******/.scss :这是一个*
模式更为极端的一个版本,它会匹配根目录和其它子目录的所有以.scss
结尾的文件。
!not-me.scss:!
表明Gulp会排除掉与之匹配的模式,这在你需要排除掉一个匹配中的文件时会很有用。在这个栗子中,not-me.scss
将会在匹配中被排除。
** .+(scss|sass) :加号和括号(parentheses)允许Gulp去匹配多种模式,不同的模式被|
(pipe)隔开。这个栗子中,Gulp会匹配根目录下所有以.scss
或.sass
结尾的所有文件。现在我们就可以把app/scss/styles.scss
替换成scss//.scss
模式。gulp.task('sass', function() { return gulp.src('app/scss/*/.scss') // Gets all files ending with .scss in app/scss and children dirs .pipe(sass()) .pipe(gulp.dest('app/css'))})
现在的问题是,我们每次都要手动去调用gulp sass
才能把Sass转换成CSS吗?
我们可以通过一个叫"watching"的进程让Gulp在sass保存的时候自动运行sass任务。
监视Sass文件的变化(Watching Sass files for changes)
Gulp为我们提供了一个watch
方法来检查文件是否被保存。watch
方法的语法是:
// Gulp watch syntaxgulp.watch('files-to-watch', ['tasks', 'to', 'run']);
如果我们想监听所有的Sass文件并在Sass文件被保存时运行sass任务,我们只需要把files-to-watch
换成app/scss//.scss
,把['tasks', 'to', 'run']
换成['sass']:
// Gulp watch syntaxgulp.watch('app/scss//.scss', ['sass']);
gulp.task('watch', function(){ gulp.watch('app/scss/*/.scss', ['sass']); // Other watchers})
当你运行了gulp watch
命令后,你就能看到Gulp马上开始监听了。
[图片上传中。。。(5)]修改Sass文件
接下来就看看怎么让Gulp在Browser Sync的帮助下实现在保存一个.scss文件时重载浏览器。
Browser Sync实时重载(Live-reloading with Browser Sync)
通过spinning up web 服务器Browser Sync能让我们更容易实现实时重载。它也有其它特征,例如多设备同步动作。
第一步:安装Browser Sync$ npm install browser-sync --save-dev
你会发现当我们安装Browser Sync时并没有gulp-
前缀。这是因为Browser Sync是和Gulp一起运行的,所以我们不需要使用插件。
第二步:require Browser Syncvar browserSync = require('browser-sync').create();
我们需要创建一个browserSync
任务使得Gulp可以使用Browser Sync旋转加速服务器。因为我们正在运行服务器,我们需要让Browser Sync知道服务器的根目录应该在哪里。在这里的栗子中是app
文件夹:gulp.task('browserSync', function() { browserSync.init({ server: { baseDir: 'app' }, })})
第三步:同时我们需要对我们的sass
任务做一点小小的改变,使得Browser Sync可以在sass
任务完成时向浏览器注入新的CSS样式(更新CSS)。gulp.task('sass', function() { return gulp.src('app/scss/*/.scss') // Gets all files ending with .scss in app/scss .pipe(sass()) .pipe(gulp.dest('app/css')) .pipe(browserSync.reload({ stream: true }))});
到这里,我们就配置好Browser Sync了。现在我们需要同时运行watch
和browserSync
任务来做到实时重载。如果我们要打开两个命令行窗口来分别运行gulp browserSync
和gulp watch
这会十分笨重,所以我们要让Gulp同时运行它们,通过告诉watch
任务browserSync
必须在watch
运行前完成。可以通过给watch
任务添加第二个参数来实现上述要求。gulp.task('watch', ['array', 'of', 'tasks', 'to', 'complete','before', 'watch'], function (){ // ...})
在这个栗子中,我们会添加browerSync任务。gulp.task('watch', ['browserSync'], function (){ gulp.watch('app/scss/*/.scss', ['sass']); // Other watchers})
同时,我们也要保证sass
在watch
前运行,以保证CSS在我们运行Gulp命令时都是最新的。gulp.task('watch', ['browserSync', 'sass'], function (){ gulp.watch('app/scss/*/.scss', ['sass']); // Other watchers});
现在,当在命令行运行了gulp watch
,Gulp会马上启动sass
和'browserSync'。当两个任务都完成时,watch
才会运行。同时会打开app/index.html
。
[图片上传中。。。(6)]
如果你改变了styles.scss
文件,你会看到浏览器自动的重载。
既然我们已经监视了.scss
文件重载,接下来我们看看怎么在HTML或JS文件被保存的时候重载浏览器。可以通过添加两个监听程序,并在文件被保存的时候调用browserSync.reload方法。
gulp.task('watch', ['browserSync', 'sass'], function (){ gulp.watch('app/scss//.scss', ['sass']); // Reloads the browser whenever HTML or JS files change gulp.watch('app/.html', browserSync.reload); gulp.watch('app/js/*/.js', browserSync.reload); });
目前我们已经解决了三件事情:
为开发旋转加速web服务器
使用Sass预处理器
在文件被保存时重载浏览器
接下来会处理优化资源的部分。首先冲优化CSS和JS文件开始。
优化CSS和JS文件
在为产品优化CSS和JS文件的时候,开发人员通常有两个任务要完成:缩小(minification)和串联(concatenation)。
其中一个开发人员面临的问题就是,在使程序自动化的时候很难把你的脚本按正确的顺序串联。
假设index.html
中包含3个<script>标签
<body> <script src="js/lib/a-library.js"></script> <script src="js/lib/another-library.js"></script> <script src="js/main.js"></script></body>
这些脚本被保存在两个不同的目录。使用传统的像gulp-concatenate
这样的传统插件很难做到把他们串联在一起。庆幸的是,gulp-useref
可以解决这个问题。Gulp-useref通过寻找一个以
开始,以
结尾的注释来做到把任意数目的CSS和JS文件串联到一个文件中。
... HTML Markup, list of script / link tags.
<type>可以是js,css或者是remove。最好给你想要串联的文件的类型设定type
。如果你给设定remove
设定了type
,那么Gulp会移除整个build块而不创建一个文件。
<path>在这里指的是生成文件的目标路径。
这里我们希望最终的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>
现在配置gulp-useref插件到gulpfile。我们需要安装并把它require到gulpfile。
$ npm install gulp-useref --save-dev
var useref = require('gulp-useref');
构建useref任务的步骤和其它相似。
gulp.task('useref', function(){ return gulp.src('app/*.html') .pipe(useref()) .pipe(gulp.dest('dist'))});
运行gulp useref
就可以了。然而,文件现在还没有被缩小。我们需要使用gulp-uglify
插件来缩小JS文件。同时,我们还需要另一个叫gulp-if
插件来保证我们只会缩小JS文件。
// Other requires...var uglify = require('gulp-uglify');var gulpIf = require('gulp-if');gulp.task('useref', function(){ return gulp.src('app/.html') .pipe(useref()) // Minifies only if it's a JavaScript file .pipe(gulpIf('.js', uglify())) .pipe(gulp.dest('dist'))});
其它的同理。在串联CSS文件的时候,使用gulp-cssnano
来压缩文件。
var cssnano = require('gulp-cssnano');gulp.task('useref', function(){ return gulp.src('app/.html') .pipe(useref()) .pipe(gulpIf('.js', uglify())) // Minifies only if it's a CSS file .pipe(gulpIf('*.css', cssnano())) .pipe(gulp.dest('dist'))});
优化图片
使用gulp-imagemin
来优化图片。通过gulp-imagemin
我们可以压缩png
,jpg
,gif
甚至svg
。
gulp.task('images', function(){ return gulp.src('app/images/*/.+(png|jpg|gif|svg)') .pipe(imagemin()) .pipe(gulp.dest('dist/images'))});
因为不同的文件类型都会被不同程度的优化,你可能会想给imagemin
增加可选参数来定制每个文件的优化方式。例如,你可以通过设置interlaced
参数为true
来创建隔行的GIFs。
gulp.task('images', function(){ return gulp.src('app/images/*/.+(png|jpg|jpeg|gif|svg)') .pipe(imagemin({ // Setting interlaced to true interlaced: true })) .pipe(gulp.dest('dist/images'))});
优化图片是一项十分慢的过程,除非必须,否则你不会想要重复一遍。这样我们可以使用gulp-cache
插件。
var cache = require('gulp-cache');gulp.task('images', function(){ return gulp.src('app/images/*/.+(png|jpg|jpeg|gif|svg)') // Caching images that ran through imagemin .pipe(cache(imagemin({ interlaced: true }))) .pipe(gulp.dest('dist/images'))});
现在还有一个需要从app
目录转换到dist
目录,就是fonts 目录。
复制fonts到Dist
因为font文件已经被优化过了,所以我们不需要再做什么。只需要把fonts复制到dist就好了。我们可以通过指明gulp.src
和gulp.dest
来复制文件,不需要其它插件。
gulp.task('fonts', function() { return gulp.src('app/fonts/*/') .pipe(gulp.dest('dist/fonts'))})
这样子,当你运行gulp fonts
时,Gulp就会从app
复制fonts
到dist
。
到现在,我们已经有了6个不同的任务,每个都要在命令行单独调用,这真是一件很笨重的事。因此我们想要把所有命令绑定到一句命令中。
在我们那样做之前,我们先来看看怎么自动清理产生的文件。
自动清理产生的文件
我们已经可以自动创建文件,我们想要确保那些不会再使用的文件不会留再任何我们不知道的地方。这个过程叫做cleaning(或删除文件)。
我们使用del
来清理文件。引用方式同上述的其它一样。
npm install del --save-dev
var del = require('del');
del
方法需要在一个告诉它要删除哪个文件的node通配符数组。配置一个Gulp任务就跟第一个'hello'任务差不多。
gulp.task('clean:dist', function() { return del.sync('dist');})
这样,当你运行gulp clean:dist时,'dist'文件夹就会被删除。
我们不需要担心会删除了dist/images
文件夹,因为gulp-cache
已经把图片缓存在本地系统中了。要想清楚本地系统缓存,你可以单独创建一个叫cache:clear
的任务。
gulp.task('cache:clear', function (callback) { return cache.clearAll(callback)})
结合Gulp任务
先来总结下我们做过的东西,目前,我们已经创建了两类Gulp任务。第一种是用于开发过程的,把Sass编译成CSS,监视变化,有依据地重载浏览器。
第二种适用于优化过程的,为产品网站准备好所有文件。优化这个过程中像CSS,JS和图片这样子的资源,把fonts从app
复制到dist
。
我们之前已经用gulp watch
命令把第一种任务组合到一个工作流中。
gulp.task('watch', ['browserSync', 'sass'], function (){ // ... watchers})
第二类包括那些我们运行来创造产品网站的任务。其中包括了clean:dist
,sass
,useref
,images
和fonts
.我们需要一个额外的叫Run Sequence
的插件。
$ npm install run-sequence --save-dev
语法:
var runSequence = require('run-sequence');gulp.task('task-name', function(callback) { runSequence('task-one', 'task-two', 'task-three', callback);});
这样任务就会一个接一个的运行。
Run Sequence也允许你同时运行任务,只要你把他们放到一个数组中。
gulp.task('task-name', function(callback) { runSequence('task-one', ['tasks','two','run','in','parallel'], 'task-three', callback);});
为了一致性,我们也可以用相同的序列处理第一组任务。并且使用default
作为任务名字。应为这样我们在调用的时候只需要写gulp
。
作者的一些建议:For development:Using Autoprefixer to write vendor-free CSS codeAdding Sourcemaps for easier debuggingCreating Sprites with sprityCompiling only files that have changed with gulp-changedWriting ES6 with Babel or TraceurModularizing Javascript files with Browserify, webpack, or jspmModularizing HTML with template engines like Handlebars or SwigSplitting the gulpfile into smaller files with require-dirGenerating a Modernizr script automatically with gulp-modernizr
For optimization:Removing unused CSS with unCSSFurther optimizing CSS with CSSOGenerating inline CSS for performance with Critical
总结:
这篇文章的内容可以帮助我们快速的了解Gulp,但是其中还有很多问题需要深究,还要继续学习。
作者:JenniferYe链接:http://www.jianshu.com/p/5afd6348dae2來源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。