@a06062125
2016-11-01T10:24:09.000000Z
字数 5539
阅读 717
未分类
3663项目依赖工作流执行静态文件预编译打包、调试辅助、代码风格检查等工作, 大大提升开发人员的调试效率和代码可靠性。
然而随着项目迭代, 编译任务的启动和执行也越来越慢(平均时长1min++), 漫长的等待时间实在让人抓狂。
以v1.9-dev某次gulp任务启动日志为例, 启动耗时1分29秒, 观测某次脚本变化到打包完毕10s+, 这还不是最慢的情况。
启动日志
Starting php-fpm done[16:54:55] Using gulpfile ~/devspace/town/gulpfile.js...[16:55:41] bizScripts all files 1.25 MB[16:55:41] Finished 'bizScripts' after 42 s...[16:55:47] Finished 'bundle_ng_js' after 5.2 s...[16:56:24] Finished 'bizScripts:watch' after 36 s// 执行时长:00:01:29
观测到变化后重新打包
[17:42:06] watchify.onUpdatd [ '/home/weimengxi/devspace/town/src/www/business/apps/live-room/index.js' ][17:42:26] Browserify Bundle start[17:42:26] watchify.onLog 694391 bytes written (19.74 seconds)[17:42:26] Browserify Bundle finish live-room/index.js after 92.18 ms[17:42:26] bizScripts > live-room/index.js all files 694.39 kB// 从观测到变化到打包完毕: 20s
辣么问题来了, 怎么能让它 快 一点呢???
gulp工作流在3663项目中主要在两个过程中发挥作用:
静态资源编译过程又可细分为
entry, 单页入口文件模板合并, styles, less compile to css, postcss大法(autoprefix, 媒体查询合并, 兼容降级) .etcscripts, browserify大法(预处理、依赖管理、文件合并、打包)、ng预编译代码规范检查
开发调试类任务
任务概览

