Gulp打包工具

作者: 张歆琳 | 来源:发表于2017-01-12 00:17 被阅读1123次

    前端打包工具有很多款,从早期雅虎的Ant到现在的Webpack,期间的迭代变化的差别之大,如同Java到JavaScript,除了名字有点一样,几乎就是两门完全不同的语言。公司项目主要用Gulp和Webpack,本篇先整理一下Gulp

    如果你用过Grunt,可能觉得Gulp有点莫名其妙,Grunt前辈社区完善,插件成千上万,弄出个Gulp干什么?我个人感觉在未来的前端开发中一切都将是JS,因此即便是配置工具,Gulp用JS代码实现的策略优于Grunt的半JS半配置的策略。而且Gulp用流的方式进行文件处理,通过管道将多个任务和操作连接在一起,全程只有一个IO过程,最后的结果直接写入硬盘。因此打包流程更加清晰,没有中间临时文件,速度更快。注意,不要轻视“速度更快”这个评价,打包的时间越短越好,快1秒也能提高前端工程师的效率,做前端的都懂的…

    • 安装和执行
    • 插件引入
    • task
    • 数据流
    • watch

    安装和执行

    安装很简单:

    npm install --global gulp
    

    安装之后,在工程目录下新建一个名为gulpfile.js的文件:

    var gulp = require('gulp');
    gulp.task('default', function() {
        ……
    });
    

    这样在目录下执行gulp就能自动执行上面定义的default方法。

    插件引入

    作为一款流程的打包工具,社区丰富的插件库是必不可少的。除了var gulp=require(‘gulp’);是一定要引入的外,其他的插件根据需要自行引入。例如gulpfile.js的头部可能是这样的:

    var gulp = require('gulp');
    var del = require('del');
    var less = require('gulp-less');
    var base64 = require('gulp-base64');
    var tpl2mod = require('gulp-tpl2mod');
    var extReplace = require('gulp-ext-replace');
    

    从上面代码就能看出,Gulp完全遵守CommonJS的规范,无论是前端页面工程师,还是后端Node工程师都可以零基础立马上手。这可能也是Gulp能取代Grunt的一个原因。

    task

    引入插件后,就需要建立一个个子任务来执行插件。task函数的原型:

    gulp.task(name[, deps], fn)
    

    第一个参数是task名。第二个参数可选,是个任务列表array,这些任务会在运行当前任务之前运行,例如:

    gulp.task('default', ['css', 'image', 'ejs', 'babel']);
    

    需要注意的是,你需要确保array里的任务都在当前任务开始前被运行完毕。如果array里的任务是同步方法,那就没没什么好担心的,Gulp会确保顺序依次执行。但如果array里的任务是异步方法,需要确保是否使用了一个callback,或返回一个promise或stream。

    第三个参数fn里定义了任务需要执行的操作。

    数据流
    如果你熟悉Java,那么IO数据流这个策略应该非常熟了。Gulp通过串联起来的的小函数来传递数据,这些函数会对数据进行修改,然后把修改后的数据传递给下一个函数。src函数的原型:

    gulp.src(globs[, options])
    

    该函数将输出匹配globs的文件。输出的文件可以用pipe输入到别的插件中,形成一串数据流。

    第一个参数globs,可以是string也可以是array,是一些常用的正则表达式,例如:

    js/sample.js    //精确匹配文件
    js/*.js              //匹配js目录下的所有js文件
    js/**/*.js        //匹配js目录及其子目录下所有后缀为.js的文件
    !js/sample.js   //从匹配结果中去除js/sample.js文件
     *.+(js|css)      //匹配根目录下所有后缀为.js或者.css的文件
    
    //例如:匹配js目录及其子目录下所有js文件,但需要去除后缀为.min.js的文件
    gulp.src(['js/**/*.js', '!js/**/*.min.js'])
    

    更多高级语法,请仔细阅读node-glob语法。

    第二个参数options可选,除了支持node-globglob-stream的参数外,还支持一些Gulp的额外的参数。例如:

    options.buffer:如果设为false,将会以stream方式返回file.contents而不是文件buffer的形式。这在处理一些大文件的时候将会很有用。

    options.read:如果设为false, 那么file.contents会返回null,这样就不会去读取文件

    options.base:string型的值,将会被加在glob之前。例如下面两段代码唯一的区别是,上面这段没有options.base,而下面这段加上了options.base,导致结果路径有区别:

    gulp.src('client/js/**/*.js') 
      .pipe(minify())
      .pipe(gulp.dest('build')); 
     //匹配client/js/somedir/somefile.js并且将base解析为client/js/,因此结果 写入build/somedir/somefile.js
    
    gulp.src('client/js/**/*.js', { base: 'client' })
      .pipe(minify())
      .pipe(gulp.dest('build'));
    //结果写入build/js/somedir/somefile.js
    

    数据流的结果通过dest函数输出,原型:

    gulp.dest(path[, options])
    

    第一个参数是文件被输出的路径,路径是相对路径,当然相对路径也可根据上面的options.base来计算。第二个参数options可选,具体可以参照Linux的文件系统操作命令:

    options.cwd:默认值process.cwd()。输出目录的 cwd 参数,只在所给的输出目录是相对路径时候有效。

    options.mode:默认值0777,用以定义所有在输出目录中所创建的目录的权限。

    看一个Babel解码ES6的例子:

    gulp.task('babel', function () {
        return gulp.src('./javascript/**/*.js')
            .pipe(babel({
                presets: [
                    'es2015',
                    'stage-0'
                ],
                plugins: [
                    'transform-runtime',
                    'syntax-async-functions',
                    'transform-class-properties',
                    'transform-decorators-legacy'
                ]
            }))
            .pipe(gulp.dest('./js'));
    });
    

    最后,Gulp及其插件使用的流是vinyl文件对象流(stream或buffer),和普通的文件流(chunk)还是有区别的。因此在使用Gulp时,如果pipe出现Streaming not supported。可能是因为传给Gulp及其插件的是普通文件流(例如Node里fs.createReadStream(‘app.js’).pipe(uglify()))。可以用vinyl-source-stream转换工具转一下就行了。

    watch

    Gulp可以监视文件的修改,功能类似于Jade里的-w参数,当文件有变动时,执行回调函数。Watch有两种原型:

    gulp.watch(glob[, opts], tasks)
    gulp.watch(glob[, opts, cb])
    

    第一种原型:第一个参数glob用于指定哪些文件需要被监视,语法参数数据流不赘述。第二个参数opts可选,参照gaze。第三个参数tasks用于指定当被监视的文件有改动时,执行哪些task。watch函数始终会返回一个EventEmitter 来发射change 事件。例如:

    var watcher = gulp.watch('js/**/*.js', ['uglify','reload']);
    watcher.on('change', function(event) {
      console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
    });
    

    第二种原型:和第一种的区别是,第三个参数不是task数组,而是自定义回调函数。回调函数的参数是event对象,你可以从该参数中获取到event.type(被监视的文件发生的变化类型added,changed, deleted)和event.path(触发该事件的文件的路径)例如:

    gulp.watch('js/**/*.js', function(event) {
      console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
    });
    

    总结

    技术总是在发展,从实际使用下来的经验看,Gulp确实比Grunt更快,代码更少更易读。Gulp能火多久不清楚,目前来看,还是项目的一个比较理想的打包工具。

    相关文章

      网友评论

        本文标题:Gulp打包工具

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