Gulp学习

作者: JenniferYe | 来源:发表于2016-05-10 10:09 被阅读1277次

    参照Gulp for Beginners来学习Gulp基本内容。以下为学习记录笔记。

    安装Gulp

    首先需要安装Node.js,并在控制台输入$ npm install gulp -gMac端需要写成$ 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.srcgulp.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 underscore
    3.编辑~/.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 PATH
    gyp verb `which` failed Error: not found: python2
    

    解决办法: $ npm install python

    在我们使用这个插件之前,我们必须像使用gulp那样先把gulp-sassnode_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.destdestination

    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 syntax
    gulp.watch('files-to-watch', ['tasks', 'to', 'run']); 
    

    如果我们想监听所有的Sass文件并在Sass文件被保存时运行sass任务,我们只需要把files-to-watch换成app/scss/**/*.scss,把['tasks', 'to', 'run']换成['sass']:

    // Gulp watch syntax
    gulp.watch('app/scss/**/*.scss', ['sass']); 
    
    gulp.task('watch', function(){ 
        gulp.watch('app/scss/**/*.scss', ['sass']); 
        // Other watchers
    })
    

    当你运行了gulp watch命令后,你就能看到Gulp马上开始监听了。

    如果你改变了styles.scss文件,你会看到浏览器自动的重载。

    其它的同理。
    在串联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.srcgulp.dest来复制文件,不需要其它插件。

    gulp.task('fonts', function() { 
        return gulp.src('app/fonts/**/*') 
        .pipe(gulp.dest('dist/fonts'))
    })
    

    这样子,当你运行gulp fonts时,Gulp就会从app复制fontsdist

    到现在,我们已经有了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,imagesfonts.
    我们需要一个额外的叫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 code
    Adding Sourcemaps for easier debugging
    Creating Sprites with sprity
    Compiling only files that have changed with gulp-changed
    Writing ES6 with Babel or Traceur
    Modularizing Javascript files with Browserify, webpack, or jspm
    Modularizing HTML with template engines like Handlebars or Swig
    Splitting the gulpfile into smaller files with require-dir
    Generating a Modernizr script automatically with gulp-modernizr

    For optimization:
    Removing unused CSS with unCSS
    Further optimizing CSS with CSSO
    Generating inline CSS for performance with Critical

    总结:

    这篇文章的内容可以帮助我们快速的了解Gulp,但是其中还有很多问题需要深究,还要继续学习。

    PS:评论区里有人提到不应该使用sudo。
    相关阅读:
    https://pawelgrzybek.com/fix-priviliges-and-never-again-use-sudo-with-npm/
    https://github.com/brock/node-reinstall

    相关文章

      网友评论

      本文标题:Gulp学习

      本文链接:https://www.haomeiwen.com/subject/ktnsrttx.html