首页 > 编程语言 >小程序工程化探索

小程序工程化探索

时间:2024-08-05 22:55:30浏览次数:8  
标签:NPM 文件 探索 代码 程序 分包 工程化 页面

小程序工程化探索

原创 陈晓强 WecTeam  2019年11月02日 17:00

上个月(2019年10月)去参加了阿里举办的第二届前端艺术家沙龙,做了小程序工程化的分享,现整理如下。

图片

小程序是近两年兴起的最热门的技术之一了,但不同于 H5 在工程化方面的成熟,小程序在工程化方面的探讨并不多。京东社交电商前端团队是最早的那一批小程序开发人员,有多早呢,我想可以用内测玩家这个词来形容。两年多以来,我们在工程化方面做了很多积累:包括规范化、组件化、工具化、自动化测试、持续集成系统等,接下来为大家一一揭晓。

 

图片

首先是规范,无规矩不成方圆,有了统一的规范,才能做更多统一的决策。

可以看到,我们的规范包括目录结构规范、git 分支规范、代码编写规范、开发规范、体验规范等等。

 

图片

基于这些规范,项目初期,我们借助小程序开发者工具现有能力,再加上 gulp 的补充,形成了最初的开发模式。可以看到,gulp 的补充主要是 sass 的处理和打包文件的提取及压缩。以上规范和开发模式都是大家所常见的,那是不是有这些就够了?

 

图片

先看一组数据,2017年1月9号,随着微信宣布小程序上线,我们的京东购物小程序也发布了第一个版本。页面数量15个,总包小于1M,参与开发人员不到10人。而到今年,我们的小程序已经有超过200个页面。总包超过10M,参与人数超过100,平均一周2个版本。当初的小程序已长成了一个大程序。看看规模暴增后带来的问题。

 

图片

可以看到,规模的暴增给开发、测试、打包、发布各个阶段都造成了问题。

开发阶段,开发者工具越来越卡,有时候想使用手机预览,等了2分钟,结果工具告诉我文件太多了,哎。另外一个问题就是出现了大量相同、相似代码,很难处理。

测试阶段,页面越来越多,很难覆盖全,有时候等到上线了才发现有个别页面功能有问题,只能重新发版。

打包阶段,第1个问题是代码包超限,这时不得不通过删代码或者调整业务的方式来处理,这是个很麻烦的事情。另一个问题是,我们有多个小程序,但代码很难复用。

发布阶段,流程繁琐,开发人员又比较多,导致效率低下。

先看看开发阶段调试越来越卡的问题

 

图片

不管什么 IDE,什么语言,当项目过大,文件过多时,必然会卡,小程序开发者工具也同样存在这个问题,我们的小程序到现在已经有6000多个文件,这对 IDE 来说实在是太难了。

怎么办呢? 其实我们平时业务开发往往只涉及到一两个页面,我能不能只加载这个页面相关的文件呢? 答案是可以的,这个方案我们叫单页抽取,通过工具化的手段进行文件依赖分析,仅提取当前开发页面所需的文件。

 

图片

文件依赖分析如何做:可以看下这个图,app.json 里注册了小程序所有的页面路径,通过这个信息就可以拿到所有页面的文件依赖及组件的文件依赖。

 

 

图片

可以看到,通过单页抽取,加载的文件数量从6000多下降到200多,预览耗时从100s下降到15s,启动、编译等操作的耗时,都有很明显的下降。

 

图片

好,开发调试卡的问题通过单页抽取解决了,接下来是大量相同、相似代码造成的冗余问题。

 

图片

先看下例子,这是两个不同页面的文件,但是存在完全相同的两个函数,这显然是有问题的。

 

图片

相同、相似代码形成的原因首先是复制粘贴,有相似功能的拷贝,也有跨小程序的拷贝。

然后是对项目不熟悉,新同学加入或业务交接等,会让开发人员面对一个全新的项目。这种陌生的情况下,许多开发人员就会产生重复造轮子的问题,只顾着自己开发的部分,完全没考虑到项目原先的代码状况。

这个怎么解决呢,一个是组件化,通过人工手段进行分析,提取 NPM 包,推动业务侧改造,减少重复代码。另一个是代码审计,通过工具化手段进行分析,给出建议,避免重复代码形成。

 

图片

这里的组件化,其实是指 NPM 包的提取,怎么做呢,可以分析现有公共文件,分析常见业务代码,提取成 NPM 包。然后再对 NPM 包的 API重新设计、评审以保证它的合理性。最后使用 JsDoc 同步生成详细的 API 文档,推动业务侧改造。

 

