个人比价推崇前后端分离的开发方式,大家伙各司其职,只需通过 API 进行交流,不仅避免了沟通上的成本,更提升了开发效率。而在前端开发工作中,许多需求和问题是相似的,所以我们的开发模式往往是雷同的,是否能够总结出一套通用的模式呢?

(备份一个webpack的中文网站:https://angular.cn/docs/ts/latest/guide/webpack.html)

日常前端开发的处境

1、 开发流程相似

​ 前端开发工作包含哪些?html、css、js,对应的工程目录也相似,每次重新创建都要耗费一些时间。

2、 需求更改频繁

​ 开发们都推崇两个字“复用”,那么是什么阻碍了代码的复用?答:产品经理的需求变更。虽然有些搞笑的成分,但毋庸置疑,前端开发中需求频繁更改是非常常见的,我们可不想因为一条样式修改而找遍所有文件。

3、 如何跨域

​ 如何跨域是每个前端必须面对的,最优的解决方案是服务器的反向代理来实现,而多数前端都没有这方面的经验。幸好,在开发环境中,我们可以利用 node 或者 gulp 来解决跨域问题。

​ 之前我的一篇博客介绍了利用node.js进行跨域访问:http://www.cnblogs.com/fayin/p/6628150.html

​ 今天,我将介绍用gulp搭建工作流,并带来第二种前端跨域的方式。

点击:这里查看完整代码

gulp 搭建工作流

首先介绍下安装依赖,明确有哪些task:

  • gulp-load-plugins:用来加载插件,避免我们再头部声明一堆插件,做到想用就用
  • less:用于编译 .less文件
  • autoprefixer:自动添加css前缀
  • babel:es6 编译成 es5
  • uglify:JS压缩
  • minify:CSS压缩
  • rename:重命名
  • sourcemaps:资源映射
  • concat:合并文件
  • del:删除文件、文件夹
  • inject:文件注入
  • notify:提示信息
  • browser-sync:热启动
  • http-proxy-middleware:配合browser-sync进行跨域
  • changed:只有发生了改变的文件才能进入流中
  • sequence:让task按顺序完成
  • rev:添加MD5
  • watch:监听文件变化

gulpfile.js

/**
* gulp mask list
*
* gulp-load-plugins
*
* babel, less, uglify, browser-sync, del, autoprefixer, concat, minifyCss, rename
* sourcemaps, inject, notify
*
*/ const APIURL = 'http://192.168.1.30:6760';
const ISPROXY = false; const DEV_PRO = false; const
fs = require('fs'),
path = require('path'),
gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
del = require('del'),
browserSync = require('browser-sync').create(),
reload = browserSync.reload,
plugins = gulpLoadPlugins(),
sequence = require('gulp-sequence'),
gulpCopy = require('gulp-file-copy'),
proxy = require('http-proxy-middleware'),
fileinclude = require('gulp-file-include'),
pngquant = require('imagemin-pngquant'),
mozjpeg = require('imagemin-mozjpeg'),
merge = require('merge-stream'); const DIST = 'dist',
SRC = 'dist'; const getFolders = (dir)=> {
return fs.readdirSync(dir)
.filter((file)=> {
return fs.statSync(path.join(dir, file)).isDirectory();
})
};
const getError = function(err) {
console.log(err.toString());
this.emit('end');
}; gulp.task('clean', function () {
return del(['dist/**/*'])
}); gulp.task('clean-css', function () {
return del(['dist/css/**/*.*'])
}); gulp.task('clean-js', function () {
return del(['dist/js/*.*'])
}); gulp.task('include', function () {
return gulp.src('src/*.html')
.pipe(plugins.changed(DIST))
.pipe(fileinclude({
prefix: '@@',
basepath: '@file'
}))
.pipe(plugins.debug({title: '文件引入:'}))
.pipe(gulp.dest('dist'))
}); gulp.task('css', ()=> {
let commonStyle = gulp.src('src/less/*.less',{base: 'src/less'})
.pipe(plugins.changed(DIST, {extension: '.css'}))
//.pipe(plugins.watch('src/less/*.less'))
.pipe(plugins.sourcemaps.init())
.pipe(plugins.less())
.on('error', getError)
.pipe(plugins.autoprefixer({
browsers: ['last 4 version','Android >= 4.0'],
cascade: true,
remove: true
}))
.pipe(plugins.concat('common.css'))
.pipe(plugins.minifyCss())
.pipe(plugins.rename({suffix: '.min'}))
//.pipe(plugins.rev()) // 添加md5
.pipe(plugins.sourcemaps.write('.'))
.pipe(plugins.debug({title: '编译css:'}))
.pipe(gulp.dest('dist/css'))
.pipe(browserSync.stream({match: '**/*.css'}));
// .pipe(gulp.rev.manifest())
// .pipe(gulp.dest('dist/rev'))
let lessPath = 'src/less';
let folders = getFolders(lessPath); let folderStyle = folders.map((folder)=> {
let newPath = path.join(lessPath, folder, '/*.less');
return gulp.src(newPath)
.pipe(plugins.changed(DIST, {extension: '.css'}))
//.pipe(plugins.watch(newPath))
.pipe(plugins.sourcemaps.init())
.pipe(plugins.less())
.pipe(plugins.autoprefixer({
browsers: ['last 4 version','Android >= 4.0'],
cascade: true,
remove: true
}))
.pipe(plugins.concat(folder+'.css'))
.pipe(plugins.minifyCss())
.pipe(plugins.rename({suffix: '.min'}))
//.pipe(plugins.rev()) // 添加md5
.pipe(plugins.sourcemaps.write('.'))
.pipe(plugins.debug({title: '编译foldercss:'}))
.pipe(gulp.dest('dist/css/'+folder))
.pipe(browserSync.stream({match: '**/*.css'}));
});
return merge(commonStyle, folderStyle);
}); gulp.task('es6ToEs5', function () {
return gulp.src('src/js/**/*.js')
.pipe(plugins.changed(DIST, {extension: '.js'}))
.pipe(plugins.sourcemaps.init())
.pipe(plugins.babel({
presets: ['es2015']
}))
.on('error', getError)
//.pipe(plugins.concat('main.js'))
.pipe(plugins.uglify())
.pipe(plugins.rename({suffix: '.min'}))
//.pipe(plugins.rev())
.pipe(plugins.sourcemaps.write('.'))
.pipe(plugins.debug({title: '编译js:'}))
.pipe(gulp.dest('dist/js'))
.pipe(browserSync.stream({match: '**/*.js'}));
}); gulp.task('rev',['css'],function() {
return gulp.src(['dist/rev/rev-manifest.json','dist/*.html']) //获取rev-manifest.json和要替换的html文件
.pipe(plugins.revCollector({
replaceReved: true //根据rev-manifest.json的规则替换html里的路径,由于替换是根据rev-manifest.json规则来的,所以一定要先生成这个文件再进行替换
}))
.pipe(gulp.dest('dist'))
.pipe(browserSync.stream({match: '**/*.css'}));
//.pipe(plugins.notify('md5 success!!!!'))
}); gulp.task('copy', function () {
let start = 'src/lib/*.*',
start2 = 'src/images/**/*.*';
let copyLib = gulp.src(start)
.pipe(plugins.changed(DIST))
.pipe(gulpCopy('dist/lib', {
start: 'src/lib'
})); let copyImages = gulp.src(start2)
.pipe(plugins.changed(DIST))
.pipe(plugins.imagemin(
[pngquant(), mozjpeg()],
{verbose: true}
))
.pipe(gulp.dest('dist/images'));
return merge(copyLib, copyImages)
}); gulp.task('injectFile', function () {
let target = ['src/*.html','!src/_head.html'],
target2 = ['dist/lib/*.js', 'dist/js/*.js', 'dist/css/*.css'],
sources = gulp.src(target2, {'read': false});
return gulp.src(target)
.pipe(plugins.changed(DIST))
.pipe(fileinclude({
prefix: '@@',
basepath: '@file'
}))
.pipe(plugins.inject(sources, {relative: true}))
.pipe(plugins.debug({title: '注入:'}))
.pipe(gulp.dest('dist'))
.pipe(browserSync.stream({match: '**/*.html'}));
//.pipe(plugins.notify('inject success'))
}); gulp.task('watch-css', function (callback) {
sequence('rev', 'injectFile', callback)
}); gulp.task('watch-js', function (callback) {
sequence('es6ToEs5', 'injectFile', callback)
}); gulp.task('del-maps', function () {
return del(['dist/**/*.map']);
}); gulp.task('html-watch', ['injectFile'], function (done) {
browserSync.reload();
done();
}); gulp.task('server', function() {
const aipProxy = proxy('/api', {
target: APIURL,
changeOrigin: true,
ws: true
}); if (!ISPROXY) {
browserSync.init({
// files:'**',
server: {
baseDir: './'
}
});
}else {
browserSync.init({
server: {
baseDir: './',
middleware: [aipProxy]
}
});
} gulp.watch(['src/*.html'], ['injectFile']);
gulp.watch(['src/images/**/*.*'], ['copy']);
gulp.watch(['src/less/**/*'], ['watch-css']);
gulp.watch(['src/js/**/*.js', 'src/lib/*.*'], ['watch-js']);
gulp.watch(['dist/*.html']).on('change', browserSync.reload);
gulp.watch(['src/**/**'])
.on('change', function (event) {
if(event.type == 'deleted') {
let _path = event.path,
cssPath = _path.replace(/src\\less/, 'dist\\css');
console.log(cssPath);
if(path.extname(_path) === '.less') {
del(path.dirname(cssPath)+'/*.*');
sequence('rev', 'injectFile');
}else {
del(_path.replace(/src/, 'dist'))
} }
})
.on('error', function (err) {
console.log(err)
});
//browserSync.watch('./src/**/*.*').on('change',reload);
//browserSync.watch('./dist/**/*').on('change',reload);
}); gulp.task('dev', sequence('clean', ['rev', 'es6ToEs5','copy'], 'injectFile', 'server')); gulp.task('build-pro', sequence('clean',['rev', 'es6ToEs5', 'copy'],'injectFile', 'del-maps'));

目录

gulp 搭建个人工作流:文件注入、热启动、跨域的更多相关文章

  1. nginx处理vue打包文件后的跨域问题

    起因 在vue文件打包后,项目脱离了vue配置的反向代理配置,还是会报跨域的错误,或者直接打不开本地文件, 但是此刻我们想打开打包后的文件,测试一下文件有没有错误,因为经常会存在开发阶段没有问题,打包 ...

  2. Springboot 项目源码 Activiti6 工作流 vue.js html 跨域 前后分离 websocket即时通讯

    特别注意: Springboot 工作流  前后分离 + 跨域 版本 (权限控制到菜单和按钮) 后台框架:springboot2.1.2+ activiti6.0.0+ mybaits+maven+接 ...

  3. springcloud 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离

    1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...

  4. spring cloud 框架源码 activiti工作流 vue.js html 跨域 前后分离 springboot

    1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...

  5. springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离

    1.代码生成器: [正反双向](单表.主表.明细表.树形表,快速开发利器)freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本.处理类.service等完整模块2. ...

  6. plupload 如何控制最小宽度和文件类型及跨域

    直接上代码 plupload.addFileFilter('min_width', function (maxwidth, file, cb) { var self = this, img = new ...

  7. 阿里云OSS上传文件本地调试跨域问题解决

    问题描述: 最近后台说为了提高上传效率,要前端直接上传文件到阿里云,而不经过后台.因为在阿里云服务器设置的允许源(region)为某个固定的域名下的源(例如*.cheche.com),直接在本地访问会 ...

  8. 文件上传跨域解决方案-jQuery-File-Upload

    GIT 下载地址 https://github.com/blueimp/jQuery-File-Upload 亲测HTTPS HTTP跨域无压力 不用自带的DEMO 用下面的DEMO <!DOC ...

  9. EIP权限工作流平台总结-4跨域配置

    1.预览地址:www.eipflow.com (1) 权限工作流:www.demo.eipflow.com/Account/Login (2) 基础权限版:www.auth.eipflow.com/A ...

随机推荐

  1. PLSQL Developer工具的使用

    1.运行 2.字体大小 导入csv文件. 任何工具都有失败的可能, 这个时候,也失败了. 当然还有另一种可能,文件被人为改过了,括号改过了,就即使使用下面的kettle工具也没用了.这时可以导出文件对 ...

  2. 最大正方形 · Maximal Square

    [抄题]: 在一个二维01矩阵中找到全为1的最大正方形 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 返回 4 [暴力解法]: 时间分析: 空间分析:i j 中保留一 ...

  3. Qt的安装和使用中的常见问题(详细版)

    对于太长不看的朋友,可参考Qt的安装和使用中的常见问题(简略版). 目录 1.引入 2.Qt简介 3.Qt版本 3.1 查看安装的Qt版本 3.2 查看当前项目使用的Qt版本 3.3 查看当前项目使用 ...

  4. NormalMap原理详细解析

    NormalMap的实现标志着对渲染流水线的各个环节以及矩阵变化有了正确和深入的认识.这里记录一下学习过程,以及关于NormalMap的诸多细节. 刚开始想要实现NormalMap程序的时候,查阅的是 ...

  5. [Training Video - 2] [Groovy Introduction]

    Building test suites, Test cases and Test steps in SOAP UI Levels : test step level test case level ...

  6. Java Thread系列(三)线程安全

    Java Thread系列(三)线程安全 一.什么是线程安全 线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的. 线程安全来 ...

  7. Mac之如何查看已用端口

    一.苹果自带的网络分析工具查看方法:       OS X 10.9 下面 网络实用工具 从实用工具目录里消失了,可能苹果认为这个程序用的人太少就取消了吧.但是对于做互联网的人还是有点用的. 启动方法 ...

  8. win7搭建node+npm+bower的环境

    原文的地址:https://my.oschina.net/JeeChou/blog/219699 Windows下的NodeJS安装是比较方便的(v0.6.0版本之后,支持windows native ...

  9. (二分搜索 )Strange fuction -- HDU -- 2899

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=2899 Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  10. ETL 运行维护

    装载数据仓库过程中,不管作业是实时执行还是批处理方式执行,其调度时间,执行顺序和执行环境都是关键点. 本章描述创建一个ETL操作策略,来保证数据仓库的数据即时可用. ETL执行策略分为两种:1 调度 ...