个人比价推崇前后端分离的开发方式,大家伙各司其职,只需通过 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. 滑动窗口的中位数 · Sliding Window Median

    [抄题]: 给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,找到数组中每个窗口内的中位数.(如果数组个数是偶数,则在该窗口排序数字后,返回第 N/2 个数字 ...

  2. 字符编码codecs模块(读写文件)

    python对多国语言的处理是支持的很好的,它可以处理现在任意编码的字符,这里深入的研究一下python对多种不同语言的处理.有一点需要清楚的是,当python要做编码转换的时候,会借助于内部的编码, ...

  3. Python爬虫利器六之PyQuery的用法

    前言 你是否觉得 XPath 的用法多少有点晦涩难记呢? 你是否觉得 BeautifulSoup 的语法多少有些悭吝难懂呢? 你是否甚至还在苦苦研究正则表达式却因为少些了一个点而抓狂呢? 你是否已经有 ...

  4. msys2 + clion安装所需的mingw64编译环境

    pacman -S mingw-w64-x86_64-toolchain 输出结果为: $ pacman -S mingw-w64-x86_64-toolchain:: 在组 mingw-w64-x8 ...

  5. 15 Independent Alleles

    Problem Figure 2. The probability of each outcome for the sum of the values on two rolled dice (blac ...

  6. Atom 编辑器侧边栏忽略隐藏文件

    设置中配置需要忽略的文件后缀 package中找到treeview,勾选上这个配置就行

  7. ACTIVITI 5.14事件监听器的BUG

    在ACTIVITI 5.14中,测试内部子流程时发现事件定义的事件监听器不能触发. <activiti:executionListener event="start" del ...

  8. swoole实现websocket推送

    环境配置:      swoole 1.9.3.centos6.5(虚拟机).PHP7.01   思路:      ①通过server中的collections取出fd      ②写一个admin. ...

  9. SOA和微服务到底是什么关系?

    SOA和微服务到底是什么关系? 说实话,我确实不明白SOA和微服务到底有什么本质上的区别,两者说到底都是对外提供接口的一种架构设计方式.我倒觉得微服务其实就是随着互联网的发展,复杂的平台.业务的出现, ...

  10. JScript 对象 <|> JSON

    <script type="text/javascript"> function test(){ var array = [{"id":1},{&q ...