图片

NPM 质量如何保证?这就需要完善的测试用例、高标准的覆盖率。另外使用 ts 也能避免一些隐藏的问题。如此多的 NPM 包怎么管理呢,可以通过 lerna 进行统一维护、发布。 另外,跟随业界多端统一的步伐,NPM 包需要具有多端复用的能力。

 

图片

也许有人会问为什么不一开始就使用 NPM,答案很简单,微信小程序初期并不支持,实际上他从基础库版本2.2.1开始支持 NPM,但到目前为止,我们小程序仍然有12.8%的用户低于此版本。这个问题可以在打包阶段处理,通过 CLI 将 NPM 包的引用修改为相对路径引用。

 

图片

前面讲到通过 NPM 来减少重复代码。另外一个手段则是通过代码审计来避免重复代码的形成,通过 CLI 我们可以找出重复的代码片段,输出统计结果和详细对比结果(本章开头的示例)。进一步,可以找出相似代码。

可以看到,在改造前,我们 js 的重复率有12%,12%是什么概念?如果你只有两个一模一样的文件,重复率就是50%。 12%意味着每8行代码代码里有2行是一样的。重复代码很多,那重复检测的依据是什么,常见的有基于 token 的对比和基于 AST 的对比。

 

图片

来看看基于 token 的重复检测原理,其实也很简单,就是将代码转换 token,然后再判断一定长度 token 的 md5 值是否相同。基于 AST 的重复及相似代码检测复杂一些,这里就不细讲了。

 

图片

好,冗余问题我们通过组件化、代码审计的方式可以解决,接下来讲测试问题。

 

图片

由于规模暴增,页面越来越多,有些公共文件的改动几乎会影响到所有页面,直接导致测试工作量飙升,质量无法保证。因此我们开发了一个模拟用户行为的小程序自动化测试工具 —— Sandbox。

 

图片

Sandbox 架构分4层,第一层是测试用例层,第二层是用例步骤控制层,提供 api 供测试用例调用。第三层为沙盒环境,会预处理输入的小程序代码,创建小程序运行时,然后运行在 V8 引擎上,最后一层则是微信 api 的模拟供沙盒调用。需要提一下的是,今年6月份官方提供了小程序自动化 SDK,下一步我们对其进行整合。

 

图片

这是结合 Mocha 编写的测试用例,可以看到测试用例调用沙盒 api 进行流程编排,有加载页面、模拟点击等。在最后的 check 方法中可以拿到当前页面的 data 和路由来检查是否符合预期。

 

图片

执行结果如图,这样就完成了对用户行为的模拟以及结果的自动验证。

 

图片

好,通过自动化测试沙盒,解放了大量测试人力,使得他们可以更专注于版本特性,保证了版本质量。接下来看看代码包超限的问题。

 

图片

不管是微信小程序,还是支付宝小程序或者其他小程序,代码包大小都是有限制的,拿微信小程序举例,总包上限为8M,主包或单个分包上限为2M。

代码包超限首先是影响发版进度,不知道你有没有体验过:熬夜加班写完代码,测都测完了,跟别人的分支合并时发现超限了。这显然不是一时半会能解决的,不紧急的可以等下次发版,紧急的就只能推迟发布了。

然后是新增业务,分包大小已经接近上限了,来个新页面,谁来腾空间? 这也是个不得不面对的问题。

最后由于代码包太大,启动慢是必然的,太接近包上限,也容易导致小程序内存不足、甚至微信客户端闪退等问题。

 

图片

怎么办呢,首先是要减小体积。常见的减小体积的方式有这些,前面几种手段相对比较常规,重点讲一下最后一条:找出未使用的文件、函数,删掉。

 

图片

来看看未使用的文件、函数是怎么形成的。项目初期我们使用 gulp 进行构建,通过规则指定哪些目录需要打包,哪些文件需要剔除等,但久而久之,规则难免有遗漏。随着业务迭代,页面/组件下线,许多公共函数不再被引用,这些靠人工是很难识别的。自然也是需要通过工具化手段来解决。

第一个手段是依赖分析,通过工具在打包时删掉未使用的文件、函数,释放空间。另外一个手段是只能分包,打包时按照算法动态调整 NPM 包到主包或子包,临时调整分包大小。

文件的依赖分析,前面已经讲过了,下面看看函数依赖分析怎么做。

 

图片

