内容简介: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 版本,前端工作流客户端
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。