用gulp管理本身的前端开发任务及须要注意的坑

关于gulp,grunt,webpack,刚走前端模块化的我,真的是傻傻分不清楚,幸亏有大神各类答疑解惑,使我略知一二,你也想知道的,也许还想知道点啥,资源罗列:
一、中文官方文档
二、阮老师的gulp入门
三、个人参考;
本次开发,受尤大神知乎上的回答提示,没有采用vue-cli直接入手vue框架,而是采用vue全家桶+requireJs+gulp着手本身的前端构建,gulp为本身第一次使用,因此写下此文,算是对本身成长的一次记录。关于gulp,首先你得知道npm,node这些常识,其次官方的API应该细度加实践一下,其四个基本操做:gulp.task、gulp.src、gulp.dest、gulp.watch四个基本方法,需用知道是干什么的,该怎么用。gulp有什么用?文章将基于如下4条逐一展开讲:
一、搭建web服务器
二、优化资源,好比压缩CSS、JavaScript、压缩图片;
三、使用预处理器LESS,jade,JSX须要编译发布;
四、文件保存时自动重载浏览器;javascript

一:开启一个本地web服务

一般开发时,咱们不可能一直写静态页面,咱们须要在其余设备查看效果或者与后台的动态交互,使前端开发变得更有意义。因此与后端交付以前,你得有一个本地服务器来发布你的内容。直白点说,没有服务器,咱们是经过这样的连接(file:///D:/vueProject/myblog/dist/index.html)访问咱们的页面的,而有了服务器依赖,咱们是经过这样的连接(http://localhost/)访问咱们的页面的,应用上线的感受,有没有?其实之前基于JavaWeb开发(tomcat)网页时,根本就没这档子事。闲话少扯,进入正题。利用gulp资源,开启一个服务器,你须要下载安装gulp-webserver这个插件,而后这样配置,源码:css

var gulp = require('gulp');
var webserver = require('gulp-webserver');
gulp.task("Server",function(){
    gulp.src('dist')  //你web资源的根目录
    .pipe(webserver({
        port:80,
        host:'127.0.0.1',
        liveload:true,
        directoryListing:{
            path:'index.html', //你web资源的起始页,在dist目录下
            enable:true
        }
    }))
});

基于以上,而后在命令行中输入gulp Server就能够开启一个本地端口为80(也能够为其余)的本地服务器,很简单有木有,但上面的服务器有一个问题,只有本机能访问,局域网内其余设备没法访问该站点,别信网上那些啥开防火墙,开端口胡扯的,根本不要紧,由于gulp的web-server就只有这点功能,想要服务器局域网都能访问,在gulp-webserver官方文档的FAQ给出了解决方案:Set 0.0.0.0 as host option.html

二:优化资源

gulp的主要功能就是文件的合并,压缩,MD5,因为个人前端JS是基于requireJS构建的,为了在页面加载时提升响应速度,就须要减小文件请求数量并压缩文件的大小,为了作这些操做,须要下载gulp-requirejs-optimize(requireJS序列化工具),gulp-rename,gulp-concat,gulp-minify-css,gulp-rev,gulp-rev-collector,through2,gulp-clean,run-sequence等插件包。我要达到的目以下图所示,从新生成发布目录、CSS文件的合并压缩,JS文件的优化及压缩及重命名带上MD5序列号。上源码:图片描述前端

var gulp = require('gulp'),
reqOptimize =require('gulp-requirejs-optimize'),
rename = require("gulp-rename"),
changed = require("gulp-changed"),
contact =require('gulp-concat'),
rev =require('gulp-rev'),
through2 = require('through2'),
revCollector = require('gulp-rev-collector'),
clean = require('gulp-clean'),
runSequence = require('run-sequence'),
minifyCss = require('gulp-minify-css');
/*将requireJs文件转移到发布目录*/
gulp.task('revJs',function(){
    gulp.src('js/main/*.js')
    .pipe(gulp.dest('dist/js/main'))
});
/*将全部的图片转移到发布目录*/
gulp.task('revImg',function(){
    gulp.src('img/**/*')
    .pipe(gulp.dest('dist/img'))
});
/*将css文件合并压缩转移到发布目录*/
gulp.task('revCss',function(){  
     gulp.src('css/*.css')
    .pipe(contact('index.css'))
    .pipe(minifyCss())//{compatibility: 'ie8'}
    .pipe(gulp.dest('dist/css'))
});
/*将主文件依赖管理合并、压缩、重命名、并去掉.js操做,而后转移到发布目录,操做后文件名如app-1da68b69e1.js*/        
function modify(modifier) {
    return through2.obj(function(file, encoding, done) {
        var content = modifier(String(file.contents));      
        file.contents = new Buffer(content);
        this.push(file);
        done();
    });
}   
function replaceSuffix(data) {
    return data.replace(/\.js/gmi, "");
}    
gulp.task('optimizeJS', function (cb) {
    gulp.src('js/app.js')
    .pipe(reqOptimize({
    optimize:"none",
    paths:{
        vue:'lib/vue',
        vueRouter:'lib/vue-router',
        vueResource:'lib/vue-resource',
        temp:'component/template',
        resize:'component/resizeWindow'
    }
    }))
    .pipe(rev())  //- 文件名加MD5后缀
    .pipe(gulp.dest('dist/js'))   //- 生成MD5后的文件
    .pipe(rev.manifest({merge:true}))  //- 生成一个rev-manifest.json,记录版本映射
    .pipe(gulp.dest(""))    
    .pipe(modify(replaceSuffix))            //- 对去掉rev-manifest问件中的文件去掉.js后缀,这主要是考虑requireJs的操做规范
    .pipe(gulp.dest(''))       
    .on('end',cb);   
});    
/*因为对app.js重命名加入了md5序列号值,因此须要替换原始index.html中关于app.js的引用*/
/*这里须要注意,revCollector()至关于一个全文件查找替换的过程,以个人为例*/ 
/*个人rev-manifest.json文件中对应的映射是:"app": "app-1da68b69e1",因此这个函数在操做时,会对index.html全文模糊搜索‘app’这三个关键字,而后替换为app-1da68b69e1,*/
/*这其中容易出错就在于他是模糊搜索,因此若是你的文件中有个css的class名或自定义的标签名会内容带有app三个字母,它都会进行替换,因此,在转换过程当中,要避开这个坑*/      
gulp.task("updateHtml",function (cb) {
    gulp.src(['rev-manifest.json', 'index.html'])  
        .pipe(revCollector())                   //- 替换为MD5后的文件名
        .pipe(rename("index.html"))
        .pipe(gulp.dest('dist'))
        .on('end', cb);
});

基于以上源码,在命令行中依次输入gulp revJs,gulp revImg,gulp revCss, gulp optimizeJS,gulp updateHtml,就能够达到上述目的,这样是否是有点繁琐,能不能一步到位?固然能够,咱们能够帮上述任务写到一个命令中,固然你也能够写到default任务中,而后执行gulp alltaskvue

gulp.task('alltask',['revJs','revImg','revCss','optimizeJS','updateHtml'])

上述代码有一个问题,特别是针对个人项目,由于个人updateHtml是基于optimizeJS执行完后生成的rev-manifest.json执行的,但gulp.task中的任务组,默认是并行执行的,但我但愿的是前三个转移并行执行,后面两个串行执行,通过资料查找得知,在gulp 4以前,须要依赖run-sequence来管理任务的执行顺序,而gulp 4引入了连个新的API:gulp.series(串行)和gulp.parallel(并行)来保证任务按指定的顺序执行。在这里我采用了run-sequence的解决方案:java

gulp.task('default', function(callback) {
    runSequence(
        "clean",                //- 上一次构建的结果清空
        "revImg",
        "revCss",
        "revJs",                
        "optimizeJS",        //- - 文件合并与md5并去.js后缀
        "updateHtml",      //- 首页路径替换为md5后的路径
        "Server",   //- 服务器开启
        callback);
});

下一步重点研究,怎样将生成后的JS及CSS文件带上如browser-sync-client.js?v=2.18.12版本号的形式。node

四:文件更改保存时浏览器的自动重载(先跳过三)

在咱们的开发过程当中,咱们常常会修改html,CSS,js文件,因为咱们的生产目录与开发目录不一致,因此须要执行GULP命令来发布文件到生产目录。可是频繁的关闭服务与重启服务,这样就形成了不少时间浪费,因此咱们须要利用gulp.watch来监视文件的改动,并将这些改动从新发布到生产目录,并重启服务(非手动)。因为我的以为gulp-webServer与gulp-livereload的局限性,因此讲服务采用browser-sync来代替gulp-webServer,后者自身支持热更新,无需在浏览器安装任何插件(gulp-livereload须要安装livereload插件),直接上源码:webpack

var browserSync = require("browser-sync").create(); //引入模块 
/*每次发布生产文件前,先将dist目录下的文件状况*/
gulp.task("clean",function () {
    return gulp.src([
        'rev-manifest.json',
        'dist/js/*.js',
        'dist/index.html'
    ]).pipe(clean());
});   
/*每次app.js变更时,须要清除rev-manifest.json文件中的映射,使其保证只有惟一的一个映射*/
gulp.task("JSreload",function(){
    return gulp.src(['rev-manifest.json', 'dist/js/*.js','dist/index.html']).pipe(clean());
})     
/*每次任务发起前,先清空温江,而后再依次发布文件,启动服务器,监听变更*/
gulp.task('server', ['clean'], function() {  
    runSequence(       
        "revImg",
        "revCss",
        "revJs",
        "optimizeJS",        //- - 文件合并与md5并去.js后缀
        "updateHtml"      //- 首页路径替换为md5后的路径
    );      
    browserSync.init({  
        port: 80,  
        server: {  
            baseDir: ['dist']  
        }  
    });  
  //监控文件变化,自动更新 
    gulp.watch('js/app.js', function(){
            runSequence(
            "JSreload",
            'optimizeJS',           
            "updateHtml", 
            browserSync.reload     
        );       
    });  
    gulp.watch('css/*.css',  function(){
            runSequence(
            "revCss",
            browserSync.reload     
        );       
    });
    gulp.watch('index.html',  function(){
            runSequence(
            "updateHtml", 
            browserSync.reload    
        );       
    }); 
});

/将server事务,注册为默认任务/
gulp.task('default',['server']);
基于以上操做,命令行运行gulp ,咱们就开启了一个基于browserSync的本地服务器以下图所示,而且局域网内的设备均可以经过主机IP+port访问应用。图片描述web

三:预处理器文件编译

暂时没用到,后面用到再增长,能够参考其余人的vue-router

相关文章
相关标签/搜索