# 1. 背景

工具是生产力的基本,也是提升研发效能的关键。工具是一个个点,当把这些点封装好、关联好,串联起来,就构成了基础设施。团队需要持续不断的沉淀这些工具。

项目由web项目转为跨端项目过程中,积累了一系列工具,这里对一些核心工具进行下总结,主要包括原理、用法、效果等方面。

从宏观上说,这些工具解决的问题包括:

  1. 瓶颈问题、卡脖子问题,不解决就无法继续进行,比如JS分发、组件分发,如果不解决,就无法满足小程序主包2M的限制,无法预览、上传、上线。
  2. 自动化相关,大幅减少工作量,以更优雅、更稳定的方式,替代手动改代码,提高效率

从技术类别上,这些工具类型分为:

  1. Eslint插件
  2. Webpack Loader
  3. Webpack Plugin
  4. 脚手架工具,可视为node脚本的集合
  5. CI相关

# 2. 工具

# 2.1. JS分发

JS分发和组件分发客观来说,是相对复杂的插件。

# 2.1.1. 背景

由于uni-app对JS文件的打包策略并不完善,会将多个分包使用的JS都放到主包中,这会让主包变得特别大。因此需要将只有分包使用的JS文件转移到分包中。

# 2.1.2. 原理

总体分为两步,第一步是先收集要移动的文件,第二步是真正移动。

收集过程是从 compilation.modules 过滤出vue文件,就是一个个module,然后获取这些 module 的 chunks,找到这些 chunks 对应的分包,如果有分包在使用,但是主包没在使用,就把它放入 moveFiles 中。

移动 module 过程如下。遍历 modules,如果某个 module 存在于 moveFiles 中,调用 module.getChunks 获取它的所有 chunks,如果只有 common/vendor 中包含这个 module,说明这个需要被放到分包中,并将 common/vendor 中的移除。

# 2.1.3. 效果及扩展

JS分发插件使用后,主包大小减少了0.51M。

除了上面自动化的移动JS外,还实现了移动指定JS文件到指定分包的功能,扩展了插件的使用场景,可以让主包更小。

# 2.2. 组件分发

# 2.2.1. 背景

组件分发的灵感来自于uni-app源码中的提示,“将只有分包使用的组件移动到分包中”。

项目的一些公共组件,比如local-component、component中vue文件,会被打包到主包中,因此这里需要将只有分包使用的组件移动到分包中,但是如何在不改动项目架构的情况下实现这一功能呢?

# 2.2.2. 原理

总体步骤如下:

  1. 生成组件的基本相互引用关系
  2. 构建组件所有引用关系图
  3. 拉平上述组件关系
  4. 逆向获取使用一个组件的所有分包
  5. 根据组件使用的分包进行移动、删除主包内容等
# 2.2.3. 效果及扩展

使用组件分发插件后,主包大小减少了 2.17 M。

为了让插件更加灵活,可以适应不同项目,提供了几个配置选项:

  • 最大分包使用数目 maxUseTimes
    • 对一个组件,如果使用它的分包多于 maxUseTimes 时,就不再处理
  • 禁止移动的组件列表 disableList
    • 如果 disableList 中包含组件的路径和名称匹配到了,就不再处理

使用前:

使用后:

# 2.3. Eslint插件

开发了Eslint插件eslint-plugin-pmd,可以一键转化不符合跨端规范的代码,包括:

  1. 禁止从js文件中加载Vue组件。 由于uni-app仅支持vue文件组件,并不能识别从js引入再导出的组件,所以这里需要自动转化。

  2. 禁止在vue的template中用+号转换字符串为数字 uni-app不允许+str语法,这里自动识别并自动转为parseInt(str)

  3. 禁止在vue模板中使用复杂的key 对于字符串拼接:key="hold+ index"这种key会及时提示错误

# 2.4. 全局组件插入loader

对于一些所有页面都在使用的组件,用loader的方式自动注入,提升了效率,也减少了出错的可能。

# 2.5. page-meta插入loader

微信小程序原生支持rem,但是需要插件page-meta标签,这里也是用loader自动注入。

# 2.6. 替换web端组件

一些web端的组件也会被打包进小程序的产物中,因为小程序模式下无法开启tree-shaking。因此这里需要用工具将一些没用的组件消除掉。