函数依赖分析,或者说 Tree-Shaking,就是识别出未使用的代码并删掉。在 h5 里听得多,相信大家也都有一些实践,小程序如何做呢?

 

图片

首先,Tree-Shaking 基于 ES6 的模块机制,为此,我们我要统一对小程序代码做了一轮改造,将 commonjs 模块写法全部替换成 ES6 的模块写法,这是前提。

有了这个前提,在 CLI 打包过程中,可以将代码转成 AST,通过 AST 获取各模块的调用关系,删除未使用函数节点,再将 AST 转成代码。

具体实现可以参考这份代码,需要注意的是,一个函数没有被其他模块引用并不代表可以直接删除,还需要考虑模块内的引用情况,同时,写代码时尽量避免副作用。

 

图片

依赖分析可以删除未使用的文件、函数,释放空间。智能分包则是可以临时调整各分包大小。

 

看图,左边第一个分包使用了 cookie 和 md5 两个包,第二个分包则只使用了 cookie,通过算法配置,在编译时可以选择将两个 NPM 包都提到主包,这时主包大,分包小。或者仅将共用的 cookie 提到主包,md5 留在分包,这时主包小,分包大。这样可以大幅度缓解发版时主包或者分包超限导致延期的问题。

 

图片

智能分包流程是这样的,先解析 NPM 依赖,获得各 NPM 包被分包引用情况,根据算法动态生成 package.json 到分包,再到各分包下执行 npm install,接着调用开发者工具构建 NPM,最后修改引用路径,兼容低版本。

 

图片

好,代码包超限的问题,我们通过依赖分析释放出了大概20%的空间,但这些都只是技术上的手段,根源还是在业务方,如果任由业务不断扩张,或许扔键盘是最好的解决方案。 接下来看看多小程序间的代码复用问题。

 

图片

可以看到,同一个 git 项目中,有一些页面、组件、文件是可以同时被多个小程序复用的。复用就会产生类似这样的差异代码,大量的 if else用于环境判断,这些代码最终会出现在小程序代码包里,不管是执行速度也好,体积也好,都会受到影响,在小程序里,空间可是很宝贵的。正确的姿势应该是在编译阶段就将差异解决掉。

差异小的可以分片段,通过条件语法区分,差异大的分文件,通过文件后缀区分,主要是 app.json 等配置文件。

 

图片

这些也是通过工具化来解决,首先看条件语法编译,我们采用注释的方式编写条件语法,通过 CLI 针对不同小程序编译出不同的代码片段,使得代码更简洁。

 

图片

再看看文件后缀编译,小程序的 app.json 中会注册不同的页面,我们可以使用后缀来标识这个文件属于哪个 app,编译时根据 CLI 参数读取相应后缀的文件,这样就可以自由组合打包成不同的小程序。

 

图片

前面很多地方提到了工具化,这也是我们解决大规模小程序问题的主要手段,来总体看下 CLI 有哪些能力,开发这里讲到了单页抽取,测试这里讲到了 Sandbox,代码审计这里讲到了重复代码分析,打包这里讲到了未使用文件/函数删除、智能分包、条件编译等。 除此之外,CLI 还包含了一些常用功能,如 LiveReload、ts 支持、静态代码扫描等等。

 

图片

讲了这么多,看一下我们的 CLI 长啥样子:这是一个指定单页调试的命令,包含代码转换、依赖分析、npm 包的安装和构建、文件监听、自动唤起开发者工具等等。

 

图片

好,多小程序间代码的复用问题,我们通过条件语法编译、文件后缀编译可以解决,接下来看看发布流程过于繁琐的问题。

 

图片

Git Flow 想必大家都知道,我们的小程序也是基于 Git Flow 的分支规范,可以看到各个阶段需要的手工操作过多,可以想象一下,当发版时需要人工合并几十个分支时是什么样的场景,我们甚至经历过几次因为合版冲突的问题,十几号人花了大半天时间才解决。

 

图片

因此,我们通过流程固化、api 集成等手段搭建了持续集成系统,包含特性录入、发布计划管理、代码构建、Git 操作等多项功能。

 

图片

特定步骤包括:新建分支、送测、构建、关联发布版本等等,定时任务包括自动合并分支、静态代码扫描等。

具体的构建步骤,则是从项目初始化开始,获取代码,调用 CLI 工具进行编译,执行自动化测试、预览、上传。

最下面一层,由于预览、上传等依赖小程序开发者工具提供的 CLI 命令,比较耗时,使用了3个不同的进程队列来进行提速。

 