启动任务
// 流程控制gulp.task('default', ['clean'], function(cb) {runSequence(['styles', 'images', 'fonts'], ['npapiStyle','ieBgcolorstyles','bizScripts', 'libScripts'],'bundle_ng_js','entry', ['watch', 'serve'],cb)});
如果把runSequence()的参数列表展开放到一个串行的任务数组tasks中
(...args) =>{ let tasks = args }, 可以发现, 串行任务越多 , 执行时间越长。
任务时序图
通过分析, 发现现有流程存在这些问题
没有充分利用任务并发执行的优势
拷贝类任务与编译类任务没有依赖关系, 可以并发执行;
存在重复执行的任务
gulp.task('npapiStyle', function() {var file = fs.createWriteStream('dist/' + ENV.get("build_mode") + '/static/styles/npapi-fix.css');file.write(npapiCss);});
代码规范检查是否可以放到发布流程中?
目前我们的检测规范比较宽松, 仅检测会引发功能阻塞的不规范代码。 如会造成ie8抛异常的拖尾逗号、对象字面量重复键值, 360浏览器极速模式某些触发3D加速场景flash背景透明bug的css。
编译任务中,对未发生变化文件的重复编译操作
脚本编译慢:browserify开启watchify模式时,没有做缓存包依赖分析结果的配置, 导致每次打包都要对所有文件重新进行依赖分析;
样式编译慢:样式观测任务中, 对未发生变化文件的重复处理也是造成时间加长的主要原因。
做了依赖分析后的任务流程控制
gulp.task('default', ['clean'], function(cb) {var cps = ['images', 'fonts', 'libScripts'],compiles = ['styles', 'bizScripts', 'bundle_ng_js', 'entry'],fallbacks = ['npapiStyle','ieBgcolorstyles'];runSequence(cps.concat(compiles, fallbacks), ['watch', 'serve']);});
执行时间为max(ttasks[0], ttasks[1])
默认启用broswerify的watchify模式, 不再在watch任务中重复执行bizScripts任务
gulp.task('watch', function() {var watchOpts = {readDelay: 10};// ... other watch tasks, styles, images, fonts, entry .etc// return gulp.start('bizScripts:watch');return util.noop();})
注意: 你的任务是否在这些前置依赖的任务完成之前运行了?请一定要确保你所依赖的任务列表中的任务都使用了正确的异步执行方式:使用一个 callback,或者返回一个 promise 或 stream。
https://github.com/gulpjs/gulp/blob/master/docs/API.md
// 把内存中的数据写入到目标文件中var buffer2Stream = function(buffer, targetFile, destDir) {var stream = source(targetFile);stream.write(buffer);process.nextTick(function() {stream.end();});// 返回vinyl streamreturn stream.pipe(vinylBuffer()).pipe(gulp.dest(destDir));}function styleFallback(fallbackStyles, fileName) {var destDir = path.join('dist/', ENV.get("build_mode"), 'static/styles');return buffer2Stream(fallbackStyles, fileName, destDir);}gulp.task('npapiStyle', ['styles'], function(){return styleFallback(npapiCss, 'npapi-fix.css');});
通过配置 opts.cache , opts.packageCache 开启watchify的缓存模式。
开启缓存模式后的 watchify 会在首次执行打包任务时保存脚本的依赖分析结果,当观测到文件变化时, 仅需要对变化的文件重新进行依赖分析和相关转换。
第一次执行打包任务所花时间不变的情况下, 开启缓存时, 观测到文件变化后执行打包任务所花的时间会大大减少(包规模越大, 提速越明显); 没有开启缓存模式时,每次执行打包任务所花的时间都会和第一次一样长。
if (isWatching) {opts.plugin = opts.plugin || [];// 更多说明请戳 https://github.com/substack/watchifyopts.plugin.push(watchify);// 缓存modules的依赖分析结果opts.cache = {};// 缓存package.json的依赖分析结果opts.packageCache = {};}
tips: 这里的
opts.cache,opts.packageCache是browserify的一个共享配置变量,browserify里依赖的module-deps模块也需要这两个配置变量来进行依赖分析结果管理。
styles 编译任务优化 引入gulp-changed 判断样式文件是否发生变化, 未发生变化的样式文件不再执行编译打包工作。
如果项目中需要编译的.less文件数目是n, 时间将缩减为原来的1/n 。
var styleGlob = 'src/www/static/styles/*.{less,css}',dist = 'dist/' + ENV.get("build_mode") + '/static/styles';return gulp.src([styleGlob]).pipe(plumber()).pipe(gulpif(/\.less$/, less()))// 对比源文件和dist目录中目标文件的修改时间, 仅传递修改过的文件到后续操作中.pipe(gulpif(ENV.get("is_debug"), changed(dist, {extension: '.css',hasChanged: changed.compareSha1Digest}))).pipe(postcss(processors)).pipe(gulpif(ENV.get("is_compress"), cleanCss())).pipe(size({title: 'styles'})).pipe(gulp.dest(dist));
将任务按图1中的类别拆分到 _gulpfiles/tasks/ 目录下, 方便维护;
通过以上优化, 目前任务启动仅受限于最慢的单个任务 (我会告诉你是打包业务脚本吗) 。 在相同开发机上测试, 启动时间缩减一半以上。
优化前: 1min29s
优化后: 39s
执行日志
Starting php-fpm done[20:14:14] Using gulpfile ~/devspace/town/gulpfile.js...[20:14:53] Finished 'bizScripts' after 39 s[20:14:53] Starting 'watch'...[20:14:53] Starting 'serve'...[20:14:53] Finished 'serve' after 61 μs// 执行时长:00:00:39
browserify 打包提速开启了 watchify 的缓存模式后,browserify 单次编译打包时间由蜗牛速度提至小兔子速度
优化前: 20s
优化后: 1s
[17:46:17] watchify.onUpdate [ '/home/weimengxi/devspace/town/src/www/business/apps/live-room/index.js' ][17:46:18] Browserify Bundle start[17:46:18] watchify.onLog 694394 bytes written (0.69 seconds)[17:46:18] Browserify Bundle finish live-room/index.js after 92.63 ms[17:46:18] bizScripts > live-room/index.js all files 694.39 kB// 从观测到变化到打包完毕:1s
styles 编译任务提速优化前:5s+
估化后:1s+
代码已提交至 master 远程分支。