gulp打造前端自动化工作流

栏目: Node.js · 发布时间: 7年前

内容简介: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. 新版开发模式的项目需求
    1. 组件化的开发方式,互不影响,同时兼容现有线上公共代码;
    2. 开发环境工程和部署环境工程分离;
    3. 资源定位,通过参数配置实现线上和测试环境cdn指向区分;
    4. 非覆盖式发布脚本,实现程序自动化发布实现;
    5. 静态资源发布上线需要做压缩优化
    6. 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. 下一步计划
  1. seajs依赖、合并处理(use和require里面如何读取到最新增量文件);
  2. 开发与配置分离,目前都是通过gulpfile去控制,多人开发的时候容易弄错;
  3. js打包任务,是继续用seajs还是有其他的方案?

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

社会工程

社会工程

海德纳吉 (Christopher Hadnagy) / 陆道宏、杜娟、邱璟 / 人民邮电出版社 / 2013-12 / 59.00元

本书首次从技术层面剖析和解密社会工程手法,从攻击者的视角详细介绍了社会工程的所有方面,包括诱导、伪装、心理影响和人际操纵等,并通过凯文 · 米特尼克等社会工程大师的真实故事和案例加以阐释,探讨了社会工程的奥秘。主要内容包括黑客、间谍和骗子所使用的欺骗手法,以及防止社会工程威胁的关键步骤。 本书适用于社会工程师、对社会工程及信息安全感兴趣的人。一起来看看 《社会工程》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码