在前端开发工程化领域,本文将介绍用「增量」思想提升代码检查、打包构建环节的速度,从而实现开发过程的效率提升。
接下来我们通过自定义git的pre-commit钩子脚本来为一个工程实现增量代码提交检查能力。
本脚本中ESLint检查执行到文件这一粒度。实现增量代码检查首先就是要能找到增量代码,即修改了哪些文件。我们借助git版本管理工具寻找提交时暂存区和HEAD之间的差异,找到修改的文件列表。
代码交付时的增量检查实现方式和上面的步骤类似,关键点就是找到增量的部分。
以一个包含460个js文件的中等规模工程为例,下图中左边为全量代码检查的耗时,右边为增量代码检查的耗时:
如果开发者只修改了一个文件,在提交代码时全量检查需要耗时38秒,而增量检查只需要耗时2秒。
前文实现了文件粒度的增量检查,考虑到大型项目中可能存在很多大文件,如果只修改了几行代码就需要对整个文件进行ESLint检查依然是个低效的操作,我们可以尝试找到代码行粒度的增量代码做检查。
以使用webpack进行打包构建为例,我们同样尝试用「增量」思想来优化这个问题。
和前文类似,第一步依旧是找到增量代码,即本次发布修改了哪些文件。最简单的仍然是选择用gitdiff命令来实现。和增量代码检查不一样的是,这里要对比待发布的集成分支和主干,找到之间的差异文件列表。
constexecSync=require('child_process').execSync;constpath=require('path').posix;constGITDIFF='gitdifforigin/master--name-only';//执行git的命令constdiffFiles=execSync(GITDIFF,{encoding:'utf8',}).split('\n').filter((item)=>item).map((filePath)=>path.normalize(filePath));获得了修改的文件列表后,并不能直接触发webpack打包,需要根据文件之间的引用关系找到入口文件,把需要重新打包的页面入口传给webpack。
思路是先构建每个页面入口文件的依赖树,如果这棵树包含了上述被修改的文件,就说明这个页面需要被重新打包。如图所示:
以上图中两个入口文件为例,它们的依赖树如下:
//被修改的文件列表constdiffFiles=['util/fetch.js'];//用madge库计算依赖树的示例代码,具体可查看官方文档//Promise.all([madge('./demo/index.js'),madge('./demo/buy.js')]).then((result)=>{//result.forEach((e)=>{//console.log(e.obj());//})//});//最后得到的依赖树如下constrelyTree={//demo/index.js文件的依赖树{'demo/a.jsx':['util/fetch.js'],'demo/b.js':[],'demo/index.js':['demo/a.jsx','demo/b.js'],'util/fetch.js':[]},//demo/buy.js文件的依赖树{'util/env.js':[],'demo/buy.js':['demo/c.js','demo/d.js'],'demo/c.js':['util/env.js'],'demo/d.js':[]}};深度遍历每个入口文件的依赖树,根据是否包含被修改的文件列表中的文件来判断是否需要重新打包构建,示例代码如下:
/*计算增量入口示例代码*///全量页面入口constentries=['demo/index.js','demo/buy.js',];//判断两个数组是否存在交集functionintersection(arr1,arr2){letflag=false;arr1.forEach((ele)=>{if(arr2.includes(ele)){flag=true;}});returnflag;}//计算增量入口constincrementEntries=[];for(constiinrelyTree){for(constjinrelyTree[i]){if(intersection(relyTree[i][j],diffFiles)){incrementEntries.push(i);}}}比如我们已知本次发布是修改了util/fetch.js这个文件,遍历以上2个依赖树就得知只有demo/index这个页面受影响,修改webpack的配置只把这个文件作为入口参数触发打包就可以极大提升打包构建的速度。
前端工程还有一些依赖是package.json文件里描述的npm包,安装在node_modules文件夹里,模块之间的依赖关系非常复杂。简单起见,当第一步gitdiff发现package.json里有模块升级时,考虑到这不是高频事件,可以直接触发全量打包。
以一个包含50个页面的MPA工程为例,下图中左边为全量打包构建的耗时,右边为增量打包构建的耗时:假设开发者修改了2个页面,增量打包机制通过计算只传入这两个页面入口给webpack,整个打包构建流程将从7分钟缩短为50秒,极大提升持续集成的效率。
本文以增量代码检查和增量打包构建两个特定业务场景为例,介绍了「增量」思想在前端开发工程化中如何做效率提升。这两个案例不一定能直接照搬到大家的前端工程化实践中去,旨在介绍这样一种编程设计思想,大家可以发挥各自的想象力运用到更多的地方。