技巧集:http://www.gulpjs.com.cn/docs/recipes/

其实无非就是利用各种gulp插件、node脚本对项目文件做各种IO操作,只是备忘,需要的话,还是自己重新写最合适。

1. 一个justwork的多页应用工作流

毛病:如果需要task之间的同步依赖关系,那么上一个task function里面需要有return;各个task的依赖,应该用gulpSequence做拉平。

var gulp = require('gulp'),
sass = require('gulp-sass'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
browserSync = require('browser-sync').create(),
open = require('gulp-open'),
del = require('del'),
usemin = require('gulp-usemin'),
// useref = require('gulp-useref'),// 这个相对目录有问题 妈的 不用了
zip = require('gulp-zip'),
gulpRevAll = require('gulp-rev-all'),
revReplace = require("gulp-rev-replace"),
uglify = require('gulp-uglify'),
minifyCss = require('gulp-minify-css'), Replace = require('gulp-replace'),
htmlmin = require('gulp-htmlmin'),
gulpSequence = require('gulp-sequence'),
argv = require('yargs').argv; // node命令传入的参数整合参数 /**************************配置项**************************/
var _opt = {
src: 'app/',
// src: 'dist/sce/app/',
// devHost:"sns-operating-dev.sohuno.com",
// devHost: "dev.w.sohu.com", //默认当前局域网ip
// startPath: '/view/intro.html',
startPath: '/view/index.html', dest: 'dist/',
tem: 'tem/',
revDelay: 5, //单位秒
staticInCDN: true, //默认放cdn
cdnPath: '//sns_business.cdn.sohusce.com/square-unlogin-v3/',
// staticProxyPath: '/h5static/',//需要代理的静态资源路径标记
sce: {
// releaseUrl: 'http://fe.w.sohu.com/h5apps/sns-square-test/view/intro.html', //线上或测试环境的项目url
manageUrl: '//console.sce.sohuno.com/apps/versions?appid=',
path: 'sce/',
yamlPath: 'sce/app.yaml',
appPath: 'sce/app/',
confPath: 'sce/conf/',
test: { //暂仅测试环境 这里需要优化配置 gulp发布的时候带上环境参数 如gulp r --test/product
appId: 212250773,
sceHost: '//sns-square-unlogin-v30-test.sce.sohuno.com',
backendHost: {
'sns-core': 'sns-api.apps.sohuno.com', //sns-data-api-test.sce.sohuno.com sns-api.apps.sohuno.com msapi.t.sohu.com
// 'sns-data':'sns-data-api-test.sce.sohuno.com'
}
},
product: {
appId: 985464923,
sceHost: '//sns-square-unlogin-v30.sce.sohuno.com',
backendHost: {
'sns-core': 'sns-api.apps.sohuno.com',
// 'sns-data':'sns-data.sohuno.com'
}
}
}
}; /**************************本地开发Server**************************/
var _env = _opt.sce[Object.keys(argv)[1]] ? Object.keys(argv)[1] : 'test';
console.log("● serverPath:" + _opt.src);
console.log("● serverEnv:" + _env); // 静态服务器
gulp.task('serve', ['sass'], function() {
var proxyMiddleware = require('http-proxy-middleware');
var proxy = proxyMiddleware(['/sns-core'], {
target: 'http://' + _opt.sce[_env].backendHost['sns-core'],
pathRewrite: {
'^/sns-core/(.*)': '/$1'
},
changeOrigin: true,
headers: {
host: _opt.sce[_env].backendHost['sns-core'],
origin: 'http://' + _opt.sce[_env].backendHost['sns-core']
}
}); //禁止开发server的缓存
var proxyNoCache = function(req, res, next) {
res.setHeader('CacheControl', 'no-cache');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '-1');
res.setHeader('ETag', Date.now()); //禁止304
next();
} browserSync.init({
server: {
baseDir: _opt.src //_opt.dest//''//''// _opt.dest,//_opt.dest src
},
ui: {
port: 3030
},
host: _opt.devHost, //hosts文件设置代理到开发机IP server种cookie用
open: "external", //
startPath: _opt.startPath,
ghostMode: false, //关掉多设备同步
middleware: [proxy, proxyNoCache]
}); gulp.watch(_opt.src + "/static/scss/*.scss", ['sass']);
gulp.watch([_opt.src + "/static/js/**",
_opt.src + "/static/img/**",
_opt.src + "/**/*.html"
]).on('change', browserSync.reload);
}); // gulp.task('rrr', function() {
// return gulp.src([_opt.src + "/static/scss/sns-base.scss"], {
// base: _opt.src + "/static/scss/"
// })
// .pipe(Replace(/\n[\t\u0020]*?\/\/.+?\n/g,"\n\n"))
// .pipe(gulp.dest(_opt.src + "/static/acss/"))
// }); gulp.task('sass', function() {
var postPlugins = [
autoprefixer() //browserlist read from package.json //取值https://github.com/ai/browserslist#queries
];
return gulp.src([_opt.src + "/static/scss/**/*.scss"], {
base: _opt.src + "/static/scss/"
})
// auto append night mode(.night),color base scss/_const.scss
// 以后抽象成一个插件
// 最好的实现不是预先删除注释,而应该是不去替换注释里的夜色才对 @20180119
// 有个bug 启动的时候可以注掉 修改scss后的reload任务不好使
// 干掉scss中的注释 避免下面的夜色模式替换 把注释里的也给替换了导致scss结构错乱报错
.pipe(Replace(/([\s;])\/\/.+?(?=\n)/g, function(s, m1) {
//删掉空字符或者;后面的单行注释内容;
//这个正则引擎 不支持肯定逆序表达式 (?<=[\s;]) 只能function return m1了
return m1;
}))
.pipe(Replace(/\/\*.+?\*\//g,''))//删掉块级注释 咦尼玛 这个怎么不好使 见main.css
//_const.scss中色值变量命名 需遵循规范 $c-grey1:#000; $c-night-grey1:#454545;
.pipe(Replace(/([\w-]+?\s*?\:.*\$c-.+?;)/g, function(s, m1, m2) {
// console.log('----\r\n'+m1+'\r\n----\r\n');
var m1_night = m1.replace(/\$c-/g, '$c-night-');
return m1 + '\n @at-root .night &{' + m1_night + '}\n';
}))
.pipe(sass())
.on('error', function(err) {
console.log('Less Error!', err.message);
this.emit('end');
})
.pipe(postcss(postPlugins))
.pipe(gulp.dest(_opt.src + "/static/css/"))
.pipe(browserSync.reload({ stream: true }));
}); // gulp.task('openUrl', function() {
// console.log('----打开sce线上url,fiddler代理至本地');
// gulp.src(__filename)
// .pipe(open({ uri: _opt.sce.releaseUrl, app: "chrome" }));
// }); /**************************临时工具处理**************************/
//图片压缩 非尺寸
gulp.task('imgmin1', function() {
var imagemin = require('gulp-imagemin');
// gulp.src(_opt.src+'/img/*.+(png)')
gulp.src(_opt.src + '/static/img/**/*.png', {
base: _opt.src
})
.pipe(imagemin())
.pipe(gulp.dest(_opt.src));
}); /**************************打包发布正式方案**************************/ gulp.task('delDest', function() {
// console.log("● 环境:"+_env);
var path = _opt.dest;
console.log('----清空目录' + path);
return del(path);
});
gulp.task('tem', ['delDest'], function() {
var path = _opt.tem;
console.log('----清空目录' + path);
return del(path);
}); gulp.task('delTem', function() {
var path = _opt.tem;
console.log('----清空目录' + path);
return del(path);
});
gulp.task('delSceApp', function() {
var path = _opt.sce.appPath;
console.log('----清空目录' + path);
return del(path);
});
// 拷贝文件
gulp.task('copy2tem', ['delDest', 'delTem', 'sass'], function() {
console.log('----拷贝文件到临时文件夹');
return gulp.src([
_opt.src + '/static/**',
_opt.src + '/view/**',
'!' + _opt.src + '/static/scss/**'
], {
base: _opt.src
})
.pipe(gulp.dest(_opt.tem));
});
// 合并
gulp.task('usemin', ['copy2tem'], function() { //
return gulp.src([
_opt.tem + 'view/**/*.html'
], {
base: _opt.tem
})
.pipe(usemin({ //成功的先不上报处理了
jsAttributes: {
// onload: 'window.srcLoadLog && srcLoadLog(this)',
onerror: 'window.srcErrorLog && srcErrorLog(this)'
},
cssAttributes: {
// onload: 'window.srcLoadLog && srcLoadLog(this)',
onerror: 'window.srcErrorLog && srcErrorLog(this)'
} }))
.pipe(gulp.dest(_opt.tem));
}); //js压缩
gulp.task('jsmin', ['usemin'], function() {
console.log('----压缩js');
return gulp.src([
_opt.tem + '/static/js/**/*.js',
'!' + _opt.tem + '/static/js/**/*.min.js'
], {
base: _opt.tem
})
// .pipe(uglify())
.pipe(uglify({
compress: {
// "quote-keys":true//ie8
// properties:false,
drop_console: true
}
// quote_keys: true
// beautify : { beautify: false, ascii_only: true, quote_keys: true }
}))
.pipe(gulp.dest(_opt.tem));
});
//css压缩
gulp.task('cssmin', ['usemin'], function() {
console.log('----压缩CSS');
return gulp.src([
_opt.tem + '/static/css/**/*.css',
'!' + _opt.tem + '/static/css/*.min.css'
], {
base: _opt.tem
})
.pipe(minifyCss())
.pipe(gulp.dest(_opt.tem));
}); // 加MD5戳
gulp.task('revAll', ['jsmin', 'cssmin'], function() { //
console.log('----加MD5戳&替换相互引用(延时' + _opt.revDelay + 's后进行下一任务)');
// var revAll = new RevAll({
// dontRenameFile: [/^\/static\/img\/ad-avatar/]//ad-avatar前端不直接用 手动替换后上传cdn给server下发用
// // ,dontGlobal:[]
// // ,dontSearchFile:[/^\/static\/js\//]//dontSearchFile 对js/xx/下的路径文件 不做内容中的引用替换处理
// }); gulp.src([_opt.tem + '/*/**'], { ///static/**
base: _opt.tem
})
.pipe(gulpRevAll.revision({
dontRenameFile: [/^\/view\//, /^\/static\/img\/ad-avatar/] //ad-avatar前端不直接用 手动替换后上传cdn给server下发用
// ,dontGlobal:[]
,
dontSearchFile: [/^\/static\/js\//] //dontSearchFile 对js/xx/下的路径文件 不做内容中的引用替换处理
}))
.pipe(gulp.dest(_opt.tem))
.pipe(gulpRevAll.versionFile())
.pipe(gulp.dest(_opt.tem))
.pipe(gulpRevAll.manifestFile())
.pipe(gulp.dest(_opt.tem));
}); //htmlmin
gulp.task('htmlmin', function() { //
console.log('----htmlmin');
return gulp.src([
_opt.tem + '/**/*.html' // '!'+_opt.dest+'/tpls/write/write.html'
], {
base: _opt.tem
})
.pipe(htmlmin({
collapseWhitespace: true,
removeComments: true,
minifyCSS: true,
minifyJS: true
}))
.pipe(gulp.dest(_opt.tem + '/'));
});
//加cdn前缀
gulp.task('cdnPre', ['htmlmin'], function() {
if (!_opt.staticInCDN) return false;
console.log('----加CDN前缀');
return gulp.src([
_opt.tem + '/**/*.html'
// ,_opt.dest + '/static/js/common/myLib.*.js'
], {
base: _opt.tem
}) //下面日后写成通配符严格匹配 path/**.xxx 上面的js就可以写成all js了
.pipe(Replace(/"[./]*static\//g, '"' + _opt.cdnPath)) //有点风险 日后优化
.pipe(gulp.dest(_opt.tem + '/'));
});
//imgmin - 这个任务时间太长 依赖建立不起来,r完了还会在压着,所以从gulp 抽成单独一项任务,gulp serve前手动搞
// gulp.task('imgmin',['copy2tem'], function() {
// var imagemin = require('gulp-imagemin');
// // gulp.src(_opt.src+'/img/*.+(png)')
// gulp.src(_opt.tem + '/static/img/**/*.png', {
// base: _opt.tem
// })
// .pipe(imagemin())
// .pipe(gulp.dest(_opt.tem));
// }); //拷贝sce基础文件至dist
gulp.task('sce_base2dist', function() {
console.log('----拷贝sce基础文件到发布目录');
return gulp.src([
_opt.sce.path + "/**"
], {
base: _opt.sce.path
})
.pipe(gulp.dest(_opt.dest + "/sce"));
});
// 根据环境修改sce appId
gulp.task('sceConfigInit', ['sce_base2dist'], function() {
console.log('----sce配置初始化');
// return gulp.src(_opt.sce.yamlPath)
return gulp.src([
_opt.dest + _opt.sce.yamlPath,
_opt.dest + _opt.sce.confPath + '/nginx_server.inc'
], {
base: _opt.dest
}) //backendHost 下面正则优化 增强匹配的严谨性--这里以后改成写入而不是 替换是不是能好一些
.pipe(Replace(/appid: \d+/, 'appid: ' + _opt.sce[_env].appId))
.pipe(Replace(/server_sns-core(?=[;/ ])/g, _opt.sce[_env].backendHost['sns-core']))
.pipe(gulp.dest(_opt.dest));
}); // 拷贝文件
gulp.task('tem2sceDist', ['cdnPre'], function() {
console.log('----拷贝项目文件到dist/sce目录');
return gulp.src([
_opt.tem + "/**",
'!' + _opt.tem + 'rev-*.json'
], {
base: _opt.tem
})
.pipe(gulp.dest(_opt.dest + _opt.sce.appPath));
});
// 静态资源压缩zip for cdn
gulp.task('static2zip', ['cdnPre'], function() {
if (!_opt.staticInCDN) return false;
console.log('----静态资源to zip for cdn');
var cdn_project_name = 'toCDN_' + _opt.cdnPath.match(/\/\/(.+?)\.cdn/)[1] + '_' + _opt.cdnPath.replace(/.+\.com\//, "").replace(/\//g, "") + ".zip";
// var cdn_project_name = 'toCDN_' + _opt.staticProxyPath.replace(/\//g, "") + ".zip";
return gulp.src([
_opt.tem + '/static/**'
], {
base: _opt.tem + '/static/'
})
.pipe(zip(cdn_project_name))
.pipe(gulp.dest(_opt.dest)); //剔除rev map文件、zip打包文件 需要优化
}); // sce项目zip
gulp.task('sce2zip', ['tem2sceDist', 'sceConfigInit'], function() {
console.log('----sce to zip');
var zip_name = 'sce_' + _opt.sce[_env].appId + '.zip';
return gulp.src([_opt.dest + _opt.sce.path + '/**'])
.pipe(zip(zip_name))
.pipe(gulp.dest(_opt.dest));
}); //发布
gulp.task('packContinue', ['sce2zip', 'static2zip'], function() {
console.log('----清除临时文件');
// 清除临时文件
del(_opt.tem);
console.log('● 环境:' + _env);
console.log('● 前端项目已发布到' + _opt.dest);
if (_opt.staticInCDN) console.log('○ 静态资源zip请上传至:' + _opt.cdnPath);
console.log('○ sce zip请上传至:' + _opt.sce.manageUrl + _opt.sce[_env].appId);
console.log('● sce前端服务host:' + _opt.sce[_env].sceHost); console.log('----完成!');
});
// 发布-cdn
gulp.task('r', ['revAll'], function(cb) {
// console.log("----环境:"+_env);
setTimeout(function() { //延时太挫 待优化 https://github.com/gulpjs/gulp/issues/96
gulpSequence('packContinue', cb);
}, _opt.revDelay * 1000); //revAll 延时
});
// 发布-local
gulp.task('r:local', ['revAll'], function(cb) {
_opt.staticInCDN = false;
// console.log("----环境:"+_env);
setTimeout(function() { //延时太挫 待优化 https://github.com/gulpjs/gulp/issues/96
gulpSequence('packContinue', cb);
}, _opt.revDelay * 1000); //revAll 延时
});

2. 优化迭代了多个版本的比较完美的脚手架

优点:模块化拆分、回调拉平、功能配置化

let gulp = require('gulp'),
config = require('./config.js'),
del = require('del'),
requireDir = require('require-dir'),
chalk = require('chalk'),
runSequence = require('run-sequence'); console.log('Waiting For Gulp Tasks Loading ...' + '\n'); let {
NODE_ENV: env,
CDN: cdn
} = process.env; // 递归引入gulp/tasks目录下的文件,该操作比较耗时(稍弱些的机器配置 14s左右)
requireDir('./gulp/tasks', {
recurse: true
}); if (env !== 'dev') {
console.log('\n\n/*********************** 打包开始,当前环境为:' + chalk.blue.bold(env) + ' ***********************/' + '\n');
}
gulp.task('build', function(cb) { //默认不放 CDN
del.sync(config.temp);
del.sync(config.dist);
runSequence(['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['uncss'], ['sprite'],['jscss2dist'], ['usemin'], ['cssmin', 'jsmin', 'htmlmin'], ['revision'], ['cdnPre'], ['delRedundant'], ['zip'], ['openUrl'], function() {
if (cdn === 'true') console.log('○ 静态资源zip请上传至:' + config.cdnPath);
console.log('○ sce zip请上传至:' + config.sce.manageUrl + config.sce[env].appId);
console.log('\n\n/*********************** 打包结束,当前环境为:' + chalk.blue.bold(env) + ' ***********************/' + '\n');
});
}) //不做jscss合并等工作 直接打包
gulp.task('build:dev', function(cb) {
del.sync(config.temp);
del.sync(config.dist);
runSequence(['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['sprite'],'temp2dist', ['zip'], ['openUrl'], function() {
if (cdn === 'true') console.log('○ 静态资源zip请上传至:' + config.cdnPath);
console.log('○ sce zip请上传至:' + config.sce.manageUrl + config.sce[env].appId);
console.log('\n\n/*********************** 打包结束[纯开发包],当前环境为:' + chalk.blue.bold(env) + ' ***********************/' + '\n');
});
}) gulp.task('dev', function(cb) {
del.sync(config.temp);
config.buryPointSwitch = false;
config.isImgOptmize = false;
runSequence(['svg'], ['fileInclude', 'eslint', 'ES6', 'imgMin'], ['sass'], ['sprite'], ['dev-server'], cb);
}); //打包到dist 且启动目录改到dist(用来本地测试打包后的页面运行 注:需要去dev-server改一下serverPath)
gulp.task('dev:dist', function(cb) {
del.sync(config.temp);
config.buryPointSwitch = false;
config.isImgOptmize = false;
// runSequence(['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['sprite'],'temp2dist', ['dev-server'], cb);
runSequence( ['delRedundant'], ['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['uncss'], ['sprite'], ['usemin'], ['cssmin', 'jsmin', 'htmlmin'], ['revision'],'dev-server', cb);
});

前后端分离+本地服务实时刷新+缓存管理+接口proxy+静态资源增量更新+各种性能优化+上线运维发布——gulp工作流搭建的更多相关文章

  1. 前后端分离中的无痛刷新token机制

    今天我们来说一说前后端分离中的无痛刷新token机制 博主先来分享一波福利,最近挖到的宝藏,刚开始学Java的同学看 https://www.bilibili.com/video/BV1Rx41187 ...

  2. laravel前后端分离的用户登陆 退出 中间件的接口与session的使用

    在项目开发的过程中,需要有用户的登陆 退出 还有校验用户是否登陆的中间件; 基本思路: 登陆: 前端请求接口的参数校验 用户名 密码规则的校验 用户名密码是否正确的校验; 如果上面的校验都通过的了,把 ...

  3. 微服务-Springboot+Redis缓存管理接口代码实现

    废话少说,上代码,结合代码讲解: 一.创建maven工程:导入依赖: <packaging>war</packaging><!--修改jdk的版本--><pr ...

  4. mock的使用及取消,node模仿本地请求:为了解决前后端分离,用户后台没写完接口的情况下

    借鉴:https://www.jianshu.com/p/dd23a6547114 1.说到这里还有一种是配置node模拟本地请求 (1)node模拟本地请求: 补充一下 [1]首先在根目录下建一个d ...

  5. 前后端分离——token超时刷新策略

    前言 记录一下前后端分离下————token超时刷新策略! 需求场景 昨天发了一篇记录 前后端分离应用——用户信息传递 中介绍了token认证机制,跟几位群友讨论了下,有些同学有这么一个疑惑:toke ...

  6. 基于 Spring Security 的前后端分离的权限控制系统

    话不多说,入正题.一个简单的权限控制系统需要考虑的问题如下: 权限如何加载 权限匹配规则 登录 1.  引入maven依赖 1 <?xml version="1.0" enc ...

  7. 在前后端分离项目中使用SpringBoot集成Shiro

    前言 这次在处理一个小项目时用到了前后端分离,服务端使用springboot2.x.权限验证使用了Shiro.前后端分离首先需要解决的是跨域问题,POST接口跨域时会预发送一个OPTIONS请求,浏览 ...

  8. 基于Vue的前后端分离项目实践

    一.为什么需要前后端分离 1.1什么是前后端分离  前后端分离这个词刚在毕业(15年)那会就听说过,但是直到17年前都没有接触过前后端分离的项目.怎么理解前后端分离?直观的感觉就是前后端分开去做,即功 ...

  9. SpringMVC+Spring+mybatis+maven+搭建多模块框架前后端分离开发框架的完整demo,拿走不谢。——猿实战02

            猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是 ...

随机推荐

  1. 【BZOJ 3569】DZY Loves Chinese II

    题面 Description 神校XJ之学霸兮,Dzy皇考曰JC. 摄提贞于孟陬兮,惟庚寅Dzy以降. 纷Dzy既有此内美兮,又重之以修能. 遂降临于OI界,欲以神力而凌♂辱众生. 今Dzy有一魞歄图 ...

  2. C/C++ 无法解析的外部符号解决方案

    { //0 类的成员函数没有实现就调用 //1 调用没有编译生成cpp 的函数 //2 没有加载lib //3 最重要的就是有声明无实现 }

  3. Dart编程判断

    条件/决策构造在执行指令之前评估条件. 下表是Dart中的条件语句 序号 声明和说明 1 if 语句 一个if语句由一个布尔表达式后跟一个或多个语句. 2 If...Else 语句 一个if可以跟一个 ...

  4. OpenSceneGraph | OSG如何存储带纹理osgb格式可以节省空间

      在使用OSG(OpenSceneGraph)存储带纹理osgb格式的过程中,大家会遇到这样一种情况:存储后的osgb文件所占用的大小远大于原始文件的大小,几倍至几十倍.这是为何呢?原因是OSG默认 ...

  5. NX二次开发-UFUN工程图插入PNG图片UF_DRF_create_image_from_file

    #include <uf.h> #include <uf_drf.h> UF_initialize(); //插入PNG char* file_name = "D:\ ...

  6. NX二次开发-NXOPEN创建工程图表格Annotations::TableSectionBuilder *tableSectionBuilder1;

    NX9+VS2012 #include <uf.h> #include <uf_tabnot.h> #include <NXOpen/Part.hxx> #incl ...

  7. [JZOJ 5814] 树

    题目:从u到v经过多少条边. 思路: 考虑他是怎么走的?? 从\(u\)到\(v\)一定是\(fa[u]\),\(fa[fa[u]]\),反正就是走\(LCA\),那么如果算出每个点到父亲的期望步数, ...

  8. HDU6181-求解次短路-A*或者dijkstra

    (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 题意:传送门  原题目描述在最下面.  次短路裸题. 思路:  在dijstra的过程过维护两个数组变量:\(dis1[],dis2[ ...

  9. Area--->AreaRegistrationContext.MapRoute

    文章引导 MVC路由解析---IgnoreRoute MVC路由解析---MapRoute MVC路由解析---UrlRoutingModule Area的使用 Area--->AreaRegi ...

  10. python批量运行py文件

    import os path="E:\\python" #批量的py文件路径 for root,dirs,files in os.walk(path): #进入文件夹目录 for ...