替换一个文件有两种方式:

  1. 将引入文件的地址替换,比如import { Button } from 'vant',可以将vant转为一个另一个文件,import { Button } from 'fake-comp';
  2. 加载文件时,用新内容替换,对于上面的例子,就是加载vant时,直接替换掉。

对于三方库,用的是第1种方式,对于本地文件,用的是第2种方式。

# 2.7. 懒加载的兼容

web用的是lazyload这个三方库,而小程序自带lazyload属性,所以实现了一种根据编译环境,自动选择合适的懒加载方案的loader。

# 2.8. 调试工具

实现了小程序打包产物中自动注入构建信息的工具,方便查看:

  • 最后一次commit信息
  • 构建环境
  • 版本是否被覆盖、是否是最新的
  • 当前是测试环境还是线上环境

# 2.9. 基于摩斯密码的加密

实现了基于摩斯密码的加密方案,可以在小程序中隐藏对应的h5路由信息,方便开发者调试定位问题。

# 2.10. 路由hook

用hook的方式扩展uni-simple-router的路由模式,可以做到不改代码,也可以保留h5的功能多样性。

# 2.11. CI相关

实现了微信小程序和qq小程序的自动构建、自动上传、自动预览的功能,主要解决了以下痛点:

  • 构建时间长,流程繁琐

  • 外部开发人员无法预览

本次CI功能点如下:

  • 自动进行uni-app打包,打包两份:test和release环境
  • 将打包产物自动上传
  • 自动预览、生成图片
  • 将预览图片上传到腾讯云
  • 发送构建通知、腾讯云图片地址到企业微信

下面是一些相对于其他CI的优化点:

  • 多环境区分
    • 对于开发版,同一个开发者只能保留一份,当我们既想看测试环境,又想看正式环境时就捉襟见肘了。
    • 借助小程序ci,对多个环境用不同的机器人,这样就不会覆盖了。
  • 配置驱动
    • 由于小程序ci机器人范围有限(1-30),所以只能手动维护,让其重复利用。
    • 这里我让项目每个分支每个环境分别对应一个机器人,当一个分支废弃后,这个机器人就可以释放给其他分支使用。
    • 同时其他配置项也可以统一保管起来,比如腾讯云密钥、小程序密钥等,方便维护
  • 自动重试
    • 有时候上传或者预览会失败,可能是环境问题,也可能是多个流水线同时上传会冲突,因为需要增加自动重试功能。
  • 并行提速
    • 上传和预览是可以同步进行的,这样可以节省一些构建时间。
  • canvas绘图
    • 小程序ci默认提供的图片只有二维码,笔者用canvas将一些构建信息和二维码绘制到一张新图上,方便定位和查看。
    • 绘制的信息示例:
    • 版本号:1.0.5
    • 提交者:CI机器人5
    • 环境:test
    • 分支:release
    • 构建时间:2022-10-19: 09:36:37
    • 最后提交:lee - 修复page
    • 二维码

目前,CI流水线日均构建30+次,每次构建时间6min左右,每日可节省工时180min+。

# 3. 工程化

由于loader的机制接近于黑盒子,为了保证工具的稳定性,需要用完善的测试用例覆盖,其他工具也是如此。

这里我将上述的loader、plugin抽离出来,并用ts+jest+rollup重构,单独发了npm包uni-plugin-light,好处是:

  • 方便其他项目接入
  • 核心方法必须通过单元测试,提高了工具的可用性,减少了bug率
  • 方便扩展

# 4. 其他工具

除了上述跨端工具外,这里也简单介绍下一些其他实用工具:

  • eslint-plugin-light,一行代码完成eslint配置
  • 开源治理日报机器人,每日提醒代码规范、代码安全问题
  • TAM日报,每次发送项目PV、UV、错误率、性能数据,方便开发人员查看
  • 公共库自动打Tag、自动升版本,并发送changelog到企业微信群中
  • 七彩石配置自动同步COS,方便使用

# 5. 总结及后续规划

在日常开发中,开发了一系列工具,解决了一些针对性的问题,提升了效率。

除了工具链外,前端开发中另一个重要的部分是组件库,由于分工过细、赶需求等,规范的组件库一直没有沉淀下来,后面会加强此方面的建设,构建高可用、灵活的组件库。