图片

接入持续集成后,我们可以看到减少了很多手工操作,出错的概率也大大降低了。

 

图片

好,最后一个问题也解决了。

 

图片

最后总结一下,大规模小程序场景,仅有规范是不够的,需要自动化测试保证版本质量,需要组件化解决代码冗余问题,需要工具化解决开发调试问题、打包编译等问题。持续集成系统解决发布流程繁琐问题。

 

总的看来,我们所做的这些,大多是基于现有的一些前端工程化方面的技术和思想,把它们应用到了小程序项目中,并针对小程序的特殊性做一差异化处理。放眼未来,希望整个小程序生态圈能够更加的规范和统一。

 

图片

以上就是我的分享,谢谢大家。欢迎关注我们的公众号,定期推送原创文章,感谢支持。

 

 

 

关注公众号「WecTeam」,后台回复“小程序”,获取本次演讲 PPT 高清版!

标签:NPM,文件,探索,代码,程序,分包,工程化,页面
From: https://www.cnblogs.com/sexintercourse/p/18344207

相关文章

  • 京喜小程序最佳实践:我是如何写超大型小程序代码的
    京喜小程序最佳实践:我是如何写超大型小程序代码的原创 罗文林 WecTeam  2020年04月02日11:45 你和一头骆驼准备穿过沙漠,前面是一眼望不到头的沙海,你的目的是要穿过沙漠到达对面的绿洲。现在你写的每一行代码就是往骆驼上负重。当然,有些负重是必须的,比如水和食物。可能......
  • 深圳大学-电信院-C程序设计实验-数组、函数、结构体的综合使用
    实验目的(1)进一步掌握数组的定义与使用;进一步掌握函数的定义和函数调用方法;(2)学习和掌握结构体的定义和使用方法;(3)进一步掌握C语言的编程方法;学习动画程序的基本设计思想和方法。实验内容本实验编写一个在控制台窗口中,在不考虑重力的条件下,模拟一组弹球在一个二......
  • C++ exe程序内存占用分析
    编译 $gitclonehttps://github.com/google/bloaty$cdbloaty$cmake-Bbuild-GNinja-S.$cmake--buildbuild$cmake--buildbuild--targetinstall命令bloaty.exe --list-sourcesrmembersthe.ofilesina.afilecompileunitssourcefile......
  • 微信小程序项目-宠物商城项目uniapp源码和代码讲解
      ......
  • 人工智能时代,程序员如何保持核心竞争力?
    人工智能时代,程序员如何保持核心竞争力?随着AIGC(如chatgpt、midjourney、claude等)大语言模型接二连三的涌现,AI辅助编程工具日益普及,程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工作,也有人认为AI是提高效率的得力助手。面对这一趋势,程序员应该如何应对?......
  • 绘制程序流图
    绘制程序流图程序流程图(Flowchart)是一种图形化表示程序逻辑的方式,它使用一系列标准化的图形符号来表示算法或工作流程中的步骤和决策点。以下是绘制程序流程图的基本步骤和方法:确定开始和结束点:用椭圆形表示开始点(Start)。用带圆角的矩形表示结束点(End)。使用流程线:用......
  • 在python jupyter下运行cuda c++程序
    Installrunthisonjupyter(*.ipynb)files!pip3installnvcc4jupyterUsageloadtheextensiontoenablethemagiccommands:%load_extnvcc4jupyterRuncudatest%%cuda#include<stdio.h>__global__voidhello(){printf("Hellofromblock......
  • 在python jupyter下运行cuda c++程序
    Installrunthisonjupyter(*.ipynb)files!pip3installnvcc4jupyterUsageloadtheextensiontoenablethemagiccommands:%load_extnvcc4jupyterRuncudatest%%cuda#include<stdio.h>__global__voidhello(){printf("Hellofromblock......
  • [米联客-安路飞龙DR1-FPSOC] SDK入门篇连载-02 FPSoc程序固化入门
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 1概述在应用的调试过程中,我们......
  • 《Advanced RAG》-05-探索语义分块(Semantic Chunking)
    摘要文章首先介绍了语义分块在RAG中的位置和作用,并介绍了常见的基于规则的分块方法。然后,阐述了语义分块的目的是确保每个分块包含尽可能多的独立语义信息。接着,文章分别介绍了三种语义分块方法的原理和实现方法,并对每种方法进行了总结和评估。文章观点语义分块是R......