内容简介:gulp打造前端自动化工作流
在引入gulp构建 工具 之前,我的开发方式和目录是这样的:
project -- test 存放html文档 --0618 -- coin -- css 存放css文档 -- web -- app -- app.css -- js 存放js文档 -- web -- app -- scroll.js -- image 存放image -- web -- app -- logo.png -- gitignore git忽略文件 -- node_modules grunt模块 -- gruntfile.js grunt配置文件信息 -- README.md 组件总体说明 -- package.json 版本等元信息
这样的一套开发框架结合seajs、git、switchHost、grunt和jenkins从去年5月份开始一直沿用到了今天,这样做的优势是非常简单,当开发团队很小的时候操作起来非常自由。当团队扩展速度越来越快时,所涉及到的成员由我一人到杭州+上海若干团队成员的共同参与,于是也有不少同学来向我反馈一些问题:
-
1. 老版开发模式的瓶颈
- 我手上的这个项目文件应该放在什么目录下面,需要依赖现有那些公共库?
- 前端项目开发完毕后转化为jsp/vm需要手动修改域名,能否加个配置?
- 工程量越来越大,后续维护不好弄,老的不敢删除,新的越来越多
- 每次发布上线后总是会遇到缓存问题
- 上线部署比较麻烦,需要手动发布到又拍云,项目越大越容易漏文件
我相信随着业务的发展和团队人员的扩张,每个团队都会遇到类似的问题,如何改造现有的工程,既保证业务的海海需求不会delay,同时也要提高团队成员的开发效率,就是我最近在探索的前端自动化工作流,来帮助我们前端人员开阔眼界,提升效率,让开发的归开发,让部署的归部署,解放前端生产力来做更多有意义的事情, 而不是每天苦逼的调bug,改代码,日复一日地加班。
-
2. 新版开发模式的项目需求
- 组件化的开发方式,互不影响,同时兼容现有线上公共代码;
- 开发环境工程和部署环境工程分离;
- 资源定位,通过参数配置实现线上和测试环境cdn指向区分;
- 非覆盖式发布脚本,实现程序自动化发布实现;
- 静态资源发布上线需要做压缩优化
- mock server,模拟服务端动态数据
-
3. 项目选型考察结果
fis: --优点 1.广泛使用,社区氛围浓郁,最近出了fis3 2.使用简单,容易上手; 3.国产良心; --缺点 1.黑盒,不清楚实现原理; 2.感觉插件略少,不像其他两个有npm包支持 3.速度太!慢!,realese一个工程好好久 grunt: --优点 1.最早被广泛使用的构建工具; 2.插件丰富; --缺点 1.配置麻烦; 2.速度太!慢! gulp: --优点 1.基于工作流的自动化构建工具,不生成中间文件,大大加快了构建速度; 2.插件丰富,使用广泛; 3.通过代码而非配置的形式,更适合前端开发人员使用 --缺点 学习门槛较高,需要对node较熟悉
对目前主流的自动化构建工具的考察结果,综合社区氛围、插件丰富程度、使用习惯以及构建速度来看,gulp有一定的优势,以下我们就用gulp来改造现有较为冗余的工程项目。
- 4. 先从改造项目目录开始
新版工程项目地址, 摸我
--app 负责存放工程地址(源地址) --common 存放公共静态资源库 --js common js脚本 --libs --公共类插件,比如validator,dialog,scroll等等,自定义的公共基础模块 --vendors --第三方公共脚本,jQuery,zepto,seajs,template,html5,modernizr等。 --bi等 --公共类业务脚本 --style 公共样式文件 --web --header.less --btn.less --view --0818 --app view/0818/app是一个独立的模块。 css --818.css js --818.js index.html --web --dist 本地构建目录(目标地址) --0818 --coin --mock_server 本地模拟服务端数据 --data --product.json 模拟服务端数据(18产品) --list.json --index.js mock_server配置信息(通过express搭建) --node_modules node模块 --gitignore git忽略文件 --gulpfile.js gulp配置文件信息 --README.md 组件总体说明 --package.json 版本等元信息
- 5. gulpfile代码分解
1.定义模块变量 var gulp = require('gulp'); //基础,必须引入 var del = require('del'); //清理文件夹,可选 var args = require('minimist')(process.argv.slice(2)); //关键:读取传入参数,其中minimist是一个命令行插件。 //0:node,1:文件路径 var plugins = require('gulp-load-plugins')(); //通过驼峰直接读取模块而不需要require //移动端调试 var browserSync = require('browser-sync').create(); //移动端调试神器 var url = require('url'); //解析url
2.配置参数和项目路径 //1.-n : 构建项目名称,必须带上 //2.--dist : 是否对工程进行构建(如果不构建,就启动当前项目) //3.--production: 控制是否线上发布,可选 // 1.获取项目名称 if (!args.n) { console.log('请使用 -n 参数设置项目名称, 比如 -n view/0818/web'); process.exit(0); } var projectName = args.n.toString(); // 2. 是否进行构建 //(当启动服务器的时候是在项目工程启动还是构建目录启动) if (args.dist) args.domain = false; // 3.控制是否线上发布 var isProduction = args.production; //获取线上版本参数 var cdn = isProduction ? 'http://wacai-file.b0.upaiyun.com' : 'http://b1.cdn.wacaiyun.com'; //4.获取路径 //dir代表当前的目录,resolve相当于不断的调用系统的cd命令,将path一路拼接起来 var paths = { dir : path.resolve(__dirname), base: path.resolve(__dirname, 'app'), dist: path.resolve(__dirname, 'dist',projectName) }; var projPath = path.resolve(paths.base,projectName);
构建任务之
####一. 清理任务,每次构建先清理构建目录内容
gulp.task('clean', function () { return del([paths.dist]); });
####二. less编译任务,后续工程样式文件从.css迁入.less
//执行less任务 gulp.task('less', function () { return gulp.src(projPath + '/**/[^_]*.less') //plumber:任务错误中断后继续 .pipe(plugins.plumber()) .pipe(plugins.less()) .pipe(plugins.autoprefixer()) .pipe(gulp.dest(projPath)); });
//demo @import (less) "../../../common/styles/web/reset.less"; @import (less) "../../../common/styles/web/var.less"; @import (less) "../../../common/styles/web/header.less"; @import (less) "../../../common/styles/web/footer.less"; @import (less) "../../../common/styles/web/form.less"; @import (less) "../../../common/styles/web/layout.less"; @import (less) "../../../common/styles/web/btn.less"; @import (less) "../../../common/styles/web/modalBox.less"; @import (less) "./user.css";
####三. 构建任务
gulp.task('build', ['clean','less'], function (){ //revAll是一个构造方法 var revAll = new plugins.revAll({ //html不加md5 dontRenameFile: ['.html'], dontUpdateReference: ['.html'], //rev - revisioned reference path 调整后的路径 //source - original reference path 源路径(相对于html的路径) //path - path to the file 文件路径(绝对路径) transformPath: function (rev, source, file){ //如果是cdn绝对地址,不做转换 if(file.path.indexOf('//')==0) return; //如果不是发布到dist目录,静态资源+cdn前缀 if (args.domain !== false) { var filePath = file.path.slice(__dirname.lastIndexOf('/')) return cdn + filePath; } //如果发布到dist目录,返回转化后地址 return rev; } }); //css,html,js筛选 var cssFilter = plugins.filter('**/*.css'); var htmlFilter = plugins.filter('**/*.html'); var jsFilter = plugins.filter('**/*.js'); return gulp.src([projPath + '/**/*.{png,jpg,html,css,js}']) .pipe(revAll.revision()) .pipe(cssFilter) .pipe(plugins.minifyCss()) .pipe(cssFilter.restore()) .pipe(jsFilter) .pipe(plugins.uglify()) .pipe(jsFilter.restore()) .pipe(htmlFilter) //conditionals:true,不移除ie浏览器相关的注释代码 .pipe(plugins.minifyHtml({conditionals: true})) .pipe(htmlFilter.restore()) .pipe(gulp.dest(paths.dist)) //生成manifest文件 .pipe(revAll.manifestFile()) .pipe(gulp.dest(paths.dist)); });
####四. mock-server任务
//自动启动/重启你的node程序,开发node服务端程序必备 gulp.task('mock-server', function (){ plugins.nodemon({ script: './mock_server/index.js' }); });
####五.本地服务器任务
//如果不需要构建,只需要启动下服务器就行 var preTasks = args.dist ? ['mock-server', 'build'] : ['less','mock-server']; //启动服务 gulp.task('server', preTasks, function (){ var proxies = []; //理财下面统一用finacne,notification是主站访问登录信息的接口 ['finance', 'notification'].forEach(function (route){ //9999是express里面配置的端口 //url.parse返回url对象的属性 var proxyOption = url.parse('http://localhost:9999/' + route); proxyOption.route = '/' + route; proxies.push(proxy(proxyOption)); }); //browersync支持本地服务 browserSync.init({ //实时注入css,改动保存即生效 files: "**", server: { //baseDir必需和middleware必选 baseDir: [args.dist ? paths.dist : projPath], middleware: proxies }, browser: "google chrome" }); //当css文件变动时,执行less任务 gulp.watch([projPath + '/**/*.css', projPath + '/**/*.less', paths.base + '/common/**/*.css'], ['less']); //当js文件变动 gulp.watch([projPath + '/**/*.js', paths.base + '/common/**/*.js']); });
####六.自动部署页面任务
//deploy:html,部署html页面 gulp.task('deploy:html', ['build'], function (cb){ var hostname = isProduction ? '192.168.11.133' : '192.168.3.185'; //rsync是1个 linux 下面同步工具 return gulp.src(paths.dist + '/**/*.html') .pipe(plugins.rsync({ root: 'dist', destination: '/data/program/fcactive_webapps/fcactive', hostname: hostname, username: 'appweb' })); });
####七.自动部署CDN
gulp.task('deploy:cdn', ['build'], function(cb){ if (isProduction) { var upyun = new UPYUN('xxxx', 'xxx', 'xxx'); var files = glob.sync(paths.dist + '/**/*.{css,jpg,png,gif,js}'); var remotePath = '/finance_web'; var i = 0; files.forEach(function(file){ var remote = remotePath + '/' + projectName.replace(/^view\//,"") + file.replace(paths.dist, ''); upyun.uploadFile(remote, file, mime.lookup(file), true, function(err, result){ if (err) console.log(err); if (result.statusCode != 200) { console.log(result); } i++; if (i === files.length) { console.log(i + '个资源文件被上传到又拍云CDN'); cb(); } }); }); } else { var hostname = '1xx.1xx.1.x'; return gulp.src(paths.dist + '/**/*.{css,js,jpg,png,gif}') .pipe(plugins.rsync({ root: 'dist/view', destination: '/data/program/cdnweb_branchs/b1/finance', hostname: hostname, username: 'appweb' })); } });
- 6. 下一步计划
- seajs依赖、合并处理(use和require里面如何读取到最新增量文件);
- 开发与配置分离,目前都是通过gulpfile去控制,多人开发的时候容易弄错;
- js打包任务,是继续用seajs还是有其他的方案?
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端工程工作流规范
- 前端工作流中的hooks
- 使用webpack4打造自己的前端工作流
- Gulp4 前端自动化工作流配置
- 前端工程化:围绕Jenkins打造工作流的过程
- LegoFlow 开源 v2.0 版本,前端工作流客户端
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
High Performance Python
Micha Gorelick、Ian Ozsvald / O'Reilly Media / 2014-9-10 / USD 39.99
If you're an experienced Python programmer, High Performance Python will guide you through the various routes of code optimization. You'll learn how to use smarter algorithms and leverage peripheral t......一起来看看 《High Performance Python》 这本书的介绍吧!